text:
//******************************************************************************************************
//  DataFrame.cs - Gbtc
//
//  Copyright © 2012, Grid Protection Alliance.  All Rights Reserved.
//
//  Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
//  the NOTICE file distributed with this work for additional information regarding copyright ownership.
//  The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
//  not use this file except in compliance with the License. You may obtain a copy of the License at:
//
//      http://www.opensource.org/licenses/MIT
//
//  Unless agreed to in writing, the subject software distributed under the License is distributed on an
//  "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
//  License for the specific language governing permissions and limitations.
//
//  Code Modification History:
//  ----------------------------------------------------------------------------------------------------
//  04/19/2012 - J. Ritchie Carroll
//       Generated original version of source code.
//  12/17/2012 - Starlynn Danyelle Gilliam
//       Modified Header.
//
//******************************************************************************************************

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using GSF.IO;
using GSF.Parsing;
using GSF.Units.EE;

namespace GSF.PhasorProtocols.IEC61850_90_5
{
    /// <summary>
    /// Represents the IEC 61850-90-5 implementation of a <see cref="IDataFrame"/> that can be sent or received.
    /// </summary>
    [Serializable]
    public class DataFrame : DataFrameBase, ISupportSourceIdentifiableFrameImage<SourceChannel, FrameType>
    {
        #region [ Members ]

        // Nested Types

        // Defines possible signals types for an ETR file
        private enum SignalType
        {
            // Current phase magnitude.
            IPHM = 1,
            // Current phase angle.
            IPHA = 2,
            // Voltage phase magnitude.
            VPHM = 3,
            // Voltage phase angle.
            VPHA = 4,
            // Frequency.
            FREQ = 5,
            // Frequency delta (dF/dt).
            DFDT = 6,
            // Analog value.
            ALOG = 7,
            // Status flags.
            FLAG = 8,
            // Digital value.
            DIGI = 9,
            // Undefined signal.
            NONE = -1
        }

        // Fields
        private CommonFrameHeader m_frameHeader;
        private uint m_qualityFlags;
        private string m_msvID;
        private readonly int m_asduCount;
        private readonly byte[][] m_asduImages;
        private byte[] m_binaryImage;
        private ushort m_sampleCount;
        private uint m_configurationRevision;
        private byte m_sampleSynchronization;
        private ushort m_sampleRate;
        private ushort m_idCode;
        private string m_stationName;
        private ConfigurationFrame m_configurationFrame;

        #endregion

        #region [ Constructors ]

        /// <summary>
        /// Creates a new <see cref="DataFrame"/>.
        /// </summary>
        /// <remarks>
        /// This constructor is used by <see cref="FrameImageParserBase{TTypeIdentifier,TOutputType}"/> to parse an IEC 61850-90-5 data frame.
        /// </remarks>
        [EditorBrowsable(EditorBrowsableState.Never)]
        public DataFrame()
            : base(new DataCellCollection(), 0, null)
        {
        }

        /// <summary>
        /// Creates a new <see cref="DataFrame"/> from specified parameters.
        /// </summary>
        /// <param name="timestamp">The exact timestamp, in <see cref="Ticks"/>, of the data represented by this <see cref="DataFrame"/>.</param>
        /// <param name="configurationFrame">The <see cref="ConfigurationFrame"/> associated with this <see cref="DataFrame"/>.</param>
        /// <param name="msvID">MSVID to use for <see cref="DataFrame"/>.</param>
        /// <param name="asduCount">ASDU count.</param>
        /// <param name="asduImages">Concentrator's ASDU image cache.</param>
        /// <param name="configurationRevision">Configuration revision.</param>
        /// <remarks>
        /// This constructor is used by a consumer to generate an IEC 61850-90-5 data frame.
        /// </remarks>
        public DataFrame(Ticks timestamp, ConfigurationFrame configurationFrame, string msvID, int asduCount, byte[][] asduImages, uint configurationRevision)
            : base(new DataCellCollection(), timestamp, configurationFrame)
        {
            m_msvID = msvID;
            m_asduCount = asduCount;
            m_asduImages = asduImages;
            m_configurationRevision = configurationRevision;
        }

        /// <summary>
        /// Creates a new <see cref="DataFrame"/> from serialization parameters.
        /// </summary>
        /// <param name="info">The <see cref="SerializationInfo"/> with populated with data.</param>
        /// <param name="context">The source <see cref="StreamingContext"/> for this deserialization.</param>
        protected DataFrame(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            // Deserialize data frame
            m_frameHeader = (CommonFrameHeader)info.GetValue("frameHeader", typeof(CommonFrameHeader));
            m_msvID = info.GetString("msvID");
            m_sampleCount = info.GetUInt16("sampleCount");
            m_configurationRevision = info.GetUInt32("configurationRevision");
            SampleSynchronization = info.GetByte("sampleSynchronization");
            m_sampleRate = info.GetUInt16("sampleRate");
        }

        #endregion

        #region [ Properties ]

        /// <summary>
        /// Gets reference to the <see cref="DataCellCollection"/> for this <see cref="DataFrame"/>.
        /// </summary>
        public new DataCellCollection Cells
        {
            get
            {
                return base.Cells as DataCellCollection;
            }
        }

        /// <summary>
        /// Gets or sets <see cref="ConfigurationFrame"/> associated with this <see cref="DataFrame"/>.
        /// </summary>
        public new ConfigurationFrame ConfigurationFrame
        {
            get
            {
                return base.ConfigurationFrame as ConfigurationFrame;
            }
            set
            {
                base.ConfigurationFrame = value;
            }
        }

        /// <summary>
        /// Gets or sets exact timestamp, in ticks, of the data represented by this <see cref="DataFrame"/>.
        /// </summary>
        /// <remarks>
        /// The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001.
        /// </remarks>
        public override Ticks Timestamp
        {
            get
            {
                return CommonHeader.Timestamp;
            }
            set
            {
                // Keep timestamp updates synchrnonized...
                CommonHeader.Timestamp = value;
                base.Timestamp = value;
            }
        }

        /// <summary>
        /// Gets the identifier that is used to identify the IEC 61850-90-5 frame.
        /// </summary>
        public FrameType TypeID
        {
            get
            {
                return IEC61850_90_5.FrameType.DataFrame;
            }
        }

        /// <summary>
        /// Gets or sets IEC 61850-90-5 sample synchronization state.
        /// </summary>
        public byte SampleSynchronization
        {
            get
            {
                return m_sampleSynchronization;
            }
            set
            {
                m_sampleSynchronization = value;
            }
        }

        /// <summary>
        /// Gets or sets sample count for the <see cref="DataFrame"/>.
        /// </summary>
        public ushort SampleCount
        {
            get
            {
                return m_sampleCount;
            }
            set
            {
                m_sampleCount = value;
            }
        }

        /// <summary>
        /// Gets or sets current <see cref="CommonFrameHeader"/>.
        /// </summary>
        public CommonFrameHeader CommonHeader
        {
            get
            {
                // Make sure frame header exists - using base class timestamp to
                // prevent recursion (m_frameHeader doesn't exist yet)
                if ((object)m_frameHeader == null)
                {
                    m_frameHeader = new CommonFrameHeader(ConfigurationFrame, TypeID, base.IDCode, base.Timestamp, m_msvID, m_asduCount, m_configurationRevision)
                    {
                        ConfigurationFrame = ConfigurationFrame
                    };
                }

                return m_frameHeader;
            }
            set
            {
                m_frameHeader = value;

                if (m_frameHeader != null)
                {
                    State = m_frameHeader.State as IDataFrameParsingState;
                    base.Timestamp = m_frameHeader.Timestamp;
                    m_qualityFlags = ((uint)m_frameHeader.TimeQualityFlags | (uint)m_frameHeader.TimeQualityIndicatorCode);

                    // Reference header MSVID in data frame if it's defined
                    if ((object)m_frameHeader.MsvID != null)
                        m_msvID = m_frameHeader.MsvID;
                }
            }
        }

        // This interface implementation satisfies ISupportFrameImage<FrameType>.CommonHeader
        ICommonHeader<FrameType> ISupportFrameImage<FrameType>.CommonHeader
        {
            get
            {
                return CommonHeader;
            }
            set
            {
                CommonHeader = value as CommonFrameHeader;
            }
        }

        /// <summary>
        /// Gets or sets protocol specific quality flags for this <see cref="DataFrame"/>.
        /// </summary>
        public override uint QualityFlags
        {
            get
            {
                return m_qualityFlags;
            }
            set
            {
                m_qualityFlags = value;

                // Set time quality flags
                TimeQualityFlags = (TimeQualityFlags)(m_qualityFlags & ~(uint)TimeQualityFlags.TimeQualityIndicatorCodeMask);

                // Set time quality indicator code
                TimeQualityIndicatorCode = (TimeQualityIndicatorCode)(m_qualityFlags & (uint)TimeQualityFlags.TimeQualityIndicatorCodeMask);
            }
        }

        /// <summary>
        /// Gets or sets the <see cref="TimeQualityFlags"/> associated with this <see cref="DataFrame"/>.
        /// </summary>
        public TimeQualityFlags TimeQualityFlags
        {
            get
            {
                return CommonHeader.TimeQualityFlags;
            }
            set
            {
                CommonHeader.TimeQualityFlags = value;
            }
        }

        /// <summary>
        /// Gets or sets the <see cref="TimeQualityIndicatorCode"/> associated with this <see cref="DataFrame"/>.
        /// </summary>
        public TimeQualityIndicatorCode TimeQualityIndicatorCode
        {
            get
            {
                return CommonHeader.TimeQualityIndicatorCode;
            }
            set
            {
                CommonHeader.TimeQualityIndicatorCode = value;
            }
        }

        /// <summary>
        /// Gets the length of the header image.
        /// </summary>
        protected override int HeaderLength
        {
            get
            {
                return CommonHeader.Length;
            }
        }

        /// <summary>
        /// Gets the binary header image of the <see cref="DataFrame"/> object.
        /// </summary>
        protected override byte[] HeaderImage
        {
            get
            {
                return CommonHeader.BinaryImage;
            }
        }

        /// <summary>
        /// Gets the length of the <see cref="BinaryImage"/>.
        /// </summary>
        public override int BinaryLength
        {
            get
            {
                if ((object)m_binaryImage == null)
                {
                    // If parsing instead of publishing, we just return parsed frame length
                    if ((object)m_asduImages == null)
                        return CommonHeader.FrameLength;

                    m_binaryImage = GenerateBinaryImage();
                }

                if ((object)m_binaryImage != null)
                    return m_binaryImage.Length;

                return 0;
            }
        }

        /// <summary>
        /// Gets the binary image of this <see cref="DataFrame"/> object.
        /// </summary>
        public override byte[] BinaryImage
        {
            get
            {
                return m_binaryImage;
            }
        }

        /// <summary>
        /// Gets the length of the <see cref="FooterImage"/>.
        /// </summary>
        protected override int FooterLength
        {
            get
            {
                if (CommonHeader.SecurityAlgorithm != SecurityAlgorithm.None)
                    return 64;

                return 0;
            }
        }

        /// <summary>
        /// Gets the binary footer image of the <see cref="DataFrame"/> object.
        /// </summary>
        protected override byte[] FooterImage
        {
            get
            {
                int length = FooterLength;

                if (length > 0)
                {
                    SignatureAlgorithm algorithm = CommonHeader.SignatureAlgorithm;
                    byte[] buffer = new byte[length];

                    // Set signature tag
                    buffer[0] = 0x85;

                    // KeyID in common header is technically a lookup into derived rotating keys, but all implementations are using dummy key for now
                    HMAC hmac = (byte)algorithm <= (byte)SignatureAlgorithm.Sha256 ? (HMAC)(new CommonFrameHeader.ShaHmac(Common.DummyKey)) : (HMAC)(new CommonFrameHeader.AesHmac(Common.DummyKey));

                    switch (algorithm)
                    {
                        case SignatureAlgorithm.None:
                            break;
                        case SignatureAlgorithm.Aes64:
                            Buffer.BlockCopy(hmac.ComputeHash(BodyImage, 0, BodyLength).BlockCopy(0, 8), 0, buffer, 1, 8);
                            break;
                        case SignatureAlgorithm.Sha80:
                            Buffer.BlockCopy(hmac.ComputeHash(BodyImage, 0, BodyLength).BlockCopy(0, 10), 0, buffer, 1, 10);
                            break;
                        case SignatureAlgorithm.Sha128:
                        case SignatureAlgorithm.Aes128:
                            Buffer.BlockCopy(hmac.ComputeHash(BodyImage, 0, BodyLength).BlockCopy(0, 16), 0, buffer, 1, 16);
                            break;
                        case SignatureAlgorithm.Sha256:
                            Buffer.BlockCopy(hmac.ComputeHash(BodyImage, 0, BodyLength).BlockCopy(0, 32), 0, buffer, 1, 32);
                            break;
                        default:
                            throw new NotSupportedException(string.Format("IEC 61850-90-5 signature algorithm \"{0}\" is not currently supported: ", algorithm));
                    }
                }

                return null;
            }
        }

        /// <summary>
        /// <see cref="Dictionary{TKey,TValue}"/> of string based property names and values for the <see cref="DataFrame"/> object.
        /// </summary>
        public override Dictionary<string, string> Attributes
        {
            get
            {
                Dictionary<string, string> baseAttributes = base.Attributes;

                CommonHeader.AppendHeaderAttributes(baseAttributes);
                baseAttributes.Add("MSVID", m_msvID.ToNonNullString());
                baseAttributes.Add("Sample Count", m_sampleCount.ToString());
                baseAttributes.Add("Configuration Revision", m_configurationRevision.ToString());
                baseAttributes.Add("Sample Synchronization", SampleSynchronization + ": " + (SampleSynchronization == 0 ? "Not Synchronized" : "Synchronized"));
                baseAttributes.Add("Sample Rate", m_sampleRate.ToString());

                return baseAttributes;
            }
        }

        #endregion

        #region [ Methods ]

        // Does the work of generating binary image - this is a separate function since
        // the binary length cannot be calculated in advance due variable tag lengths
        private byte[] GenerateBinaryImage()
        {
            CommonFrameHeader header = CommonHeader;
            ConfigurationFrame configurationFrame = ConfigurationFrame;
            byte[] asduImage = null;
            int index = 0;

            // Get a buffer with extra room for variable length tags to hold new image
            asduImage = new byte[100 + configurationFrame.GetCalculatedSampleLength() + m_msvID.Length];

            //
            // Generate current ASDU image
            //

            // Encode place holder for ASDU sequence tag
            ushort asduSequence = (ushort)(header.AsduLength - 8);
            asduSequence.EncodeTagLength(SampledValueTag.AsduSequence, asduImage, ref index);

            // Encode MSVID value
            m_msvID.EncodeTagValue(SampledValueTag.MsvID, asduImage, ref index);

            // Encode sample count
            m_sampleCount.EncodeTagValue(SampledValueTag.SmpCnt, asduImage, ref index);

            // Encode configuration revision
            m_configurationRevision.EncodeTagValue(SampledValueTag.ConfRev, asduImage, ref index);

            // Encode timestamp
            ulong timestamp = Word.MakeQuadWord(header.SecondOfCentury, (uint)(((uint)header.FractionOfSecond << 8) | (uint)header.TimeQualityFlags));
            timestamp.EncodeTagValue(SampledValueTag.RefrTm, asduImage, ref index);

            // Defaulting sample synchronization state to true - not sure what value this has
            m_sampleSynchronization = 0x01;
            m_sampleSynchronization.EncodeTagValue(SampledValueTag.SmpSynch, asduImage, ref index);

            // Can optionally encode sample rate here - seems like a waste of space so we skip this
            //m_sampleRate.EncodeTagValue(SampledValueTag.SmpRate, bodyImage, ref index);

            // Encode sample length
            ushort sampleLength = (ushort)configurationFrame.GetCalculatedSampleLength();
            sampleLength.EncodeTagLength(SampledValueTag.Samples, asduImage, ref index);

            // Copy in base image
            Cells.BinaryImage().CopyImage(asduImage, ref index, sampleLength);

            // Update actual ASDU length in header for proper tag size encoding
            header.AsduLength = (ushort)index;

            // Encode actual ASDU sequence length - wireshark uses this value to locate ASDU data
            index = 0;
            asduSequence = (ushort)(header.AsduLength - 4);
            asduSequence.EncodeTagLength(SampledValueTag.AsduSequence, asduImage, ref index);

            // Next two tags, sample mod and UTC timestamp, are optional so we skip them to conserve bandwidth

            //
            // Manage ASDU image queue
            //

            // Cascade old ASDU images up one in buffer (newest last)
            for (int i = 0; i < m_asduCount - 1; i++)
            {
                m_asduImages[i] = m_asduImages[i + 1];
            }

            // Cache current ASDU image into image cache
            m_asduImages[m_asduCount - 1] = asduImage.BlockCopy(0, header.AsduLength);

            // Make sure ASDU image buffers are initialized (first time through they will all be null)
            for (int i = 0; i < m_asduCount - 1; i++)
            {
                if ((object)m_asduImages[i] == null)
                    m_asduImages[i] = m_asduImages[m_asduCount - 1];
            }

            //
            // Create combined ASDU primary buffer image
            //

            // Reset index for use in primary buffer
            index = 0;

            // Generate header image
            byte[] headerImage = header.BinaryImage;

            // Create a buffer large enough to hold combined ASDU images plus header
            byte[] buffer = new byte[headerImage.Length + m_asduImages.Sum(image => image.Length)];

            // Copy in common header
            headerImage.CopyImage(buffer, ref index, header.Length);

            // Publish each ASDU image in outgoing frame (e.g, DataCell(t-2), DataCell(t-1), DataCell(t))
            for (int i = 0; i < m_asduCount; i++)
            {
                m_asduImages[i].CopyImage(buffer, ref index, m_asduImages[i].Length);
            }

            return buffer;
        }

        /// <summary>
        /// Parses the binary image.
        /// </summary>
        /// <param name="buffer">Binary image to parse.</param>
        /// <param name="startIndex">Start index into <paramref name="buffer"/> to begin parsing.</param>
        /// <param name="length">Length of valid data within <paramref name="buffer"/>.</param>
        /// <returns>The length of the data that was parsed.</returns>
        public override int ParseBinaryImage(byte[] buffer, int startIndex, int length)
        {
            // Overrides base class behavior, ASDUs can generally be parsed even without configuration.
            buffer.ValidateParameters(startIndex, length);

            CommonFrameHeader header = CommonHeader;
            IDataFrameParsingState state = State;
            IConfigurationFrame configurationFrame = state.ConfigurationFrame;

            // Make sure configuration frame gets assigned before parsing begins, if available...
            if (configurationFrame != null)
                ConfigurationFrame = configurationFrame as ConfigurationFrame;

            int tagLength, index = startIndex;

            // Header has already been parsed, skip past it
            index += header.Length;

            // Get reference to configuration frame, if available
            m_configurationFrame = ConfigurationFrame;

            // Parse each ASDU in incoming frame (e.g, DataCell(t-2), DataCell(t-1), DataCell(t))
            for (int i = 0; i < header.AsduCount; i++)
            {
                // Handle redundant ASDU - last one parsed will be newest and exposed normally
                if (i > 0)
                {
                    if (header.ParseRedundantASDUs)
                    {
                        // Create a new data frame to hold redundant ASDU data
                        DataFrame dataFrame = new DataFrame
                        {
                            ConfigurationFrame = m_configurationFrame,
                            CommonHeader = header
                        };

                        // Add a copy of the current data cell to the new frame
                        foreach (IDataCell cell in Cells)
                        {
                            dataFrame.Cells.Add(cell);
                        }

                        // Publish new data frame with redundant ASDU data
                        header.PublishFrame(dataFrame);
                    }

                    // Clear any existing ASDU values from this data frame
                    Cells.Clear();
                }

                // Validate ASDU sequence tag exists and skip past it
                buffer.ValidateTag(SampledValueTag.AsduSequence, ref index);

                // Parse MSVID value
                m_msvID = buffer.ParseStringTag(SampledValueTag.MsvID, ref index);

                // If formatted according to implementation agreement, MSVID value will contain an ID code and station name
                if (!string.IsNullOrWhiteSpace(m_msvID))
                {
                    int underscoreIndex = m_msvID.IndexOf("_");

                    if (underscoreIndex > 0)
                    {
                        if (!ushort.TryParse(m_msvID.Substring(0, underscoreIndex), out m_idCode))
                        {
                            m_idCode = 1;
                            m_stationName = m_msvID;
                        }
                        else
                        {
                            m_stationName = m_msvID.Substring(underscoreIndex + 1);
                        }
                    }
                    else
                    {
                        m_idCode = 1;
                        m_stationName = m_msvID;
                    }
                }
                else
                {
                    m_idCode = 1;
                    m_stationName = "IEC61850Dataset";
                }

                //// Dataset name has been removed as per implementation agreement
                //// Parse dataset name
                //m_dataSet = buffer.ParseStringTag(SampledValueTag.Dataset, ref index);

                // Parse sample count
                m_sampleCount = buffer.ParseUInt16Tag(SampledValueTag.SmpCnt, ref index);

                // Parse configuration revision
                m_configurationRevision = buffer.ParseUInt32Tag(SampledValueTag.ConfRev, ref index);

                // Parse refresh time
                if ((SampledValueTag)buffer[index] != SampledValueTag.RefrTm)
                    throw new InvalidOperationException("Encountered out-of-sequence or unknown sampled value tag: 0x" + buffer[startIndex].ToString("X").PadLeft(2, '0'));

                index++;
                tagLength = buffer.ParseTagLength(ref index);

                if (tagLength < 8)
                    throw new InvalidOperationException(string.Format("Unexpected length for \"{0}\" tag: {1}", SampledValueTag.RefrTm, tagLength));

                uint secondOfCentury = BigEndian.ToUInt32(buffer, index);
                UInt24 fractionOfSecond = BigEndian.ToUInt24(buffer, index + 4);
                index += 7;

                // Get whole seconds of timestamp
                long timestamp = (new UnixTimeTag((decimal)secondOfCentury)).ToDateTime().Ticks;

                // Add fraction seconds of timestamp
                decimal fractionalSeconds = fractionOfSecond / (decimal)header.Timebase;
                timestamp += (long)(fractionalSeconds * (decimal)Ticks.PerSecond);

                // Apply parsed timestamp to common header
                header.Timestamp = timestamp;
                header.TimeQualityFlags = (TimeQualityFlags)buffer[index++];

                // Parse sample synchronization state
                SampleSynchronization = buffer.ParseByteTag(SampledValueTag.SmpSynch, ref index);

                // Parse optional sample rate
                if ((SampledValueTag)buffer[index] == SampledValueTag.SmpRate)
                    m_sampleRate = buffer.ParseUInt16Tag(SampledValueTag.SmpRate, ref index);

                // Validate that next tag is for sample values
                if ((SampledValueTag)buffer[index] != SampledValueTag.Samples)
                    throw new InvalidOperationException("Encountered out-of-sequence or unknown sampled value tag: 0x" + buffer[startIndex].ToString("X").PadLeft(2, '0'));

                index++;
                tagLength = buffer.ParseTagLength(ref index);

                // Attempt to derive a configuration if none is defined
                if ((object)m_configurationFrame == null)
                {
                    // If requested, attempt to load configuration from an associated ETR file
                    if (header.UseETRConfiguration)
                        ParseETRConfiguration();

                    // If we still have no configuration, see if a "guess" is requested
                    if ((object)m_configurationFrame == null && header.GuessConfiguration)
                        GuessAtConfiguration(tagLength);
                }

                if ((object)m_configurationFrame == null)
                {
                    // If the configuration is still unavailable, skip past sample values - don't know the details otherwise
                    index += tagLength;
                }
                else
                {
                    // See if sample size validation should by bypassed
                    if (header.IgnoreSampleSizeValidationFailures)
                    {
                        base.ParseBodyImage(buffer, index, length - (index - startIndex));
                        index += tagLength;
                    }
                    else
                    {
                        // Validate that sample size matches current configuration
                        if (tagLength != m_configurationFrame.GetCalculatedSampleLength())
                            throw new InvalidOperationException("Configuration does match data sample size - cannot parse data");

                        // Parse standard synchrophasor sequence
                        index += base.ParseBodyImage(buffer, index, length - (index - startIndex));
                    }
                }

                // Skip past optional sample mod tag, if defined
                if ((SampledValueTag)buffer[startIndex] == SampledValueTag.SmpMod)
                    buffer.ValidateTag(SampledValueTag.SmpMod, ref index);

                // Skip past optional UTC timestamp tag, if defined
                if ((SampledValueTag)buffer[startIndex] == SampledValueTag.UtcTimestamp)
                    buffer.ValidateTag(SampledValueTag.UtcTimestamp, ref index);
            }

            // We're not parsing any of the items remaining in the footer...
            return header.FrameLength;
        }

        // Attempt to parse an associated ETR configuration
        private void ParseETRConfiguration()
        {
            if (!string.IsNullOrWhiteSpace(m_msvID))
            {
                // See if an associated ETR file exists
                string etrFileName = m_msvID + ".etr";
                string etrFilePath = FilePath.GetAbsolutePath(etrFileName);
                bool foundETRFile = File.Exists(etrFilePath);

                if (!foundETRFile)
                {
                    // Also test for ETR in configuration cache folder
                    etrFilePath = FilePath.GetAbsolutePath(string.Format("ConfigurationCache{0}{1}", Path.DirectorySeparatorChar, etrFileName));
                    foundETRFile = File.Exists(etrFilePath);
                }

                if (foundETRFile)
                {
                    try
                    {
                        StreamReader reader = new StreamReader(etrFilePath);
                        SignalType signalType, lastSignalType = SignalType.NONE;
                        string label;
                        bool statusDefined = false;
                        bool endOfFile;
                        int magnitudeSignals = 0;
                        int angleSignals = 0;

                        ConfigurationFrame configFrame = new ConfigurationFrame(Common.Timebase, 1, DateTime.UtcNow.Ticks, m_sampleRate);

                        do
                        {
                            bool badOrder = false;

                            ConfigurationCell configCell = new ConfigurationCell(configFrame, (ushort)(m_idCode + configFrame.Cells.Count), LineFrequency.Hz60)
                            {
                                StationName = m_stationName + (configFrame.Cells.Count + 1)
                            };

                            // Keep parsing records until there are no more...
                            while (ParseNextSampleDefinition(reader, out signalType, out label, out endOfFile))
                            {
                                // If ETR is defining a new device, exit and handle current device
                                if (signalType == SignalType.FLAG && statusDefined)
                                {
                                    badOrder = (lastSignalType != SignalType.DFDT && lastSignalType != SignalType.ALOG && lastSignalType != SignalType.DIGI);
                                    lastSignalType = SignalType.FLAG;
                                    break;
                                }

                                // Validate signal order
                                switch (signalType)
                                {
                                    case SignalType.FLAG:
                                        badOrder = lastSignalType != SignalType.NONE;
                                        statusDefined = true;
                                        break;
                                    case SignalType.VPHM:
                                    case SignalType.IPHM:
                                        badOrder = (lastSignalType != SignalType.FLAG && lastSignalType != SignalType.VPHA && lastSignalType != SignalType.IPHA);
                                        PhasorDefinition phasor = new PhasorDefinition(configCell, label, 1, 0.0D, signalType == SignalType.VPHM ? PhasorType.Voltage : PhasorType.Current, null);
                                        configCell.PhasorDefinitions.Add(phasor);
                                        magnitudeSignals++;
                                        break;
                                    case SignalType.VPHA:
                                        badOrder = lastSignalType != SignalType.VPHM;
                                        angleSignals++;
                                        break;
                                    case SignalType.IPHA:
                                        badOrder = lastSignalType != SignalType.IPHM;
                                        angleSignals++;
                                        break;
                                    case SignalType.FREQ:
                                        badOrder = (lastSignalType != SignalType.VPHA && lastSignalType != SignalType.IPHA);
                                        break;
                                    case SignalType.DFDT:
                                        badOrder = lastSignalType != SignalType.FREQ;
                                        configCell.FrequencyDefinition = new FrequencyDefinition(configCell, "Frequency");
                                        break;
                                    case SignalType.ALOG:
                                        badOrder = (lastSignalType != SignalType.DFDT && lastSignalType != SignalType.ALOG);
                                        AnalogDefinition analog = new AnalogDefinition(configCell, label, 1, 0.0D, AnalogType.SinglePointOnWave);
                                        configCell.AnalogDefinitions.Add(analog);
                                        break;
                                    case SignalType.DIGI:
                                        badOrder = (lastSignalType != SignalType.DFDT && lastSignalType != SignalType.ALOG && lastSignalType != SignalType.DIGI);
                                        DigitalDefinition digital = new DigitalDefinition(configCell, label, 0, 1);
                                        configCell.DigitalDefinitions.Add(digital);
                                        break;
                                    default:
                                        throw new InvalidOperationException("Unxpected signal type enecountered: " + signalType);
                                }

                                lastSignalType = signalType;
                            }

                            if (badOrder)
                                throw new InvalidOperationException(string.Format("Invalid signal order encountered - {0} cannot follow {1}. Standard synchrophasor order is: status flags, one or more phasor magnitude/angle pairs, frequency, dF/dt, optional analogs, optional digitals", signalType, lastSignalType));

                            if (!statusDefined)
                                throw new InvalidOperationException("No status flag signal was defined.");

                            if (configCell.PhasorDefinitions.Count == 0)
                                throw new InvalidOperationException("No phasor magnitude/angle signal pairs were defined.");

                            if (magnitudeSignals != angleSignals)
                                throw new InvalidOperationException("Phasor magnitude/angle signal pair mismatch - there must be a one-to-one definition between angle and magnitude signals.");

                            if (configCell.FrequencyDefinition == null)
                                throw new InvalidOperationException("No frequency and dF/dt signal pair was defined.");

                            // Add cell to configuration frame
                            configFrame.Cells.Add(configCell);

                            // Reset counters
                            magnitudeSignals = 0;
                            angleSignals = 0;
                        }
                        while (!endOfFile);

                        // Publish configuration frame
                        PublishNewConfigurationFrame(configFrame);
                    }
                    catch (Exception ex)
                    {
                        throw new InvalidOperationException(string.Format("Failed to parse associated ETR configuration \"{0}\": {1}", etrFilePath, ex.Message), ex);
                    }
                }
            }
        }

        // Complex function used to read next signal type and label from the ETR file...
        // Note that current parsing depends on sample tag name format defined in the IEC 61850-90-5 implementation agreement
        private static bool ParseNextSampleDefinition(StreamReader reader, out SignalType signalType, out string label, out bool endOfFile)
        {
            string signalLabel, dataType, signalDetail;
            bool result = false;

            signalType = SignalType.NONE;
            label = null;

            // Attempt to read signal definition and label line
            signalLabel = reader.ReadLine();

            if (signalLabel != null)
            {
                // Attempt to reader data type line
                dataType = reader.ReadLine();

                if (dataType != null)
                {
                    // Clean up data type
                    dataType = dataType.Trim().ToLower();

                    int index = signalLabel.IndexOf("-");

                    // Get defined signal label
                    label = signalLabel.Substring(index + 1).Trim();

                    // See if signal type contains ST
                    index = signalLabel.IndexOf(".ST.");

                    if (index > 0)
                    {
                        // Get detail portion of signal type label
                        signalDetail = signalLabel.Substring(index + 4);

                        // Status or digital value
                        if (signalDetail.StartsWith("Ind1"))
                        {
                            // Status word value
                            signalType = SignalType.FLAG;

                            if (dataType != "i2")
                                throw new InvalidOperationException(string.Format("Invalid data type size {0} specified for signal type {1} parsed from {2}", dataType, signalType, signalLabel));

                            result = true;
                        }
                        else if (signalDetail.StartsWith("Ind2"))
                        {
                            // Digital value
                            signalType = SignalType.DIGI;

                            if (dataType != "i2")
                                throw new InvalidOperationException(string.Format("Invalid data type size {0} specified for signal type {1} parsed from {2}", dataType, signalType, signalLabel));

                            result = true;
                        }
                        else
                        {
                            // Unable to determine signal type
                            throw new InvalidOperationException(string.Format("Unable to determine ETR signal type for {0} ({1})", signalLabel, dataType));
                        }
                    }
                    else
                    {
                        // See if signal type contains MX
                        index = signalLabel.IndexOf(".MX.");

                        if (index > 0)
                        {
                            // Get detail portion of signal type label
                            signalDetail = signalLabel.Substring(index + 4);

                            // Frequency or phasor value
                            if (signalDetail.StartsWith("HzRte"))
                            {
                                // dF/dt value
                                signalType = SignalType.DFDT;

                                if (dataType != "f4")
                                    throw new InvalidOperationException(string.Format("Invalid data type size {0} specified for signal type {1} parsed from {2}", dataType, signalType, signalLabel));

                                result = true;
                            }
                            else if (signalDetail.StartsWith("Hz"))
                            {
                                // Frequency value
                                signalType = SignalType.FREQ;

                                if (dataType != "f4")
                                    throw new InvalidOperationException(string.Format("Invalid data type size {0} specified for signal type {1} parsed from {2}", dataType, signalType, signalLabel));

                                result = true;
                            }
                            else if (signalDetail.StartsWith("PhV") || signalDetail.StartsWith("SeqV"))
                            {
                                if (signalDetail.Contains(".mag."))
                                {
                                    // Voltage phase magnitude
                                    signalType = SignalType.VPHM;
                                }
                                else if (signalDetail.Contains(".ang."))
                                {
                                    // Voltage phase angle
                                    signalType = SignalType.VPHA;
                                }
                                else
                                {
                                    // Unable to determine signal type
                                    throw new InvalidOperationException(string.Format("Unable to determine ETR signal type for {0} ({1})", signalLabel, dataType));
                                }

                                if (dataType != "f4")
                                    throw new InvalidOperationException(string.Format("Invalid data type size {0} specified for signal type {1} parsed from {2}", dataType, signalType, signalLabel));

                                result = true;
                            }
                            else if (signalDetail.StartsWith("SeqA") || signalDetail.StartsWith("A"))
                            {
                                if (signalDetail.Contains(".mag."))
                                {
                                    // Current phase magnitude
                                    signalType = SignalType.IPHM;
                                }
                                else if (signalDetail.Contains(".ang."))
                                {
                                    // Current phase angle
                                    signalType = SignalType.IPHA;
                                }
                                else
                                {
                                    // Unable to determine signal type
                                    throw new InvalidOperationException(string.Format("Unable to determine ETR signal type for {0} ({1})", signalLabel, dataType));
                                }

                                if (dataType != "f4")
                                    throw new InvalidOperationException(string.Format("Invalid data type size {0} specified for signal type {1} parsed from {2}", dataType, signalType, signalLabel));

                                result = true;
                            }
                            else
                            {
                                // Unable to determine signal type
                                throw new InvalidOperationException(string.Format("Unable to determine ETR signal type for {0} ({1})", signalLabel, dataType));
                            }
                        }
                        else
                        {
                            // Assuming anything else is an Analog value
                            signalType = SignalType.ALOG;

                            if (dataType != "f4")
                                throw new InvalidOperationException(string.Format("Invalid data type size {0} specified for assumed analog signal type parsed from {1}", dataType, signalLabel));

                            result = true;
                        }
                    }
                }
            }

            endOfFile = !result;
            return result;
        }

        // Attempt to guess at the configuration
        private void GuessAtConfiguration(int sampleLength)
        {
            // Removed fixed length for 2-byte status, 4-byte frequency and 4-byte dF/dt
            int test = sampleLength - 10;

            // Assume remaining even 8-byte pairs are phasor values (i.e., 4-byte magnitude and 4-byte angle)
            int phasors = test / 8;
            test -= phasors * 8;

            // Assume remaining even 2-byte items are digital values
            int digitals = test / 2;
            test -= digitals * 2;

            // If no bytes remain, we'll assume this distribution as a guess configuration
            if (test == 0)
            {
                // Just assume some details for a configuration frame
                ConfigurationFrame configFrame = new ConfigurationFrame(Common.Timebase, 1, DateTime.UtcNow.Ticks, m_sampleRate);
                ConfigurationCell configCell = new ConfigurationCell(configFrame, m_idCode, LineFrequency.Hz60)
                {
                    StationName = m_stationName
                };

                // Add phasors
                for (int i = 0; i < phasors; i++)
                {
                    PhasorType type = i < phasors / 2 ? PhasorType.Voltage : PhasorType.Current;
                    PhasorDefinition phasor = new PhasorDefinition(configCell, "Phasor " + (i + 1), 1, 0.0D, type, null);
                    configCell.PhasorDefinitions.Add(phasor);
                }

                // Add frequency
                configCell.FrequencyDefinition = new FrequencyDefinition(configCell, "Frequency");

                // Add digitals
                for (int i = 0; i < digitals; i++)
                {
                    DigitalDefinition digital = new DigitalDefinition(configCell, "Digital " + (i + 1), 0, 1);
                    configCell.DigitalDefinitions.Add(digital);
                }

                configFrame.Cells.Add(configCell);
                PublishNewConfigurationFrame(configFrame);
            }
        }

        // Exposes a newly created configuration frame
        private void PublishNewConfigurationFrame(ConfigurationFrame configFrame)
        {
            // Cache new configuration
            m_configurationFrame = configFrame;

            // Cache new associated configuration frame
            ConfigurationFrame = configFrame;

            // Update the frame level parsing state
            bool trustHeaderLength = true;
            bool validateCheckSum = true;

            if ((object)State != null)
            {
                trustHeaderLength = State.TrustHeaderLength;
                validateCheckSum = State.ValidateCheckSum;
            }

            DataFrameParsingState parsingState = new DataFrameParsingState(CommonHeader.FrameLength, configFrame, DataCell.CreateNewCell, trustHeaderLength, validateCheckSum);
            CommonHeader.State = parsingState;
            State = parsingState;

            // Update local associated configuration cells
            for (int i = 0; i < Cells.Count; i++)
            {
                ConfigurationCell configCell = configFrame.Cells[i];

                // Update associated configuration cell
                Cells[i].ConfigurationCell = configCell;

                // Update local parsing state with new configuration info
                Cells[i].State = new DataCellParsingState(
                    configCell,
                    PhasorValue.CreateNewValue,
                    FrequencyValue.CreateNewValue,
                    AnalogValue.CreateNewValue,
                    DigitalValue.CreateNewValue);
            }

            // Publish the configuration frame to the rest of the system
            CommonHeader.PublishFrame(configFrame);
        }

        /// <summary>
        /// Determines if checksum in the <paramref name="buffer"/> is valid.
        /// </summary>
        /// <param name="buffer">Buffer image to validate.</param>
        /// <param name="startIndex">Start index into <paramref name="buffer"/> to perform checksum.</param>
        /// <returns>Flag that determines if checksum over <paramref name="buffer"/> is valid.</returns>
        protected override bool ChecksumIsValid(byte[] buffer, int startIndex)
        {
            // IEC 61850-90-5 data frame CRC is checked during header parsing
            return true;
        }

        /// <summary>
        /// Calculates checksum of given <paramref name="buffer"/>.
        /// </summary>
        /// <param name="buffer">Buffer image over which to calculate checksum.</param>
        /// <param name="offset">Start index into <paramref name="buffer"/> to calculate checksum.</param>
        /// <param name="length">Length of data within <paramref name="buffer"/> to calculate checksum.</param>
        /// <returns>Checksum over specified portion of <paramref name="buffer"/>.</returns>
        protected override ushort CalculateChecksum(byte[] buffer, int offset, int length)
        {
            throw new NotImplementedException("Checksum for IEC 61850-90-5 data frames are calculated when header is parsed, see CommonFrameHeader.");
        }

        /// <summary>
        /// Populates a <see cref="SerializationInfo"/> with the data needed to serialize the target object.
        /// </summary>
        /// <param name="info">The <see cref="SerializationInfo"/> to populate with data.</param>
        /// <param name="context">The destination <see cref="StreamingContext"/> for this serialization.</param>
        public override void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            base.GetObjectData(info, context);

            // Serialize data frame
            info.AddValue("frameHeader", m_frameHeader, typeof(CommonFrameHeader));
            info.AddValue("msvID", m_msvID);
            info.AddValue("sampleCount", m_sampleCount);
            info.AddValue("configurationRevision", m_configurationRevision);
            info.AddValue("sampleSynchronization", SampleSynchronization);
            info.AddValue("sampleRate", m_sampleRate);
        }

        #endregion
    }
}


text:
using System;
using System.Collections.Generic;
using System.Reflection;
using BenchmarkDotNet.Attributes;
using Microsoft.Extensions.DependencyInjection;
using Orleans;
using Orleans.Configuration;
using Orleans.Runtime.Configuration;
using Orleans.Serialization;
using Orleans.Serialization.ProtobufNet;
using UnitTests.GrainInterfaces;

namespace Benchmarks.Serialization
{
    public enum SerializerToUse
    {
        Default,
        IlBasedFallbackSerializer,
        ProtoBufNet
    }

    [MemoryDiagnoser]
    public class SerializationBenchmarks
    {
        private void InitializeSerializer(SerializerToUse serializerToUse)
        {
            Type fallback = null;
            switch (serializerToUse)
            {
                case SerializerToUse.Default:
                    break;
                case SerializerToUse.IlBasedFallbackSerializer:
                    fallback = typeof(ILBasedSerializer);
                    break;
                case SerializerToUse.ProtoBufNet:
                    fallback = typeof(ProtobufNetSerializer);
                    break;
                default:
                    throw new InvalidOperationException("Invalid Serializer was selected");
            }

            var client = new ClientBuilder()
                .UseLocalhostClustering()
                .Configure<ClusterOptions>(options =>
                {
                    options.ClusterId = nameof(SerializationBenchmarks);
                    options.ServiceId = Guid.NewGuid().ToString();
                })
                .Configure<SerializationProviderOptions>(
                    options => options.FallbackSerializationProvider = fallback)
                .Build();
            this.serializationManager = client.ServiceProvider.GetRequiredService<SerializationManager>();
        }

        [Params(SerializerToUse.IlBasedFallbackSerializer, SerializerToUse.Default, SerializerToUse.ProtoBufNet)]
        public SerializerToUse Serializer { get; set; }

        private OuterClass.SomeConcreteClass complexClass;

        private byte[] serializedBytes;

        private LargeTestData largeTestData;
        private SerializationManager serializationManager;

        [GlobalSetup]
        public void BenchmarkSetup()
        {
            this.InitializeSerializer(this.Serializer);

            this.complexClass = OuterClass.GetPrivateClassInstance();
            this.complexClass.Int = 89;
            this.complexClass.String = Guid.NewGuid().ToString();
            this.complexClass.NonSerializedInt = 39;
            var classes = new List<SomeAbstractClass>
            {
                this.complexClass,
                new AnotherConcreteClass
                {
                    AnotherString = "hi",
                    Interfaces = new List<ISomeInterface>
                    {
                        this.complexClass
                    }
                },
                new AnotherConcreteClass(),
                OuterClass.GetPrivateClassInstance()
            };

            this.complexClass.Classes = classes.ToArray();
            this.complexClass.Enum = SomeAbstractClass.SomeEnum.Something;
            this.complexClass.SetObsoleteInt(38);

            this.complexClass.Struct = new SomeStruct(10)
            {
                Id = Guid.NewGuid(),
                PublicValue = 6,
                ValueWithPrivateGetter = 7
            };
            this.complexClass.Struct.SetValueWithPrivateSetter(8);
            this.complexClass.Struct.SetPrivateValue(9);

            this.largeTestData = new LargeTestData
            {
                Description = "This is a test. This is only a test. In the event of a real execution, this would contain actual data.",
                EnumValue = TestEnum.First
            };
            this.largeTestData.SetBit(13);
            this.largeTestData.SetEnemy(17, CampaignEnemyTestType.Enemy1);

            this.serializedBytes = this.serializationManager.SerializeToByteArray(this.largeTestData);
        }

        [Benchmark]
        public byte[] SerializerBenchmark()
        {
            return this.serializationManager.SerializeToByteArray(this.largeTestData);
        }

        [Benchmark]
        public object DeserializerBenchmark()
        {
            return this.serializationManager.DeserializeFromByteArray<LargeTestData>(this.serializedBytes);
        }

        /// <summary>
        /// Performs a full serialization loop using a type which has not had code generation performed.
        /// </summary>
        /// <returns></returns>
        [Benchmark]
        public object FallbackFullLoop()
        {
            return OrleansSerializationLoop(this.complexClass);
        }

        internal object OrleansSerializationLoop(object input, bool includeWire = true)
        {
            var copy = this.serializationManager.DeepCopy(input);
            if (includeWire)
            {
                copy = this.serializationManager.RoundTripSerializationForTesting(copy);
            }
            return copy;
        }
    }

    [Serializable]
    internal struct SomeStruct
    {
        public Guid Id { get; set; }
        public int PublicValue { get; set; }
        public int ValueWithPrivateSetter { get; private set; }
        public int ValueWithPrivateGetter { private get; set; }
        private int PrivateValue { get; set; }
        public readonly int ReadonlyField;

        public SomeStruct(int readonlyField)
            : this()
        {
            this.ReadonlyField = readonlyField;
        }

        public int GetValueWithPrivateGetter()
        {
            return this.ValueWithPrivateGetter;
        }

        public int GetPrivateValue()
        {
            return this.PrivateValue;
        }

        public void SetPrivateValue(int value)
        {
            this.PrivateValue = value;
        }

        public void SetValueWithPrivateSetter(int value)
        {
            this.ValueWithPrivateSetter = value;
        }
    }

    internal interface ISomeInterface { int Int { get; set; } }

    [Serializable]
    internal abstract class SomeAbstractClass : ISomeInterface
    {
        [NonSerialized]
        private int nonSerializedIntField;

        public abstract int Int { get; set; }

        public List<ISomeInterface> Interfaces { get; set; }

        public SomeAbstractClass[] Classes { get; set; }

        [Obsolete("This field should not be serialized", true)]
        public int ObsoleteIntWithError { get; set; }

        [Obsolete("This field should be serialized")]
        public int ObsoleteInt { get; set; }

#pragma warning disable 618
        public int GetObsoleteInt() => this.ObsoleteInt;
        public void SetObsoleteInt(int value)
        {
            this.ObsoleteInt = value;
        }
#pragma warning restore 618

        public SomeEnum Enum { get; set; }

        public int NonSerializedInt
        {
            get
            {
                return this.nonSerializedIntField;
            }

            set
            {
                this.nonSerializedIntField = value;
            }
        }

        [Serializable]
        public enum SomeEnum
        {
            None,

            Something,

            SomethingElse
        }
    }

    internal class OuterClass
    {
        public static SomeConcreteClass GetPrivateClassInstance() => new PrivateConcreteClass(Guid.NewGuid());

        public static Type GetPrivateClassType() => typeof(PrivateConcreteClass);

        [Serializable]
        public class SomeConcreteClass : SomeAbstractClass
        {
            public override int Int { get; set; }

            public string String { get; set; }

            public SomeStruct Struct { get; set; }

            private PrivateConcreteClass secretPrivateClass;

            public void ConfigureSecretPrivateClass()
            {
                this.secretPrivateClass = new PrivateConcreteClass(Guid.NewGuid());
            }

            public bool AreSecretBitsIdentitcal(SomeConcreteClass other)
            {
                return other.secretPrivateClass?.Identity == this.secretPrivateClass?.Identity;
            }
        }

        [Serializable]
        private class PrivateConcreteClass : SomeConcreteClass
        {
            public PrivateConcreteClass(Guid identity)
            {
                this.Identity = identity;
            }

            public readonly Guid Identity;
        }
    }

    [Serializable]
    internal class AnotherConcreteClass : SomeAbstractClass
    {
        public override int Int { get; set; }

        public string AnotherString { get; set; }
    }

    [Serializable]
    internal class InnerType
    {
        public InnerType()
        {
            this.Id = Guid.NewGuid();
            this.Something = this.Id.ToString();
        }
        public Guid Id { get; set; }
        public string Something { get; set; }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            if (obj.GetType() != this.GetType()) return false;
            return Equals((InnerType)obj);
        }

        protected bool Equals(InnerType other)
        {
            return this.Id.Equals(other.Id) && string.Equals(this.Something, other.Something);
        }

        public override int GetHashCode()
        {
            unchecked
            {
                return (this.Id.GetHashCode() * 397) ^ (this.Something?.GetHashCode() ?? 0);
            }
        }
    }
}

redpajama_set_name: RedPajamaGithub


text:
/*--------------------------------------------------*/

#import "UINavigationController+GLBUI.h"
#import "UIDevice+GLBUI.h"

/*--------------------------------------------------*/

#import "GLBTransitionController.h"

/*--------------------------------------------------*/
#if defined(GLB_TARGET_IOS)
/*--------------------------------------------------*/

@interface GLBNavigationViewController : UINavigationController< GLBViewControllerExtension >

@property(nonatomic, readonly, getter=isAppeared) BOOL appeared;
@property(nonatomic, nullable, strong) __kindof GLBTransitionController* transitionModal;
@property(nonatomic, nullable, strong) __kindof GLBTransitionController* transitionNavigation;

+ (nonnull instancetype)viewControllerWithNavigationBarClass:(nullable Class)navigationBarClass toolbarClass:(nullable Class)toolbarClass NS_SWIFT_NAME(viewController(navigationBarClass:toolbarClass:));
+ (nonnull instancetype)viewControllerWithRootViewController:(nonnull UIViewController*)rootViewController NS_SWIFT_NAME(viewController(rootViewController:));

- (void)setup NS_REQUIRES_SUPER;

- (void)setNeedUpdate;

- (void)updateBarsAnimated:(BOOL)animated;
- (void)updateBarsWithViewController:(nonnull UIViewController*)viewController animated:(BOOL)animated;

@end

/*--------------------------------------------------*/
#endif
/*--------------------------------------------------*/


text:
function ChangeEntityParent() {
    if (childEntity.parent == parentEntity)
        childEntity.parent = null;
    else
        childEntity.parent = parentEntity;
    frame.DelayedExecute(2.0).Triggered.connect(ChangeEntityParent);
}

if (!scene.EntityByName("Parent")) {

    var parentEntity = scene.CreateEntity(0, ["Placeable", "Mesh"]);
    parentEntity.name = "Parent";

    var trans = parentEntity.placeable.transform;
    trans.pos = new float3(0, 0, 10);
    parentEntity.placeable.transform = trans;

    var meshRef = parentEntity.mesh.meshRef;
    meshRef.ref = "cube.mesh";
    parentEntity.mesh.meshRef = meshRef;

    var childEntity = parentEntity.CreateChild(0, ["Placeable", "Mesh"]);
    childEntity.name = "Child";

    trans = childEntity.placeable.transform;
    trans.pos = new float3(0, 2, 0.5);
    childEntity.placeable.transform = trans;
    childEntity.mesh.meshRef = meshRef;

    frame.DelayedExecute(2.0).Triggered.connect(ChangeEntityParent);

}


text:
require 'test_helper'

class MotdTest < ActiveSupport::TestCase

  test "test when motd valid" do

    path = "#{Rails.root}/test/fixtures/files/motd_valid"
    motd_file = MotdFile.new(path)
    expected_file = File.open(path).read

    assert_equal true, motd_file.exist?
    assert_equal path, motd_file.motd_path
    assert_equal expected_file, motd_file.content
  end

  test "test when motd empty" do
    path = "#{Rails.root}/test/fixtures/files/motd_empty"
    motd_file = MotdFile.new(path)

    assert_equal true, motd_file.exist?
    assert_equal path, motd_file.motd_path
    assert_equal '', motd_file.content
  end

  test "test when motd missing" do
    path = "#{Rails.root}/test/fixtures/files/motd_missing"
    motd_file = MotdFile.new(path)

    assert_equal false, motd_file.exist?
    assert_equal path, motd_file.motd_path
    assert_equal '', motd_file.content
  end

  test "test when motd nil" do

    motd_file = MotdFile.new(nil)

    assert_equal false, motd_file.exist?
    assert_nil motd_file.motd_path
    assert_equal '', motd_file.content
  end

end


text:
sb.include('Array.prototype.sum');
/**
@Name: Array.prototype.avg
@Author: Paul Visco
@Version: 1.1 11/19/07
@Description: Used to determine the average value from an array of values
@Return: Number The average value
@Example:
var myArray = [1,3,4,5];
var average = myArray.avg();
average = 3.25
*/
Array.prototype.avg = function(){
	var tl = this.sum();
	return tl/this.length;
};


text:
![Build Status](https://github.com/state-machines/state_machines/actions/workflows/ruby.yml/badge.svg)
[![Code Climate](https://codeclimate.com/github/state-machines/state_machines.svg)](https://codeclimate.com/github/state-machines/state_machines)
# State Machines

State Machines adds support for creating state machines for attributes on any Ruby class.

*Please note that multiple integrations are available for [Active Model](https://github.com/state-machines/state_machines-activemodel), [Active Record](https://github.com/state-machines/state_machines-activerecord), [Mongoid](https://github.com/state-machines/state_machines-mongoid) and more in the [State Machines organisation](https://github.com/state-machines).*  If you want to save state in your database, **you need one of these additional integrations**.

## Installation

Add this line to your application's Gemfile:

    gem 'state_machines'

And then execute:

    $ bundle

Or install it yourself as:

    $ gem install state_machines

## Usage

### Example

Below is an example of many of the features offered by this plugin, including:

* Initial states
* Namespaced states
* Transition callbacks
* Conditional transitions
* State-driven instance behavior
* Customized state values
* Parallel events
* Path analysis

Class definition:

```ruby
class Vehicle
  attr_accessor :seatbelt_on, :time_used, :auto_shop_busy

  state_machine :state, initial: :parked do
    before_transition parked: any - :parked, do: :put_on_seatbelt

    after_transition on: :crash, do: :tow
    after_transition on: :repair, do: :fix
    after_transition any => :parked do |vehicle, transition|
      vehicle.seatbelt_on = false
    end

    after_failure on: :ignite, do: :log_start_failure

    around_transition do |vehicle, transition, block|
      start = Time.now
      block.call
      vehicle.time_used += Time.now - start
    end

    event :park do
      transition [:idling, :first_gear] => :parked
    end

    event :ignite do
      transition stalled: same, parked: :idling
    end

    event :idle do
      transition first_gear: :idling
    end

    event :shift_up do
      transition idling: :first_gear, first_gear: :second_gear, second_gear: :third_gear
    end

    event :shift_down do
      transition third_gear: :second_gear, second_gear: :first_gear
    end

    event :crash do
      transition all - [:parked, :stalled] => :stalled, if: ->(vehicle) {!vehicle.passed_inspection?}
    end

    event :repair do
      # The first transition that matches the state and passes its conditions
      # will be used
      transition stalled: :parked, unless: :auto_shop_busy
      transition stalled: same
    end

    state :parked do
      def speed
        0
      end
    end

    state :idling, :first_gear do
      def speed
        10
      end
    end

    state all - [:parked, :stalled, :idling] do
      def moving?
        true
      end
    end

    state :parked, :stalled, :idling do
      def moving?
        false
      end
    end
  end

  state_machine :alarm_state, initial: :active, namespace: :'alarm' do
    event :enable do
      transition all => :active
    end

    event :disable do
      transition all => :off
    end

    state :active, :value => 1
    state :off, :value => 0
  end

  def initialize
    @seatbelt_on = false
    @time_used = 0
    @auto_shop_busy = true
    super() # NOTE: This *must* be called, otherwise states won't get initialized
  end

  def put_on_seatbelt
    @seatbelt_on = true
  end

  def passed_inspection?
    false
  end

  def tow
    # tow the vehicle
  end

  def fix
    # get the vehicle fixed by a mechanic
  end

  def log_start_failure
    # log a failed attempt to start the vehicle
  end
end
```

**Note** the comment made on the `initialize` method in the class.  In order for
state machine attributes to be properly initialized, `super()` must be called.
See `StateMachines:MacroMethods` for more information about this.

Using the above class as an example, you can interact with the state machine
like so:

```ruby
vehicle = Vehicle.new           # => #<Vehicle:0xb7cf4eac @state="parked", @seatbelt_on=false>
vehicle.state                   # => "parked"
vehicle.state_name              # => :parked
vehicle.human_state_name        # => "parked"
vehicle.parked?                 # => true
vehicle.can_ignite?             # => true
vehicle.ignite_transition       # => #<StateMachines:Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>
vehicle.state_events            # => [:ignite]
vehicle.state_transitions       # => [#<StateMachines:Transition attribute=:state event=:ignite from="parked" from_name=:parked to="idling" to_name=:idling>]
vehicle.speed                   # => 0
vehicle.moving?                 # => false

vehicle.ignite                  # => true
vehicle.parked?                 # => false
vehicle.idling?                 # => true
vehicle.speed                   # => 10
vehicle                         # => #<Vehicle:0xb7cf4eac @state="idling", @seatbelt_on=true>

vehicle.shift_up                # => true
vehicle.speed                   # => 10
vehicle.moving?                 # => true
vehicle                         # => #<Vehicle:0xb7cf4eac @state="first_gear", @seatbelt_on=true>

# A generic event helper is available to fire without going through the event's instance method
vehicle.fire_state_event(:shift_up) # => true

# Call state-driven behavior that's undefined for the state raises a NoMethodError
vehicle.speed                   # => NoMethodError: super: no superclass method `speed' for #<Vehicle:0xb7cf4eac>
vehicle                         # => #<Vehicle:0xb7cf4eac @state="second_gear", @seatbelt_on=true>

# The bang (!) operator can raise exceptions if the event fails
vehicle.park!                   # => StateMachines:InvalidTransition: Cannot transition state via :park from :second_gear

# Generic state predicates can raise exceptions if the value does not exist
vehicle.state?(:parked)         # => false
vehicle.state?(:invalid)        # => IndexError: :invalid is an invalid name

# Namespaced machines have uniquely-generated methods
vehicle.alarm_state             # => 1
vehicle.alarm_state_name        # => :active

vehicle.can_disable_alarm?      # => true
vehicle.disable_alarm           # => true
vehicle.alarm_state             # => 0
vehicle.alarm_state_name        # => :off
vehicle.can_enable_alarm?       # => true

vehicle.alarm_off?              # => true
vehicle.alarm_active?           # => false

# Events can be fired in parallel
vehicle.fire_events(:shift_down, :enable_alarm) # => true
vehicle.state_name                              # => :first_gear
vehicle.alarm_state_name                        # => :active

vehicle.fire_events!(:ignite, :enable_alarm)    # => StateMachines:InvalidParallelTransition: Cannot run events in parallel: ignite, enable_alarm

# Human-friendly names can be accessed for states/events
Vehicle.human_state_name(:first_gear)               # => "first gear"
Vehicle.human_alarm_state_name(:active)             # => "active"

Vehicle.human_state_event_name(:shift_down)         # => "shift down"
Vehicle.human_alarm_state_event_name(:enable)       # => "enable"

# States / events can also be references by the string version of their name
Vehicle.human_state_name('first_gear')              # => "first gear"
Vehicle.human_state_event_name('shift_down')        # => "shift down"

# Available transition paths can be analyzed for an object
vehicle.state_paths                                       # => [[#<StateMachines:Transition ...], [#<StateMachines:Transition ...], ...]
vehicle.state_paths.to_states                             # => [:parked, :idling, :first_gear, :stalled, :second_gear, :third_gear]
vehicle.state_paths.events                                # => [:park, :ignite, :shift_up, :idle, :crash, :repair, :shift_down]

# Possible states can be analyzed for a class
Vehicle.state_machine.states.to_a                   # [#<StateMachines::State name=:parked value="parked" initial=true>, #<StateMachines::State name=:idling value="idling" initial=false>, ...]
Vehicle.state_machines[:state].states.to_a          # [#<StateMachines::State name=:parked value="parked" initial=true>, #<StateMachines::State name=:idling value="idling" initial=false>, ...]

# Find all paths that start and end on certain states
vehicle.state_paths(:from => :parked, :to => :first_gear) # => [[
                                                          #       #<StateMachines:Transition attribute=:state event=:ignite from="parked" ...>,
                                                          #       #<StateMachines:Transition attribute=:state event=:shift_up from="idling" ...>
                                                          #    ]]
# Skipping state_machine and writing to attributes directly
vehicle.state = "parked"
vehicle.state                   # => "parked"
vehicle.state_name              # => :parked

# *Note* that the following is not supported (see StateMachines:MacroMethods#state_machine):
# vehicle.state = :parked
```

## Additional Topics

### Explicit vs. Implicit Event Transitions

Every event defined for a state machine generates an instance method on the
class that allows the event to be explicitly triggered.  Most of the examples in
the state_machine documentation use this technique.  However, with some types of
integrations, like ActiveRecord, you can also *implicitly* fire events by
setting a special attribute on the instance.

Suppose you're using the ActiveRecord integration and the following model is
defined:

```ruby
class Vehicle < ActiveRecord::Base
  state_machine initial: :parked do
    event :ignite do
      transition parked: :idling
    end
  end
end
```

To trigger the `ignite` event, you would typically call the `Vehicle#ignite`
method like so:

```ruby
vehicle = Vehicle.create    # => #<Vehicle id=1 state="parked">
vehicle.ignite              # => true
vehicle.state               # => "idling"
```

This is referred to as an *explicit* event transition.  The same behavior can
also be achieved *implicitly* by setting the state event attribute and invoking
the action associated with the state machine.  For example:

```ruby
vehicle = Vehicle.create        # => #<Vehicle id=1 state="parked">
vehicle.state_event = 'ignite'  # => 'ignite'
vehicle.save                    # => true
vehicle.state                   # => 'idling'
vehicle.state_event             # => nil
```

As you can see, the `ignite` event was automatically triggered when the `save`
action was called.  This is particularly useful if you want to allow users to
drive the state transitions from a web API.

See each integration's API documentation for more information on the implicit
approach.

### Symbols vs. Strings

In all of the examples used throughout the documentation, you'll notice that
states and events are almost always referenced as symbols.  This isn't a
requirement, but rather a suggested best practice.

You can very well define your state machine with Strings like so:

```ruby
class Vehicle
  state_machine initial: 'parked' do
    event 'ignite' do
      transition 'parked' => 'idling'
    end

    # ...
  end
end
```

You could even use numbers as your state / event names.  The **important** thing
to keep in mind is that the type being used for referencing states / events in
your machine definition must be **consistent**.  If you're using Symbols, then
all states / events must use Symbols.  Otherwise you'll encounter the following
error:

```ruby
class Vehicle
  state_machine do
    event :ignite do
      transition parked: 'idling'
    end
  end
end

# => ArgumentError: "idling" state defined as String, :parked defined as Symbol; all states must be consistent
```

There **is** an exception to this rule.  The consistency is only required within
the definition itself.  However, when the machine's helper methods are called
with input from external sources, such as a web form, state_machine will map
that input to a String / Symbol.  For example:

```ruby
class Vehicle
  state_machine initial: :parked do
    event :ignite do
      transition parked: :idling
    end
  end
end

v = Vehicle.new     # => #<Vehicle:0xb71da5f8 @state="parked">
v.state?('parked')  # => true
v.state?(:parked)   # => true
```

**Note** that none of this actually has to do with the type of the value that
gets stored.  By default, all state values are assumed to be string -- regardless
of whether the state names are symbols or strings.  If you want to store states
as symbols instead you'll have to be explicit about it:

```ruby
class Vehicle
  state_machine initial: :parked do
    event :ignite do
      transition parked: :idling
    end

    states.each do |state|
      self.state(state.name, :value => state.name.to_sym)
    end
  end
end

v = Vehicle.new     # => #<Vehicle:0xb71da5f8 @state=:parked>
v.state?('parked')  # => true
v.state?(:parked)   # => true
```

### Syntax flexibility

Although state_machine introduces a simplified syntax, it still remains
backwards compatible with previous versions and other state-related libraries by
providing some flexibility around how transitions are defined.  See below for an
overview of these syntaxes.

#### Verbose syntax

In general, it's recommended that state machines use the implicit syntax for
transitions.  However, you can be a little more explicit and verbose about
transitions by using the `:from`, `:except_from`, `:to`,
and `:except_to` options.

For example, transitions and callbacks can be defined like so:

```ruby
class Vehicle
  state_machine initial: :parked do
    before_transition from: :parked, except_to: :parked, do: :put_on_seatbelt
    after_transition to: :parked do |vehicle, transition|
      vehicle.seatbelt = 'off'
    end

    event :ignite do
      transition from: :parked, to: :idling
    end
  end
end
```

#### Transition context

Some flexibility is provided around the context in which transitions can be
defined.  In almost all examples throughout the documentation, transitions are
defined within the context of an event.  If you prefer to have state machines
defined in the context of a **state** either out of preference or in order to
easily migrate from a different library, you can do so as shown below:

```ruby
class Vehicle
  state_machine initial: :parked do
    ...

    state :parked do
      transition to: :idling, :on => [:ignite, :shift_up], if: :seatbelt_on?

      def speed
        0
      end
    end

    state :first_gear do
      transition to: :second_gear, on: :shift_up

      def speed
        10
      end
    end

    state :idling, :first_gear do
      transition to: :parked, on: :park
    end
  end
end
```

In the above example, there's no need to specify the `from` state for each
transition since it's inferred from the context.

You can also define transitions completely outside the context of a particular
state / event.  This may be useful in cases where you're building a state
machine from a data store instead of part of the class definition.  See the
example below:

```ruby
class Vehicle
  state_machine initial: :parked do
    ...

    transition parked: :idling, :on => [:ignite, :shift_up]
    transition first_gear: :second_gear, second_gear: :third_gear, on: :shift_up
    transition [:idling, :first_gear] => :parked, on: :park
    transition [:idling, :first_gear] => :parked, on: :park
    transition all - [:parked, :stalled]: :stalled, unless: :auto_shop_busy?
  end
end
```

Notice that in these alternative syntaxes:

* You can continue to configure `:if` and `:unless` conditions
* You can continue to define `from` states (when in the machine context) using
the `all`, `any`, and `same` helper methods

### Static / Dynamic definitions

In most cases, the definition of a state machine is **static**.  That is to say,
the states, events and possible transitions are known ahead of time even though
they may depend on data that's only known at runtime.  For example, certain
transitions may only be available depending on an attribute on that object it's
being run on.  All of the documentation in this library define static machines
like so:

```ruby
class Vehicle
  state_machine :state, initial: :parked do
    event :park do
      transition [:idling, :first_gear] => :parked
    end

    ...
  end
end
```

However, there may be cases where the definition of a state machine is **dynamic**.
This means that you don't know the possible states or events for a machine until
runtime.  For example, you may allow users in your application to manage the
state machine of a project or task in your system.  This means that the list of
transitions (and their associated states / events) could be stored externally,
such as in a database.  In a case like this, you can define dynamically-generated
state machines like so:

```ruby
class Vehicle
  attr_accessor :state

  # Make sure the machine gets initialized so the initial state gets set properly
  def initialize(*)
    super
    machine
  end

  # Replace this with an external source (like a db)
  def transitions
    [
      {parked: :idling, on: :ignite},
      {idling: :first_gear, first_gear: :second_gear, on: :shift_up}
      # ...
    ]
  end

  # Create a state machine for this vehicle instance dynamically based on the
  # transitions defined from the source above
  def machine
    vehicle = self
    @machine ||= Machine.new(vehicle, initial: :parked, action: :save) do
      vehicle.transitions.each {|attrs| transition(attrs)}
    end
  end

  def save
    # Save the state change...
    true
  end
end

# Generic class for building machines
class Machine
  def self.new(object, *args, &block)
    machine_class = Class.new
    machine = machine_class.state_machine(*args, &block)
    attribute = machine.attribute
    action = machine.action

    # Delegate attributes
    machine_class.class_eval do
      define_method(:definition) { machine }
      define_method(attribute) { object.send(attribute) }
      define_method("#{attribute}=") {|value| object.send("#{attribute}=", value) }
      define_method(action) { object.send(action) } if action
    end

    machine_class.new
  end
end

vehicle = Vehicle.new                   # => #<Vehicle:0xb708412c @state="parked" ...>
vehicle.state                           # => "parked"
vehicle.machine.ignite                  # => true
vehicle.machine.state                   # => "idling"
vehicle.state                           # => "idling"
vehicle.machine.state_transitions       # => [#<StateMachines:Transition ...>]
vehicle.machine.definition.states.keys  # => :first_gear, :second_gear, :parked, :idling
```

As you can see, state_machine provides enough flexibility for you to be able
to create new machine definitions on the fly based on an external source of
transitions.

## Dependencies

Ruby versions officially supported and tested:

* Ruby (MRI) 2.6.0+
* JRuby
* Rubinius

For graphing state machine:

* [state_machines-graphviz](http://github.com/state-machines/state_machines-graphviz)

For documenting state machines:

* [state_machines-yard](http://github.com/state-machines/state_machines-yard)

## TODO

* Add matchers/assertions for rspec and minitest

## Contributing

1. Fork it ( https://github.com/state-machines/state_machines/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request


text: Testing read the docs


text:
package com.ayushmaanbhav.jstockmart.client;

import java.util.*;
class Companies {
	static List<Company> comp;
	static Double sensex;

	static Company getCompanyWithName(String name) {
		for (int i = 0; i < comp.size(); i++) {
			if (comp.get(i).name.equalsIgnoreCase(name))
				return comp.get(i);
		}
		return null;
	}

	static Company getCompanyWithId(int id) {
		for (int i = 0; i < comp.size(); i++) {
			if (comp.get(i).id == id)
				return comp.get(i);
		}
		return null;
	}

	static void updateValues(int id, String name, double m, double i, double h, double l, double p_precision) {
		try {
			getCompanyWithId(id).updateData(m, h, l, p_precision);
		} catch (Exception e) {
			comp.add(new Company(id, name, m, i, h, l, p_precision));
		}
	}

	static void updateValues(int id, double m, double p_precision) throws Exception {
		try {
			getCompanyWithId(id).updateData(m, p_precision);
		} catch (Exception e) {
			throw new Exception("company does not exist");
		}
	}

	static void updateValues(int id, double m) throws Exception {
		try {
			getCompanyWithId(id).updateData(m);
		} catch (Exception e) {
			throw new Exception("company does not exist");
		}
	}

	static void removeDuplicates() {
		for (int i = 0; i < comp.size(); i++) {
			for (int j = 0; j < comp.size(); j++) {
				if (comp.get(i).id == comp.get(j).id) {
					comp.remove(j);
				}
			}
		}
	}
}


text:
<!DOCTYPE html>
<style>
html {
    background: url('../../compositing/repaint/resources/grid.png');
    position: absolute;
    left: 12px;
    top: 34px;

    background-attachment: fixed;
}
</style>
Root background with fixed attachment shouldn't be affected by layout of the root box.


text:
module Daodalus

  module Connection
    extend self

    def register(connection, name='default')
      connections[name.to_s] = connection
    end

    def fetch(name='default')
      connections.fetch(name.to_s) { raise InvalidConnectionError.new(name) }
    end

    def connections
      @connections ||= {}
    end

  end
end


text:
/**
 * Activity-related functions
 */
///// ACTIVITY TYPE ///////////////////////////////////////////////////////////

// var ActivityType = Backbone.Model.extend({
//     getIconPath: function() {
//         return "img/" + this.icon + ".png"
//     }
// });

var DEFAULT_ACTIVITY_TYPES = {
    "unspecified":  {displayName:"",icon: "who-knows"},

    "baseball":     {displayName: "Baseball",  icon: "baseball"},
    // "basketball":   {displayName: "Basketball",icon: "basketball"},
    "cycling":      {displayName: "Cycling",   icon: "cycling"},
    "curling":      {displayName: "Curling",   icon: "curling"},
    "indoorbike":   {displayName: "Indoor Bike", icon: "exercise-bike"},
    "lifting":      {displayName: "Lifting",   icon: "dumbbell"},
    "karate":       {displayName: "Karate",    icon: "karate"},
    "polka":        {displayName: "Polka",     icon: "../../../iconarchive/polka"},
    "pushups":      {displayName: "PushUps",   icon: "pushups"},
    "running":      {displayName: "Running",   icon: "running"},
    "sitting":      {displayName: "Aggressive Sitting", icon: "../../../flaticon/sitting"},
    "stretching":   {displayName: "Stretching",icon: "stretching"},
    "swimming":     {displayName: "Swimming",  icon: "swimming"},
    "treadmill":    {displayName: "Treadmill", icon: "treadmill"},
    "yoga":         {displayName: "Yoga",      icon: "yoga"}
    // TODO add more if desired
};

var DISPLAY_NAMES_2_ACTIV_NAMES = {};
for (var activ in DEFAULT_ACTIVITY_TYPES) {
    var obj = DEFAULT_ACTIVITY_TYPES[activ];
    DISPLAY_NAMES_2_ACTIV_NAMES[obj.displayName] = activ;
}

function displayNameForLabel(lbl) {
    knownActivity = DEFAULT_ACTIVITY_TYPES[lbl];
    return knownActivity ? knownActivity.displayName : lbl;
}

// function activityForDisplayName(name) {
//     var activKey = DISPLAY_NAMES_2_ACTIV_NAMES[name];
    // var activObj = DEFAULT_ACTIVITY_TYPES[activKey];
//     return activObj;
// }

function getAllActivities(request, response) {
    var baseTypes = Object.keys(DEFAULT_ACTIVITY_TYPES).map(function(a){
        return DEFAULT_ACTIVITY_TYPES[a].displayName;
    }).filter(function(n) { return n != ''; });
    // custom types
    var customTypes = [];
    var customMap = {};
    window.dataset.get('sessions').forEach(function(session){
        var label = session.get('label');
        if(label.toLowerCase() in customMap)
            return;
        if(label in DEFAULT_ACTIVITY_TYPES)
            return;
        if(label.length){
            label = label.charAt(0).toUpperCase() + label.substring(1);
        }
        customTypes.push(label);
        customMap[label.toLowerCase()] = label;
    });
    // final types
    var types = baseTypes.concat(customTypes).filter(function(a){
        return a.toLowerCase().indexOf(request.term.toLowerCase()) > -1;
    });
    // TODO add all types ever, not just defaults
    types.sort();
    response(types);
}

function normalizeActivity(label) {
    // @see http://www.regular-expressions.info/refcharclass.html
    return label.replace(/[^a-zA-Z ]+/g, '') // remove invalid characters
                .replace(/ +/g, ' ') // remove duplicate spaces
                .replace(/^ +/, '') // trim prepending spaces
                .replace(/ +$/, '') // trim appending spaces
                .toLowerCase(); // to lower case
}

///// ACTIVITY INFO POPUP /////////////////////////////////////////////////////

function setupActivity(){

    // make the text field be an autocomplete text (this plays poorly
    // with the dropdown, but would be preferable)
    $('#activityTypeInput').autocomplete({
        source: getAllActivities,
        appendTo: '#activityInfoView',
        minLength: 0
    });
    $('#activityTypeInput').focus(function(e) {
        if ($(this).val() == '') {
            $(this).autocomplete('search');
        }
    });

    // don't close the popup when clicked
    $('.dropdown-menu').click(function(e) {
          e.stopPropagation();
    });
    $('#cancelActivityInfo').click(function(e){
        e.preventDefault();
        hideActivityInfo(false);
    });
    $('#submitActivityInfo').click(submitActivityInfo);
    $('#deleteSession').click(deleteSession);

    $('#activityLayer').click(function(e){
        if(e.target != e.currentTarget)
            return;
        e.preventDefault();
        hideActivityInfo(false);
    });

    // submitting the form on <Enter>
    $('#activityTypeInput, #durationInput').keypress(function(e) {
        if(e.which == 13){
            $(this).blur();
            $('#submitActivityInfo').focus().click();
            return false;
        }
    });

    // duration and <Ok/Delete> labeling
    $('#durationInput').on('change', function(){
        var valid = validateInput();
        var duration = parseDuration($('#durationInput').val());
        var isDelete = duration <= 0;
        // The Delete button is right there... do we need to do anything else
        // besides disable the Okay button?
        $('#submitActivityInfo').prop('disabled', isDelete || !valid)
                                .toggleClass('disabled', isDelete || !valid);
        /*
        $('#submitActivityInfo').text(isDelete ? 'Delete' : 'Okay');
        if(isDelete)
            $('#submitActivityInfo').addClass('btn-danger');
        else
            $('#submitActivityInfo').removeClass('btn-danger');
        */
    });
}

function validateInput(){
    var duration = $('#durationInput').val();
    if(!duration.match(/^[0-9]+$/) && !duration.match(/[0-9]+:[0-9]+/)){
        // TODO maybe provide message to user
        // (though HTML-5 browsers already give a hint with red highlight and tooltip on hover)
        return false;
    }
    return true;
}

// @see http://help.dottoro.com/ljtfkhio.php
function selectContentOf(node){
    var len = $(node).val().length;
    if('selectionStart' in node){
        node.selectionStart = 0;
        node.selectionEnd = len;
        node.focus();
    } else {
        var inputRange = node.createTextRange();
        inputRange.moveStart('character', 0);
        inputRange.collapse();
        inputRange.moveEnd('character', len);
        inputRange.select();
    }
}

function showActivityInfo(session, callback, selectType, isCreate) {
    var layer = $('#activityLayer');
    // bind edited data
    layer.data('session', session);
    layer.data('callback', callback);

    // set date
    layer.find('#activityDate').text(moment(session.get('date')).format('ddd, MMM D'));

    // set fields according to session
    var durationInput = $('#durationInput');
    var duration = session.get('duration');
    durationInput.val(formatDuration(duration));

    var activ = session.get('label');
    // let the record show that Alex wrote this line
    var activityType = $('#activityTypeInput');
    activityType.val((DEFAULT_ACTIVITY_TYPES[activ] || {displayName: activ}).displayName);

    // since we are showing => duration > 0 => can save without deleting
    $('#submitActivityInfo').prop('disabled', false);

    // show delete button iff editing an existing session; update layout
    if (isCreate) {
        $('#deleteSession').hide();
        $('#activityInfoView button').removeClass('col-xs-4').addClass('col-xs-6');
    } else {
        $('#deleteSession').show();
        $('#activityInfoView button').removeClass('col-xs-6').addClass('col-xs-4');
    }

    // show layer
    layer.stop().fadeIn();

    // disable scrolling
    lockScroll();

    // select duration input
    // Note: the field must be visible for that to work!
    durationInput.blur();
    activityType.blur();
    if(selectType){
        activityType.val('');
        selectContentOf(activityType[0]);
        activityType.autocomplete('search', '');
    } else {
        selectContentOf(durationInput[0]);
    }
}

function hideActivityInfo(isOK) {
    var layer = $('#activityLayer');

    // trigger callback
    var callback = layer.data('callback') || function(){ console.log('No callback!'); };
    callback(isOK);

    //  hide
    layer.stop().fadeOut(400, unlockScroll);
}

function submitActivityInfo() {
    var layer = $('#activityLayer');
    var session = layer.data('session');

    // don't submit unless it's valid
    if(!validateInput()){
        return;
    }

    // update model (callback is responsible for the commit)
    var duration = parseDuration($('#durationInput').val());
    session.set('duration', duration);

    var displayName = $('#activityTypeInput').val();
    var activName = DISPLAY_NAMES_2_ACTIV_NAMES[displayName] || normalizeActivity(displayName);
    session.set('label', activName);

    // hide
    hideActivityInfo(true);
}

function deleteSession() {
    var layer = $('#activityLayer');
    var session = layer.data('session');
    // Easiest to let the caller take care of the actual deletion.
    session.set('duration', 0);
    hideActivityInfo(true);
}

///////////////////////////////////////////////////////////////////////////////
///// SCROLL LOCK /////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// @see http://stackoverflow.com/questions/3656592/how-to-programmatically-disable-page-scrolling-with-jquery
function lockScroll(){
    var $html = $('html');
    var $body = $('body');
    var initWidth = $body.outerWidth();
    var initHeight = $body.outerHeight();

    var scrollPosition = [
        self.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
        self.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop
    ];
    $html.data('scroll-position', scrollPosition);
    $html.data('previous-overflow', $html.css('overflow'));
    $html.css('overflow', 'hidden');
    window.scrollTo(scrollPosition[0], scrollPosition[1]);

    var marginR = $body.outerWidth()-initWidth;
    var marginB = $body.outerHeight()-initHeight;
    $body.css({'margin-right': marginR,'margin-bottom': marginB});

    // special fixed elements
    $('#header > nav').css({ 'padding-right': marginR });
}
function unlockScroll(){
    var $html = $('html');
    var $body = $('body');
    $html.css('overflow', $html.data('previous-overflow'));
    var scrollPosition = $html.data('scroll-position');
    window.scrollTo(scrollPosition[0], scrollPosition[1]);

    $body.css({'margin-right': 0, 'margin-bottom': 0});

    // fixed elements
    $('#header > nav').css({ 'padding-right': 0 });
}


text:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Workshop 3: Managing GRC for K8s on EKS on Weaveworks Introduction to GitOps w/ AWS EKS</title>
    <link>/30_workshop_03_grc.html</link>
    <description>Recent content in Workshop 3: Managing GRC for K8s on EKS on Weaveworks Introduction to GitOps w/ AWS EKS</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-US</language>

	<atom:link href="/30_workshop_03_grc/index.xml" rel="self" type="application/rss+xml" />

  </channel>
</rss>


text:
package jp.ats.liverwort.sql.binder;

import java.io.Reader;

import jp.ats.liverwort.jdbc.LiPreparedStatement;
import jp.ats.liverwort.sql.Binder;

/**
 * {@link LiPreparedStatement} に {@link Reader} から読み込んだ値を設定するための {@link Binder} です。
 *
 * @author 千葉 哲嗣
 */
public final class CharacterStreamBinder extends Binder {

	private final Reader value;

	private final int length;

	/**
	 * 値を読み込む {@link Reader} を持つインスタンスを生成します。
	 *
	 * @param value 値を読み込む {@link Reader}
	 * @param length 値のサイズ
	 */
	public CharacterStreamBinder(Reader value, int length) {
		this.value = value;
		this.length = length;
	}

	@Override
	public String toString() {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean canEvalValue() {
		return false;
	}

	@Override
	public Object getValue() {
		throw new UnsupportedOperationException();
	}

	@Override
	public Binder replicate() {
		throw new UnsupportedOperationException();
	}

	@Override
	public void bind(int index, LiPreparedStatement statement) {
		statement.setCharacterStream(index, value, length);
	}

	@Override
	protected Object getSpecificallyValue() {
		throw new UnsupportedOperationException();
	}
}