text:
using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Internal;
using System.Management.Automation.Remoting;
using System.Management.Automation.Remoting.Internal;
using System.Threading;
using Microsoft.Management.Infrastructure;
using Microsoft.Management.Infrastructure.Options;
using Microsoft.PowerShell.Cim;
using Dbg = System.Management.Automation.Diagnostics;

#if CORECLR
// Some APIs are missing from System.Environment. We use System.Management.Automation.Environment as a proxy type:
//  - for missing APIs, System.Management.Automation.Environment has extension implementation.
//  - for existing APIs, System.Management.Automation.Environment redirect the call to System.Environment.
using Environment = System.Management.Automation.Environment;
#endif

namespace Microsoft.PowerShell.Cmdletization.Cim
{
    /// <summary>
    /// Base class for all child jobs that wrap CIM operations
    /// </summary>
    internal abstract class CimChildJobBase<T> :
        StartableJob,
        IObserver<T>
    {
        private static long s_globalJobNumberCounter;
        private readonly long _myJobNumber = Interlocked.Increment(ref s_globalJobNumberCounter);
        private const string CIMJobType = "CimJob";

        internal CimJobContext JobContext
        {
            get
            {
                return _jobContext;
            }
        }
        private readonly CimJobContext _jobContext;

        internal CimChildJobBase(CimJobContext jobContext)
            : base(Job.GetCommandTextFromInvocationInfo(jobContext.CmdletInvocationInfo), " " /* temporary name - reset below */)
        {
            _jobContext = jobContext;
            this.PSJobTypeName = CIMJobType;

            this.Name = this.GetType().Name + _myJobNumber.ToString(CultureInfo.InvariantCulture);
            UsesResultsCollection = true;

            lock (s_globalRandom)
            {
                _random = new Random(s_globalRandom.Next());
            }

            _jobSpecificCustomOptions = new Lazy<CimCustomOptionsDictionary>(this.CalculateJobSpecificCustomOptions);
        }

        private CimSensitiveValueConverter _cimSensitiveValueConverter = new CimSensitiveValueConverter();
        internal CimSensitiveValueConverter CimSensitiveValueConverter { get { return _cimSensitiveValueConverter; } }

        internal abstract IObservable<T> GetCimOperation();

        public abstract void OnNext(T item);

        // copied from sdpublic\sdk\inc\wsmerror.h
        private enum WsManErrorCode : uint
        {
            ERROR_WSMAN_QUOTA_MAX_SHELLS = 0x803381A5,
            ERROR_WSMAN_QUOTA_MAX_OPERATIONS = 0x803381A6,
            ERROR_WSMAN_QUOTA_USER = 0x803381A7,
            ERROR_WSMAN_QUOTA_SYSTEM = 0x803381A8,
            ERROR_WSMAN_QUOTA_MAX_SHELLUSERS = 0x803381AB,
            ERROR_WSMAN_QUOTA_MAX_SHELLS_PPQ = 0x803381E4,
            ERROR_WSMAN_QUOTA_MAX_USERS_PPQ = 0x803381E5,
            ERROR_WSMAN_QUOTA_MAX_PLUGINSHELLS_PPQ = 0x803381E6,
            ERROR_WSMAN_QUOTA_MAX_PLUGINOPERATIONS_PPQ = 0x803381E7,
            ERROR_WSMAN_QUOTA_MAX_OPERATIONS_USER_PPQ = 0x803381E8,
            ERROR_WSMAN_QUOTA_MAX_COMMANDS_PER_SHELL_PPQ = 0x803381E9,
            ERROR_WSMAN_QUOTA_MIN_REQUIREMENT_NOT_AVAILABLE_PPQ = 0x803381EA,
        }

        private static bool IsWsManQuotaReached(Exception exception)
        {
            var cimException = exception as CimException;
            if (cimException == null)
            {
                return false;
            }

            if (cimException.NativeErrorCode != NativeErrorCode.ServerLimitsExceeded)
            {
                return false;
            }

            CimInstance cimError = cimException.ErrorData;
            if (cimError == null)
            {
                return false;
            }

            CimProperty errorCodeProperty = cimError.CimInstanceProperties["error_Code"];
            if (errorCodeProperty == null)
            {
                return false;
            }
            if (errorCodeProperty.CimType != CimType.UInt32)
            {
                return false;
            }

            WsManErrorCode wsManErrorCode = (WsManErrorCode)(UInt32)(errorCodeProperty.Value);
            switch (wsManErrorCode) // error codes that should result in sleep-and-retry are based on an email from Ryan
            {
                case WsManErrorCode.ERROR_WSMAN_QUOTA_MAX_SHELLS:
                case WsManErrorCode.ERROR_WSMAN_QUOTA_MAX_OPERATIONS:
                case WsManErrorCode.ERROR_WSMAN_QUOTA_USER:
                case WsManErrorCode.ERROR_WSMAN_QUOTA_SYSTEM:
                case WsManErrorCode.ERROR_WSMAN_QUOTA_MAX_SHELLUSERS:
                case WsManErrorCode.ERROR_WSMAN_QUOTA_MAX_SHELLS_PPQ:
                case WsManErrorCode.ERROR_WSMAN_QUOTA_MAX_USERS_PPQ:
                case WsManErrorCode.ERROR_WSMAN_QUOTA_MAX_PLUGINSHELLS_PPQ:
                case WsManErrorCode.ERROR_WSMAN_QUOTA_MAX_PLUGINOPERATIONS_PPQ:
                case WsManErrorCode.ERROR_WSMAN_QUOTA_MAX_OPERATIONS_USER_PPQ:
                case WsManErrorCode.ERROR_WSMAN_QUOTA_MAX_COMMANDS_PER_SHELL_PPQ:
                case WsManErrorCode.ERROR_WSMAN_QUOTA_MIN_REQUIREMENT_NOT_AVAILABLE_PPQ:
                    return true;

                default:
                    return false;
            }
        }

        public virtual void OnError(Exception exception)
        {
            this.ExceptionSafeWrapper(
                    delegate
                    {
                        if (IsWsManQuotaReached(exception))
                        {
                            this.SleepAndRetry();
                            return;
                        }

                        var cje = CimJobException.CreateFromAnyException(this.GetDescription(), this.JobContext, exception);
                        this.ReportJobFailure(cje);
                    });
        }

        public virtual void OnCompleted()
        {
            this.ExceptionSafeWrapper(
                    delegate
                    {
                        this.SetCompletedJobState(JobState.Completed, null);
                    });
        }

        private static readonly Random s_globalRandom = new Random();
        private readonly Random _random;
        private int _sleepAndRetryDelayRangeMs = 1000;
        private int _sleepAndRetryExtraDelayMs = 0;
        private const int MaxRetryDelayMs = 15 * 1000;
        private const int MinRetryDelayMs = 100;
        private Timer _sleepAndRetryTimer;
        private void SleepAndRetry_OnWakeup(object state)
        {
            this.ExceptionSafeWrapper(
                    delegate
                    {
                        lock (_jobStateLock)
                        {
                            if (_sleepAndRetryTimer != null)
                            {
                                _sleepAndRetryTimer.Dispose();
                                _sleepAndRetryTimer = null;
                            }
                            if (_jobWasStopped)
                            {
                                this.SetCompletedJobState(JobState.Stopped, null);
                                return;
                            }
                        }
                        this.StartJob();
                    });
        }
        private void SleepAndRetry()
        {
            int tmpRandomDelay = _random.Next(0, _sleepAndRetryDelayRangeMs);
            int delay = MinRetryDelayMs + _sleepAndRetryExtraDelayMs + tmpRandomDelay;
            _sleepAndRetryExtraDelayMs = _sleepAndRetryDelayRangeMs - tmpRandomDelay;
            if (_sleepAndRetryDelayRangeMs < MaxRetryDelayMs)
            {
                _sleepAndRetryDelayRangeMs *= 2;
            }

            string verboseMessage = string.Format(
                CultureInfo.InvariantCulture,
                CmdletizationResources.CimJob_SleepAndRetryVerboseMessage,
                this.JobContext.CmdletInvocationInfo.InvocationName,
                this.JobContext.Session.ComputerName ?? "localhost",
                delay / 1000.0);
            this.WriteVerbose(verboseMessage);

            lock (_jobStateLock)
            {
                if (_jobWasStopped)
                {
                    this.SetCompletedJobState(JobState.Stopped, null);
                }
                else
                {
                    Dbg.Assert(_sleepAndRetryTimer == null, "There should be only 1 active _sleepAndRetryTimer");
                    _sleepAndRetryTimer = new Timer(
                        state: null,
                        dueTime: delay,
                        period: Timeout.Infinite,
                        callback: SleepAndRetry_OnWakeup);
                }
            }
        }

        /// <summary>
        /// Indicates a location where this job is running
        /// </summary>
        public override string Location
        {
            get
            {
                // this.JobContext is set in the constructor of CimChildJobBase,
                // but the constructor of Job wants to access Location property
                // before CimChildJobBase is fully initialized
                if (this.JobContext == null)
                {
                    return null;
                }

                string location = this.JobContext.Session.ComputerName ?? Environment.MachineName;
                return location;
            }
        }

        /// <summary>
        /// Status message associated with the Job
        /// </summary>
        public override string StatusMessage
        {
            get
            {
                return this.JobStateInfo.State.ToString();
            }
        }

        /// <summary>
        /// Indicates if job has more data available.
        /// </summary>
        public override bool HasMoreData
        {
            get
            {
                return (Results.IsOpen || Results.Count > 0);
            }
        }

        internal void WriteVerboseStartOfCimOperation()
        {
            if (this.JobContext.CmdletInvocationContext.CmdletDefinitionContext.ClientSideWriteVerbose)
            {
                string verboseMessage = string.Format(
                    CultureInfo.CurrentCulture,
                    CmdletizationResources.CimJob_VerboseExecutionMessage,
                    this.GetDescription());
                this.WriteVerbose(verboseMessage);
            }
        }

        internal override void StartJob()
        {
            lock (_jobStateLock)
            {
                if (_jobWasStopped)
                {
                    this.SetCompletedJobState(JobState.Stopped, null);
                    return;
                }

                Dbg.Assert(!_alreadyReachedCompletedState, "Job shouldn't reach completed state, before ThrottlingJob has a chance to register for job-completed/failed events");

                TerminatingErrorTracker tracker = TerminatingErrorTracker.GetTracker(this.JobContext.CmdletInvocationInfo);
                if (tracker.IsSessionTerminated(this.JobContext.Session))
                {
                    this.SetCompletedJobState(JobState.Failed, new OperationCanceledException());
                    return;
                }

                if (!_jobWasStarted)
                {
                    _jobWasStarted = true;
                    this.SetJobState(JobState.Running);
                }
            }

            // This invocation can block (i.e. by calling Job.ShouldProcess) and wait for pipeline thread to unblock it
            // Therefore we have to do the invocation outside of the pipeline thread.
            ThreadPool.QueueUserWorkItem(delegate
            {
                this.ExceptionSafeWrapper(delegate
                {
                    IObservable<T> observable = this.GetCimOperation();
                    if (observable != null)
                    {
                        observable.Subscribe(this);
                    }
                });
            });
        }

        internal string GetDescription()
        {
            try
            {
                return this.Description;
            }
            catch (Exception)
            {
                return this.FailSafeDescription;
            }
        }

        internal abstract string Description { get; }
        internal abstract string FailSafeDescription { get; }

        internal void ExceptionSafeWrapper(Action action)
        {
            try
            {
                try
                {
                    Dbg.Assert(action != null, "Caller should verify action != null");
                    action();
                }
                catch (CimJobException e)
                {
                    this.ReportJobFailure(e);
                }
                catch (PSInvalidCastException e)
                {
                    this.ReportJobFailure(e);
                }
                catch (CimException e)
                {
                    var cje = CimJobException.CreateFromCimException(this.GetDescription(), this.JobContext, e);
                    this.ReportJobFailure(cje);
                }
                catch (PSInvalidOperationException)
                {
                    lock (_jobStateLock)
                    {
                        bool everythingIsOk = false;
                        if (_jobWasStopped)
                        {
                            everythingIsOk = true;
                        }
                        if (_alreadyReachedCompletedState && _jobHadErrors)
                        {
                            everythingIsOk = true;
                        }
                        if (!everythingIsOk)
                        {
                            Dbg.Assert(false, "PSInvalidOperationException should only happen in certain job states");
                            throw;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                var cje = CimJobException.CreateFromAnyException(this.GetDescription(), this.JobContext, e);
                this.ReportJobFailure(cje);
            }
        }

        #region Operation options

        internal virtual string GetProviderVersionExpectedByJob()
        {
            return this.JobContext.CmdletInvocationContext.CmdletDefinitionContext.CmdletizationClassVersion;
        }

        internal CimOperationOptions CreateOperationOptions()
        {
            var operationOptions = new CimOperationOptions(mustUnderstand: false)
            {
                CancellationToken = _cancellationTokenSource.Token,
                WriteProgress = this.WriteProgressCallback,
                WriteMessage = this.WriteMessageCallback,
                WriteError = this.WriteErrorCallback,
                PromptUser = this.PromptUserCallback,
            };

            operationOptions.SetOption("__MI_OPERATIONOPTIONS_IMPROVEDPERF_STREAMING", 1);

            operationOptions.Flags |= this.JobContext.CmdletInvocationContext.CmdletDefinitionContext.SchemaConformanceLevel;

            if (this.JobContext.CmdletInvocationContext.CmdletDefinitionContext.ResourceUri != null)
            {
                operationOptions.ResourceUri = this.JobContext.CmdletInvocationContext.CmdletDefinitionContext.ResourceUri;
            }

            if ((
                  (_jobContext.WarningActionPreference == ActionPreference.SilentlyContinue) ||
                  (_jobContext.WarningActionPreference == ActionPreference.Ignore)
                ) && (!_jobContext.IsRunningInBackground))
            {
                operationOptions.DisableChannel((UInt32)MessageChannel.Warning);
            }
            else
            {
                operationOptions.EnableChannel((UInt32)MessageChannel.Warning);
            }

            if ((
                  (_jobContext.VerboseActionPreference == ActionPreference.SilentlyContinue) ||
                  (_jobContext.VerboseActionPreference == ActionPreference.Ignore)
                ) && (!_jobContext.IsRunningInBackground))
            {
                operationOptions.DisableChannel((UInt32)MessageChannel.Verbose);
            }
            else
            {
                operationOptions.EnableChannel((UInt32)MessageChannel.Verbose);
            }

            if ((
                  (_jobContext.DebugActionPreference == ActionPreference.SilentlyContinue) ||
                  (_jobContext.DebugActionPreference == ActionPreference.Ignore)
                ) && (!_jobContext.IsRunningInBackground))
            {
                operationOptions.DisableChannel((UInt32)MessageChannel.Debug);
            }
            else
            {
                operationOptions.EnableChannel((UInt32)MessageChannel.Debug);
            }

            switch (this.JobContext.ShouldProcessOptimization)
            {
                case MshCommandRuntime.ShouldProcessPossibleOptimization.AutoNo_CanCallShouldProcessAsynchronously:
                    operationOptions.SetPromptUserRegularMode(CimCallbackMode.Report, automaticConfirmation: false);
                    break;

                case MshCommandRuntime.ShouldProcessPossibleOptimization.AutoYes_CanCallShouldProcessAsynchronously:
                    operationOptions.SetPromptUserRegularMode(CimCallbackMode.Report, automaticConfirmation: true);
                    break;

                case MshCommandRuntime.ShouldProcessPossibleOptimization.AutoYes_CanSkipShouldProcessCall:
                    operationOptions.SetPromptUserRegularMode(CimCallbackMode.Ignore, automaticConfirmation: true);
                    break;

                case MshCommandRuntime.ShouldProcessPossibleOptimization.NoOptimizationPossible:
                default:
                    operationOptions.PromptUserMode = CimCallbackMode.Inquire;
                    break;
            }

            switch (this.JobContext.ErrorActionPreference)
            {
                case ActionPreference.Continue:
                case ActionPreference.SilentlyContinue:
                case ActionPreference.Ignore:
                    operationOptions.WriteErrorMode = CimCallbackMode.Report;
                    break;

                case ActionPreference.Stop:
                case ActionPreference.Inquire:
                default:
                    operationOptions.WriteErrorMode = CimCallbackMode.Inquire;
                    break;
            }

            if (!string.IsNullOrWhiteSpace(this.GetProviderVersionExpectedByJob()))
            {
                CimOperationOptionsHelper.SetCustomOption(
                    operationOptions,
                    "MI_OPERATIONOPTIONS_PROVIDERVERSION",
                    this.GetProviderVersionExpectedByJob(),
                    CimSensitiveValueConverter);
            }

            if (this.JobContext.CmdletizationModuleVersion != null)
            {
                CimOperationOptionsHelper.SetCustomOption(
                    operationOptions,
                    "MI_OPERATIONOPTIONS_POWERSHELL_MODULEVERSION",
                    this.JobContext.CmdletizationModuleVersion,
                    CimSensitiveValueConverter);
            }
            CimOperationOptionsHelper.SetCustomOption(
                operationOptions,
                "MI_OPERATIONOPTIONS_POWERSHELL_CMDLETNAME",
                this.JobContext.CmdletInvocationInfo.MyCommand.Name,
                CimSensitiveValueConverter);
            if (!string.IsNullOrWhiteSpace(this.JobContext.Session.ComputerName))
            {
                CimOperationOptionsHelper.SetCustomOption(
                    operationOptions,
                    "MI_OPERATIONOPTIONS_POWERSHELL_COMPUTERNAME",
                    this.JobContext.Session.ComputerName,
                    CimSensitiveValueConverter);
            }

            CimCustomOptionsDictionary jobSpecificCustomOptions = this.GetJobSpecificCustomOptions();
            if (jobSpecificCustomOptions != null)
            {
                jobSpecificCustomOptions.Apply(operationOptions, CimSensitiveValueConverter);
            }

            return operationOptions;
        }

        private readonly Lazy<CimCustomOptionsDictionary> _jobSpecificCustomOptions;
        internal abstract CimCustomOptionsDictionary CalculateJobSpecificCustomOptions();
        private CimCustomOptionsDictionary GetJobSpecificCustomOptions()
        {
            return _jobSpecificCustomOptions.Value;
        }

        #endregion

        #region Controlling job state

        private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();

        /// <summary>
        /// Stops this job.
        /// </summary>
        public override void StopJob()
        {
            lock (_jobStateLock)
            {
                if (_jobWasStopped || _alreadyReachedCompletedState)
                {
                    return;
                }
                _jobWasStopped = true;

                if (!_jobWasStarted)
                {
                    this.SetCompletedJobState(JobState.Stopped, null);
                }
                else if (_sleepAndRetryTimer != null)
                {
                    _sleepAndRetryTimer.Dispose();
                    _sleepAndRetryTimer = null;
                    this.SetCompletedJobState(JobState.Stopped, null);
                }
                else
                {
                    this.SetJobState(JobState.Stopping);
                }
            }
            _cancellationTokenSource.Cancel();
        }

        private readonly object _jobStateLock = new object();
        private bool _jobHadErrors;
        private bool _jobWasStarted;
        private bool _jobWasStopped;
        private bool _alreadyReachedCompletedState;

        internal bool JobHadErrors
        {
            get
            {
                lock (_jobStateLock)
                {
                    return _jobHadErrors;
                }
            }
        }

        internal void ReportJobFailure(IContainsErrorRecord exception)
        {
            TerminatingErrorTracker terminatingErrorTracker = TerminatingErrorTracker.GetTracker(this.JobContext.CmdletInvocationInfo);

            bool sessionWasAlreadyTerminated = false;
            bool isThisTerminatingError = false;
            Exception brokenSessionException = null;
            lock (_jobStateLock)
            {
                if (!_jobWasStopped)
                {
                    brokenSessionException = terminatingErrorTracker.GetExceptionIfBrokenSession(
                        this.JobContext.Session,
                        this.JobContext.CmdletInvocationContext.CmdletDefinitionContext.SkipTestConnection,
                        out sessionWasAlreadyTerminated);
                }
            }
            if (brokenSessionException != null)
            {
                string brokenSessionMessage = string.Format(
                    CultureInfo.InvariantCulture,
                    CmdletizationResources.CimJob_BrokenSession,
                    brokenSessionException.Message);
                exception = CimJobException.CreateWithFullControl(
                    this.JobContext,
                    brokenSessionMessage,
                    "CimJob_BrokenCimSession",
                    ErrorCategory.ResourceUnavailable,
                    brokenSessionException);
                isThisTerminatingError = true;
            }
            else
            {
                CimJobException cje = exception as CimJobException;
                if ((cje != null) && (cje.IsTerminatingError))
                {
                    terminatingErrorTracker.MarkSessionAsTerminated(this.JobContext.Session, out sessionWasAlreadyTerminated);
                    isThisTerminatingError = true;
                }
            }

            bool writeError = !sessionWasAlreadyTerminated;
            if (writeError)
            {
                lock (_jobStateLock)
                {
                    if (_jobWasStopped)
                    {
                        writeError = false;
                    }
                }
            }

            ErrorRecord errorRecord = exception.ErrorRecord;
            errorRecord.SetInvocationInfo(this.JobContext.CmdletInvocationInfo);
            errorRecord.PreserveInvocationInfoOnce = true;

            if (writeError)
            {
                lock (_jobStateLock)
                {
                    if (!_alreadyReachedCompletedState)
                    {
                        if (isThisTerminatingError)
                        {
                            this.Error.Add(errorRecord);
                            CmdletMethodInvoker<bool> methodInvoker = terminatingErrorTracker.GetErrorReportingDelegate(errorRecord);
                            this.Results.Add(new PSStreamObject(PSStreamObjectType.ShouldMethod, methodInvoker));
                        }
                        else
                        {
                            this.WriteError(errorRecord);
                        }
                    }
                }
            }

            this.SetCompletedJobState(JobState.Failed, errorRecord.Exception);
        }

        internal override void WriteWarning(string message)
        {
            message = this.JobContext.PrependComputerNameToMessage(message);
            base.WriteWarning(message);
        }

        internal override void WriteVerbose(string message)
        {
            message = this.JobContext.PrependComputerNameToMessage(message);
            base.WriteVerbose(message);
        }

        internal override void WriteDebug(string message)
        {
            message = this.JobContext.PrependComputerNameToMessage(message);
            base.WriteDebug(message);
        }

        internal void SetCompletedJobState(JobState state, Exception reason)
        {
            lock (_jobStateLock)
            {
                if (_alreadyReachedCompletedState)
                {
                    return;
                }

                _alreadyReachedCompletedState = true;

                if ((state == JobState.Failed) || (reason != null))
                {
                    _jobHadErrors = true;
                }

                if (_jobWasStopped)
                {
                    state = JobState.Stopped;
                }
                else if (_jobHadErrors)
                {
                    state = JobState.Failed;
                }
            }

            this.FinishProgressReporting();
            this.SetJobState(state, reason);
            this.CloseAllStreams();
            _cancellationTokenSource.Cancel();
        }

        #endregion

        #region Support for progress reporting

        private readonly ConcurrentDictionary<int, ProgressRecord> _activityIdToLastProgressRecord = new ConcurrentDictionary<int, ProgressRecord>();

        internal override void WriteProgress(ProgressRecord progressRecord)
        {
            progressRecord.Activity = this.JobContext.PrependComputerNameToMessage(progressRecord.Activity);

            _activityIdToLastProgressRecord.AddOrUpdate(
                progressRecord.ActivityId,
                progressRecord,
                (activityId, oldProgressRecord) => progressRecord);

            base.WriteProgress(progressRecord);
        }

        internal void FinishProgressReporting()
        {
            foreach (ProgressRecord lastProgressRecord in _activityIdToLastProgressRecord.Values)
            {
                if (lastProgressRecord.RecordType != ProgressRecordType.Completed)
                {
                    var newProgressRecord = new ProgressRecord(lastProgressRecord.ActivityId, lastProgressRecord.Activity, lastProgressRecord.StatusDescription);
                    newProgressRecord.RecordType = ProgressRecordType.Completed;
                    newProgressRecord.PercentComplete = 100;
                    newProgressRecord.SecondsRemaining = 0;
                    this.WriteProgress(newProgressRecord);
                }
            }
        }

        #endregion

        #region Handling extended semantics callbacks

        private void WriteProgressCallback(string activity, string currentOperation, string statusDescription, UInt32 percentageCompleted, UInt32 secondsRemaining)
        {
            if (string.IsNullOrEmpty(activity))
            {
                activity = this.GetDescription();
            }
            if (string.IsNullOrEmpty(statusDescription))
            {
                statusDescription = this.StatusMessage;
            }

            Int32 signedSecondsRemaining;
            if (secondsRemaining == UInt32.MaxValue)
            {
                signedSecondsRemaining = -1;
            }
            else if (secondsRemaining <= Int32.MaxValue)
            {
                signedSecondsRemaining = (Int32)secondsRemaining;
            }
            else
            {
                signedSecondsRemaining = Int32.MaxValue;
            }

            Int32 signedPercentageComplete;
            if (percentageCompleted == UInt32.MaxValue)
            {
                signedPercentageComplete = -1;
            }
            else if (percentageCompleted <= 100)
            {
                signedPercentageComplete = (Int32)percentageCompleted;
            }
            else
            {
                signedPercentageComplete = 100;
            }

            var progressRecord = new ProgressRecord(unchecked((int)(_myJobNumber % int.MaxValue)), activity, statusDescription)
            {
                CurrentOperation = currentOperation,
                PercentComplete = signedPercentageComplete,
                SecondsRemaining = signedSecondsRemaining,
                RecordType = ProgressRecordType.Processing,
            };

            this.ExceptionSafeWrapper(
                    delegate
                    {
                        this.WriteProgress(progressRecord);
                    });
        }

        private enum MessageChannel
        {
            Warning = 0,
            Verbose = 1,
            Debug = 2,
        }

        private void WriteMessageCallback(UInt32 channel, string message)
        {
            this.ExceptionSafeWrapper(
                    delegate
                    {
                        switch ((MessageChannel)channel)
                        {
                            case MessageChannel.Warning:
                                this.WriteWarning(message);
                                break;

                            case MessageChannel.Verbose:
                                this.WriteVerbose(message);
                                break;

                            case MessageChannel.Debug:
                                this.WriteDebug(message);
                                break;

                            default:
                                Dbg.Assert(false, "We shouldn't get messages in channels that we didn't register for");
                                break;
                        }
                    });
        }

        private CimResponseType BlockingWriteError(ErrorRecord errorRecord)
        {
            Exception exceptionThrownOnCmdletThread = null;
            this.ExceptionSafeWrapper(
                    delegate
                    {
                        this.WriteError(errorRecord, out exceptionThrownOnCmdletThread);
                    });

            return (exceptionThrownOnCmdletThread != null)
                       ? CimResponseType.NoToAll
                       : CimResponseType.Yes;
        }

        private CimResponseType WriteErrorCallback(CimInstance cimError)
        {
            lock (_jobStateLock)
            {
                _jobHadErrors = true;
            }

            var cimException = new CimException(cimError);
            var jobException = CimJobException.CreateFromCimException(this.GetDescription(), this.JobContext, cimException);
            var errorRecord = jobException.ErrorRecord;

            switch (this.JobContext.ErrorActionPreference)
            {
                case ActionPreference.Stop:
                case ActionPreference.Inquire:
                    return this.BlockingWriteError(errorRecord);

                default:
                    this.WriteError(errorRecord);
                    return CimResponseType.Yes;
            }
        }

        private bool _userWasPromptedForContinuationOfProcessing;
        private bool _userRespondedYesToAtLeastOneShouldProcess;

        internal bool DidUserSuppressTheOperation
        {
            get
            {
                bool didUserSuppressTheOperation = _userWasPromptedForContinuationOfProcessing && (!_userRespondedYesToAtLeastOneShouldProcess);
                return didUserSuppressTheOperation;
            }
        }

        internal CimResponseType ShouldProcess(string target, string action)
        {
            string verboseDescription = StringUtil.Format(CommandBaseStrings.ShouldProcessMessage,
                action,
                target,
                null);

            return ShouldProcess(verboseDescription, null, null);
        }

        internal CimResponseType ShouldProcess(
            string verboseDescription,
            string verboseWarning,
            string caption)
        {
            if (this.JobContext.IsRunningInBackground)
            {
                return CimResponseType.YesToAll;
            }

            if (this.JobContext.ShouldProcessOptimization == MshCommandRuntime.ShouldProcessPossibleOptimization.AutoNo_CanCallShouldProcessAsynchronously)
            {
                this.NonblockingShouldProcess(verboseDescription, verboseWarning, caption);
                return CimResponseType.No;
            }

            if (this.JobContext.ShouldProcessOptimization == MshCommandRuntime.ShouldProcessPossibleOptimization.AutoYes_CanCallShouldProcessAsynchronously)
            {
                this.NonblockingShouldProcess(verboseDescription, verboseWarning, caption);
                return CimResponseType.Yes;
            }

            Dbg.Assert(
                (this.JobContext.ShouldProcessOptimization != MshCommandRuntime.ShouldProcessPossibleOptimization.AutoYes_CanSkipShouldProcessCall) ||
                (this.JobContext.CmdletInvocationContext.CmdletDefinitionContext.ClientSideShouldProcess),
                "MI layer should not call us when AutoYes_CanSkipShouldProcessCall optimization is in effect");
            Exception exceptionThrownOnCmdletThread;
            ShouldProcessReason shouldProcessReason;
            bool shouldProcessResponse = this.ShouldProcess(verboseDescription, verboseWarning, caption, out shouldProcessReason, out exceptionThrownOnCmdletThread);
            if (exceptionThrownOnCmdletThread != null)
            {
                return CimResponseType.NoToAll;
            }
            else if (shouldProcessResponse)
            {
                return CimResponseType.Yes;
            }
            else
            {
                return CimResponseType.No;
            }
        }

        private CimResponseType PromptUserCallback(string message, CimPromptType promptType)
        {
            message = this.JobContext.PrependComputerNameToMessage(message);

            Exception exceptionThrownOnCmdletThread = null;
            CimResponseType result = CimResponseType.No;

            _userWasPromptedForContinuationOfProcessing = true;
            switch (promptType)
            {
                case CimPromptType.Critical:
                    this.ExceptionSafeWrapper(
                            delegate
                            {
                                if (this.ShouldContinue(message, null, out exceptionThrownOnCmdletThread))
                                {
                                    result = CimResponseType.Yes;
                                }
                                else
                                {
                                    result = CimResponseType.No;
                                }
                            });
                    break;

                case CimPromptType.Normal:
                    this.ExceptionSafeWrapper(
                            delegate
                            {
                                result = this.ShouldProcess(message, null, null);
                            });
                    break;

                default:
                    Dbg.Assert(false, "Unrecognized CimPromptType");
                    break;
            }

            if (exceptionThrownOnCmdletThread != null)
            {
                result = CimResponseType.NoToAll;
            }

            if ((result == CimResponseType.Yes) || (result == CimResponseType.YesToAll))
            {
                _userRespondedYesToAtLeastOneShouldProcess = true;
            }
            return result;
        }

        #endregion

        internal static bool IsShowComputerNameMarkerPresent(CimInstance cimInstance)
        {
            PSObject pso = PSObject.AsPSObject(cimInstance);
            PSPropertyInfo psShowComputerNameProperty = pso.InstanceMembers[RemotingConstants.ShowComputerNameNoteProperty] as PSPropertyInfo;
            if (psShowComputerNameProperty == null)
            {
                return false;
            }
            return true.Equals(psShowComputerNameProperty.Value);
        }

        internal static void AddShowComputerNameMarker(PSObject pso)
        {
            PSPropertyInfo psShowComputerNameProperty = pso.InstanceMembers[RemotingConstants.ShowComputerNameNoteProperty] as PSPropertyInfo;
            if (psShowComputerNameProperty != null)
            {
                psShowComputerNameProperty.Value = true;
            }
            else
            {
                psShowComputerNameProperty = new PSNoteProperty(RemotingConstants.ShowComputerNameNoteProperty, true);
                pso.InstanceMembers.Add(psShowComputerNameProperty);
            }
        }

        internal override void WriteObject(object outputObject)
        {
            CimInstance cimInstance = null;
            PSObject pso = null;
            if (outputObject is PSObject)
            {
                pso = PSObject.AsPSObject(outputObject);
                cimInstance = pso.BaseObject as CimInstance;
            }
            else
            {
                cimInstance = outputObject as CimInstance;
            }
            if (cimInstance != null)
            {
                CimCmdletAdapter.AssociateSessionOfOriginWithInstance(cimInstance, this.JobContext.Session);
                CimCustomOptionsDictionary.AssociateCimInstanceWithCustomOptions(cimInstance, this.GetJobSpecificCustomOptions());
            }
            if (this.JobContext.ShowComputerName)
            {
                if (pso == null)
                {
                    pso = PSObject.AsPSObject(outputObject);
                }
                AddShowComputerNameMarker(pso);
                if (cimInstance == null)
                {
                    pso.Properties.Add(new PSNoteProperty(RemotingConstants.ComputerNameNoteProperty, this.JobContext.Session.ComputerName));
                }
            }

            base.WriteObject(outputObject);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                bool isCompleted;
                lock (_jobStateLock)
                {
                    isCompleted = _alreadyReachedCompletedState;
                }
                if (!isCompleted)
                {
                    this.StopJob();
                    this.Finished.WaitOne();
                }
                _cimSensitiveValueConverter.Dispose();
            }
        }
    }
}


text:
---
layout: default
---

  {% if page.banner_image %}

  {% endif %}

  {% if page.banner_video %}

      {{ page.banner_video }}

  {% endif %}

{{ page.title }}

    {% if (page.categories.size > 0 %}

      {{ page.categories | array_to_sentence_string }}
       |
    {% endif %}

    {{ page.date | date: "%b %-d, %Y" }}{% if page.author %} • {{ page.author }}{% endif %}{% if page.meta %} • {{ page.meta }}{% endif %}

    {{ content }}

  {% if site.related_posts %}

Related Posts

        {% for post in site.related_posts limit:3 %}

                {{ post.title }}
                {{ post.date | date_to_string }}

        {% endfor %}

  {% endif %}

    {% if site.theme.show_author_info %}
      {% include author.html %}
    {% endif %}

    {% if site.theme.show_share_buttons %}
      {% include share-buttons.html %}
    {% endif %}

Please enable JavaScript to view the comments powered by Disqus.

redpajama_set_name: RedPajamaGithub


text:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <artifactId>local-console</artifactId>
    <packaging>jar</packaging>
    <name>Local Console</name>
    <description>Run local commands on your os, in this simple</description>
    <parent>
        <groupId>dk.deck.remote-console</groupId>
        <artifactId>master</artifactId>
        <version>1.1.4-SNAPSHOT</version>
        <relativePath>../..</relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>console</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

</project>


text:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Chapter 3: Resultados
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Finalizada la etapa de desarrollo del Trabajo de Fin de Máster, se procede a describir la herramienta implementada.

La herramienta se ha denominado \verb1ghshell1, abreviatura de 'GitHub Shell'. Se ha publicado en NPM\cite{URL:NPM} para su fácil distribución e instalación:

\begin{figure}[H]
\begin{center}
\includegraphics[width=0.8\textwidth]{images/npm1}
\caption{Página del gestor de paquetes NPM}
\label{fig:npm}
\end{center}
\end{figure}

Las funcionalidades implementadas en \verb|ghshell|, se describen a continuación.

%---------------------------------------------------------------------------------
\section{Funcionalidades requeridas}
\label{3:sec:1}

%------------------------------------------------------------------------------------------------------------
\subsection{Autenticación con GitHub}
\label{subsec:3.1.1}

    Una vez que el usuario se autentifica con GitHub, se genera un token personal, que se usa posteriormente para acceder a la API de Github. Este token se almacena cifrado en el equipo del usuario, por lo que las siguientes ocasiones que utilice la herramienta no hará falta que vuelva a iniciar sesión:

        \begin{figure}[H]
		\begin{center}
		\includegraphics[width=0.7\textwidth]{images/ghshell1}
		\caption{Login de usuario}
		\label{fig:ghshell1}
		\end{center}
		\end{figure}

		\begin{figure}[H]
		\begin{center}
		\includegraphics[width=0.6\textwidth]{images/ghshell2-1}
		\caption{Usuario autenticado}
		\label{fig:ghshell2-1}
		\end{center}
		\end{figure}

		\begin{figure}[H]
		\begin{center}
		\includegraphics[width=1\textwidth]{images/ghshell2-3}
		\caption{Token personal en GitHub}
		\label{fig:ghshell2-3}
		\end{center}
		\end{figure}

		\begin{figure}[H]
		\begin{center}
		\includegraphics[width=0.6\textwidth]{images/ghshell2-4}
		\caption{Login automático una vez generado el token}
		\label{fig:ghshell2-4}
		\end{center}
		\end{figure}

	Si el usuario cierra sesión en la herramienta, se eliminará el token en GitHub y en el equipo:

		\begin{figure}[H]
		\begin{center}
		\includegraphics[width=0.6\textwidth]{images/ghshell2-2}
		\caption{Logout de usuario}
		\label{fig:ghshell2-2}
		\end{center}
		\end{figure}

%------------------------------------------------------------------------------------------------------------
\subsection{Listar organizaciones, asignaciones y repositorios de GitHub del usuario}
\label{subsec:3.1.2}

    Con el comando \verb'orgs -l', se puede listar las organizaciones del usuario y usando \verb'repos -l', se listarán los repositorios del usuario. También se puede acceder 'virtualmente' a las organizaciones y listar los repositorios que contiene, así como las asignaciones.
\bigskip

    NOTA: se puede consultar toda la información referente a los comandos del programa en el Apéndice 2.

        \begin{figure}[H]
		\begin{center}
		\includegraphics[width=0.9\textwidth]{images/ghshell3}
		\caption{Lista de organizaciones del usuario}
		\label{fig:ghshell3}
		\end{center}
		\end{figure}

		\begin{figure}[H]
		\begin{center}
		\includegraphics[width=0.9\textwidth]{images/ghshell4}
		\caption{Lista de repositorios de una organización}
		\label{fig:ghshell4}
		\end{center}
		\end{figure}

		\begin{figure}[H]
		\begin{center}
		\includegraphics[width=0.9\textwidth]{images/ghshell5}
		\caption{Asignaciones dentro de otra organización}
		\label{fig:ghshell5}
		\end{center}
		\end{figure}
    Las asignaciones son un conjunto de repositorios que corresponden a una tarea asignada por los profesores a los alumnos.

	También es posible acceder 'virtualmente' a los repositorios y realizar acciones sobre ellos:

		\begin{figure}[H]
		\begin{center}
		\includegraphics[width=1\textwidth]{images/ghshell5-1}
		\caption{Acceso a un repositorio de una organización}
		\label{fig:ghshell5-1}
		\end{center}
		\end{figure}

%------------------------------------------------------------------------------------------------------------
\subsection{Automatizar la descarga de repositorios}
\label{subsec:3.1.3}

    En función del contexto dónde nos encontremos dentro de la herramienta, podremos:
    \begin{itemize}
    	\item Clonar el repositorio en el que nos encontremos.
    	\item Clonar un repositorio determinado.
	    \item Clonar todos los repositorios que coincidan con una determinada expresión regular.
	    \item Clonar todos los repositorios de una asignación que coincidan con una determinada expresión
    \end{itemize}

    El clonado se realiza de manera asíncrona, por lo que podemos seguir trabajando mientras se clona(n) el/los repositorio(s). Se puede observar el estado de la clonación revisando el fichero de log que se genera cuyo nombre sigue el formato: \verb|nombre-repositorio -clone.log|.

    	\begin{figure}[H]
		\begin{center}
		\includegraphics[width=1\textwidth]{images/ghshell6-3}
		\caption{Clonado del repositorio donde nos encontramos}
		\label{fig:ghshell6-3}
		\end{center}
		\end{figure}

    Si clonamos repositorios que pertenecen a una organización, se creará una carpeta con el nombre de la organización y en su interior se guardarán los repositorios clonados.

	Además, si clonamos repositorios que pertenecen a una asignación, también se creará una carpeta con el nombre de la asignación que los contendrá.

        \begin{figure}[H]
		\begin{center}
		\includegraphics[width=1\textwidth]{images/ghshell6-1}
		\caption{Clonado de asignaciones que coinciden con una expresión regular}
		\label{fig:ghshell6-1}
		\end{center}
		\end{figure}

		\begin{figure}[H]
		\begin{center}
		\includegraphics[width=0.7\textwidth]{images/ghshell6-2}
		\caption{Resultado del clonado}
		\label{fig:ghshell6-2}
		\end{center}
		\end{figure}

%------------------------------------------------------------------------------------------------------------
\subsection{Automatizar la ejecución de scripts en los repositorios}
\label{subsec:3.1.3}

    En función del contexto donde nos encontremos dentro de la herramienta, podremos:
    \begin{itemize}
    	\item Ejecutar un script en el repositorio en el que nos encontremos.
    	\item Ejecutar un script en un determinado repositorio.
	    \item Ejecutar un script en todos los repositorios que coincidan con una determinada expresión regular.
	    \item Ejecutar un script en todos los repositorios de una asignación coincidan con una determinada expresión regular.
    \end{itemize}

	La ruta del fichero del script puede ser absoluta o relativa. Estos scripts puede ser de cualquier tipo: TDD, creación de entorno, evaluación de código...
\bigskip

	La ejecución de cada script se ejecuta en un proceso hijo independiente pero, a diferencia del clonado, el script se ejecuta línea a línea de manera síncrona. Se puede observar el estado de la ejecución del script y los resultados revisando el fichero de log que se genera: \textless nombre-repositorio \textgreater - \textless nombre-script \textgreater .log

    	\begin{figure}[H]
		\begin{center}
		\includegraphics[width=1\textwidth]{images/ghshell7-3}
		\caption{Ejecución del script 'install.sh' en el repositorio actual}
		\label{fig:ghshell7-3}
		\end{center}
		\end{figure}

        \begin{figure}[H]
		\begin{center}
		\includegraphics[width=1\textwidth]{images/ghshell7-1}
		\caption{Ejecución del script 'install.sh' en asignaciones que coinciden con una expresión regular}
		\label{fig:ghshell7-1}
		\end{center}
		\end{figure}

		\begin{figure}[H]
		\begin{center}
		\includegraphics[width=0.7\textwidth]{images/ghshell7-2}
		\caption{Resultado de la ejecución del script 'install.sh'}
		\label{fig:ghshell7-2}
		\end{center}
		\end{figure}

%------------------------------------------------------------------------------------------------------------
\subsection{Recopilar la información obtenida de la automatización de tareas}
\label{subsec:3.1.4}

    Una vez ejecutados los scripts necesarios para evaluar un determinado repositorio, es posible generar un GitBook con el resultado de la ejecución de los mismos. Este libro se genera en formato PDF y en HTML.
\bigskip

    En función del contexto dónde nos encontremos dentro de la herramienta, podremos:
    \begin{itemize}
    	\item Crear un GitBook en el repositorio en el que nos encontremos.
    	\item Crear un GitBook en un determinado repositorio.
	    \item Crear un GitBook en todos los repositorios que coincidan con una determinada expresión regular.
	    \item Crear un GitBook en todos los repositorios de una asignación coincidan con una determinada expresión regular.
    \end{itemize}

        \begin{figure}[H]
		\begin{center}
		\includegraphics[width=1\textwidth]{images/ghshell8-3}
		\caption{Creación del Gitbook en el repositorio actual}
		\label{fig:ghshell8-3}
		\end{center}
		\end{figure}

        \begin{figure}[H]
		\begin{center}
		\includegraphics[width=1\textwidth]{images/ghshell8-1}
		\caption{Creación del Gitbook en asignaciones que coinciden con una expresión regular}
		\label{fig:ghshell8-1}
		\end{center}
		\end{figure}

		\begin{figure}[H]
		\begin{center}
		\includegraphics[width=0.7\textwidth]{images/ghshell8-2}
		\caption{Resultado de la creación del Gitbook}
		\label{fig:ghshell8-2}
		\end{center}
		\end{figure}

\newpage
%---------------------------------------------------------------------------------
\section{Funcionalidades extra}
\label{3:sec:2}

Además de las funcionales solicitadas en este Trabajo de Fin de Máster, se han añadido una serie de funcionalidades extra que, a pesar de no ser requeridas, brindan al usuario de una mejor experiencia de uso del programa:

\begin{itemize}
  \item Autocompletado de los comandos disponibles en función del contexto donde nos encontremos (nivel principal, organización o repositorio).
	\item Opción de ayuda que muestra la descripción de los comandos y cómo se utilizan. Esta ayuda varía dependiendo del contexto donde nos encontremos.
	\item Opción de visualizar el directorio de trabajo donde se ha ejecutado el programa. Útil para determinar rutas relativas de los scripts que se desean ejecutar.
	\item Opción para conocer el propietario de cada repositorio. En el caso de que el repositorio pertenezca a una organización, mostrará los contribuyentes de ese repositorio.
\end{itemize}

NOTA: se puede consultar toda la información referente a los comandos del programa en el Apéndice 2.

%---------------------------------------------------------------------------------
\section{Problemas encontrados y soluciones}
\label{3:sec:3}

A continuación se detallan los problemas encontrados durante la implementación de la herramienta y las soluciones encontradas para los mismos:

%---------------------------------------------------------------------------------
\subsection{Asincronía}
\label{subsec:3.3.1}

Una de las características más importantes del lenguaje JavaScript es la asincronía. Usa un modelo de operaciones de entrada/salida sin bloqueo y orientado a eventos, que lo hace ligero y eficiente. Sin embargo, algunas acciones que debía realizar esta herramienta debían de ser síncronas. Ejemplos son el login del usuario y ejecución de scripts.
\bigskip

{\normalsize {\bfseries Solución}}
\bigskip

La solución a este comportamiento pasó por realizar un amplio estudio de la documentación para usar mecanismos que permitieran bloquear la ejecución de la herramienta en las partes que deseábamos. Los mecanismos usados han sido:

\begin{itemize}
	\item Funciones síncronas del propio lenguaje.
	\item Promesas
	\item Métodos async/await
	\item Librerías con métodos implementados de manera síncrona.
\end{itemize}

%---------------------------------------------------------------------------------
\subsection{Autocompletado de comandos}
\label{subsec:3.3.2}

Para el manejo de los flujos de lectura y escritura de la herramienta, se ha utilizado la interfaz nativa de Node.js (Readline). Esta interfaz provee de una función de autocompletado para el texto que escribe el usuario.

Sin embargo, sólo funciona con la primera palabra (comando) que escribe. Tras investigar al respecto y buscar posibles librerías alternativas, no existía ninguna solución que corrigiera este comportamiento.
\bigskip

{\normalsize {\bfseries Solución}}
\bigskip

Realizando numerosas pruebas, se halló una manera propia de conseguir completar más de un comando en la misma línea. Cuando realice los test de aceptación pertinentes requeridos por la comunidad de Node, solicitaré un Pull Request a su repositorio con esta mejora.

%---------------------------------------------------------------------------------
\section{Perfil del usuario de ghshell}
\label{3:sec:4}

El uso de \verb|ghshell| está especialmente dirigido a un determinado grupo de profesores: nos referimos al perfil de un profesor, principalmente docente en alguna rama de Ingeniería, con conocimientos avanzados en programación y en herramientas de control de versiones.

No obstante, ya que la curva de aprendizaje de \verb|ghshell| no es excesiva y dado que el uso de las herramientas de control de versiones no se limita exclusivamente a repositorios de código fuente, se puede extender su uso para el resto de profesorado y usuarios con otros roles. Basta con tener claras unas nociones básicas de informática, junto con la lectura y asimilación previa de la documentación de la herramienta.


text:
<?php

namespace Domain\Model;

class Post
{
    const EXPIRE_EDIT_TIME = 120;//seconds

    private $id;
    private $body;
    private $createdAt;

    public function __construct(
        PostId $anId,
        Body $aBody,
        \DateTime $createdAt = null
    ) {
        $this->id = $anId;
        $this->body = $aBody;
        $this->createdAt = $createdAt ?: new \DateTime();
    }

    public function editBody(Body $aNewBody)
    {
        if ($this->editExpired()) {
            throw new \RuntimeException('Edit time expired');
        }

        $this->body = $aNewBody;
    }

    private function editExpired()
    {
        $expiringTime = $this->createdAt->getTimestamp() + self::EXPIRE_EDIT_TIME;

        return $expiringTime < time();
    }

    public function id()
    {
        return $this->id;
    }

    public function body()
    {
        return $this->body;
    }

    public function createdAt()
    {
        return $this->createdAt;
    }
}


text:
"""
./opttrack/lib/optspread_factory.py

Copyright (c) 2016 Marshall Farrier
license http://opensource.org/licenses/MIT

Factory for creating spreads from assorted inputs,
particularly from records pulled from MongoDB in dictionary
form.
"""

import pytz

from ..stockopt import StockOptFactory
from .optspread import OptSpread

class OptSpreadFactory(object):

    def __init__(self, tz=None):
        self.tz = tz if tz else pytz.timezone('US/Eastern')
        self.opt_factory = StockOptFactory(tz)

    def make(self, record):
        # make a spread object from a mongo record
        spread = OptSpread(**record)
        if record['Spread_Type'] == 'dgb':
            self._update_dgb(spread, record)
        return spread

    def _update_dgb(self, spread, record):
        for item in record['Long']:
            spread.buy_one(self.opt_factory.make(**item))
        for item in record['Short']:
            spread.sell_one(self.opt_factory.make(**item))


text:
const LANGUAGES = ['A', 'B', 'C']
const FILES = ['./A.json', './B.json', './C.json']

exports.load = function(lang) {
  const idx = LANGUAGES.indexOf(lang)
  if (idx === -1) {
    throw new Error(`lang argument must be one of ${LANGUAGES.join(', ')}.`)
  }
  const db = require(FILES[idx])
  return {
    getVariants(word) {
      return db[word] || null
    },
    getVariant(word, lang) {
      const variants = this.getVariants(word)
      if (!variants) {
        return null
      }
      if (lang in variants) {
        return variants[lang]
      } else {
        return null
      }
    }
  }
}


text:
<?php
namespace Utils;

use JMS\Serializer\SerializerBuilder;

/**
 * @author Diefferson SAntos
*/
class ResponseApi
{
    /**
     * @var Integer - API response http code
     *
    */
    private $code;

	/**
	 * @var String - API response message
	 *
	*/
	private $message;

    /**
     * @var Integer - API respnse count
     *
    */
    private $count;

    /**
     * @var Integer - API respnse next
     *
    */
    private $next;

     /**
     * @var Integer - API respnse previous
     *
    */
    private $previous;

	/**
	 * @var Object - API response content
	 *
	*/
	private $content;

	public function __construct($content = null, $message = "OK" , $code = 200){
        $this->code       = $code;
		$this->message 	  = $message;
		$this->content 	  = $content;
	}

    public function getResponse(){

        $format = 'json';

        $serializer = SerializerBuilder::create()->build();

        $response = $serializer->serialize($this, $format);

        return $response;
    }

    /**
     * @return Integer - API response http code
     */
    public function getCode()
    {
        return $this->code;
    }

    /**
     * @param Integer - API response http code $code
     *
     * @return self
     */
    public function setCode($code)
    {
        $this->code = $code;

        return $this;
    }

    /**
     * @return String - API response message
     */
    public function getMessage()
    {
        return $this->message;
    }

    /**
     * @param String - API response message $message
     *
     * @return self
     */
    public function setMessage($message)
    {
        $this->message = $message;

        return $this;
    }

    /**
     * @return Integer - API respnse count
     */
    public function getCount()
    {
        return $this->count;
    }

    /**
     * @param Integer - API respnse count $count
     *
     * @return self
     */
    public function setCount($count)
    {
        $this->count = $count;

        return $this;
    }

    /**
     * @return Integer - API respnse next
     */
    public function getNext()
    {
        return $this->next;
    }

    /**
     * @param Integer - API respnse next $next
     *
     * @return self
     */
    public function setNext($next)
    {
        $this->next = $next;

        return $this;
    }

    /**
     * @return Integer - API respnse previous
     */
    public function getPrevious()
    {
        return $this->previous;
    }

    /**
     * @param Integer - API respnse previous $previous
     *
     * @return self
     */
    public function setPrevious($previous)
    {
        $this->previous = $previous;

        return $this;
    }

    /**
     * @return Object - API response content
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * @param Object - API response content $content
     *
     * @return self
     */
    public function setContent($content)
    {
        $this->content = $content;

        return $this;
    }
}


text:
Emissary.defineController('org.jpokemon.driver.Keyboard', {
  view: false,
  canvasIsFocused: false,

  constructor: function() {
    this.setKeys({
      87: 'up',
      65: 'left',
      83: 'down',
      68: 'right',
      69: 'interact'
    });

    $(document).mouseup(this.onClick);
    $(document).keydown(this.onKeydown);
    $(document).keyup(this.onKeyup);

    window.JPokemon = window.JPokemon || {};
    JPokemon.input = this;
  },

  setKeys: function(keys) {
    this.keys = {};
    for (var key in keys) {
      this.keys[key] = keys[key];
      // set up backwards links, just because
      this.keys[keys[key]] = key;
    }
  },

  onClick: function(e) {
    if (JPokemon.canvas == e.target) {
      this.canvasIsFocused = true;
    }
    else {
      this.canvasIsFocused = false;
    }
  },

  onKeydown: function(e) {
    var keyCode = e.keyCode;

    if (this.value || !this.canvasIsFocused || !this.keys[keyCode]) {
      return;
    }

    this.value = this.keys[e.keyCode];
  },

  onKeyup: function(e) {
    var keyCode = e.keyCode;

    if (!this.value || !this.canvasIsFocused || !this.keys[keyCode]) {
      return;
    }

    if (this.keys[keyCode] === this.value) {
      this.value = null;
    }
  }
});


text:
const express = require('express');
const router = express.Router();
const db = require('../db/connection');

router.get('/', (req, res, next) => {
  const renderObject = {};
  renderObject.title = 'Donuts';
  db.any('SELECT * FROM donuts')
  .then((results) => {
    renderObject.donuts = results;
    res.render('donuts.html', renderObject);
  })
  .catch((error) => {
    next(error);
  });
});

router.post('/', (req, res, next) => {
  const newDonut = {
    name: req.body.donut_name,
    topping: req.body.topping,
    price: req.body.price
  };
  db.any(`INSERT INTO donuts (name, topping, price) VALUES('${newDonut.name}', '${newDonut.topping}', '${newDonut.price}')`)
  .then((result) => {
    res.send('You added a donut!');
  })
  .catch((error) => {
    next(error);
  });
});

router.put('/:id', (req, res, next) => {
      const donutID = parseInt(req.params.id);
      const updateDonut = {
        name: req.body.name,
        topping: req.body.topping,
        price: req.body.price
      };

      db.tx(t=> {
          return t.batch([
              t.any(`UPDATE donuts SET name = '${updateDonut.name}' WHERE id = ${donutID}`, [true]),
              t.any(`UPDATE donuts SET topping = '${updateDonut.topping}' WHERE id = ${donutID}`, [true]),
              t.any(`UPDATE donuts SET price = '${updateDonut.price}' WHERE id = ${donutID}`, [true])
          ]);
        })
      .then(result=> {
        if (!result.length) {
          res.status(404).send({
            status: 'error',
            message: 'That donut doesn\'t exist'
          });
        } else {
          res.send('You updated a donut!');
        }
      })
      .catch((error) => {
        next(error);
      });
    });

router.delete('/:id', function (req, res, next) {
  const donutID = parseInt(req.params.id);
  db.tx(t=> {
      return t.batch([
          t.any(`UPDATE employees SET favorite_donut = NULL WHERE favorite_donut = ${donutID}`),
          t.any(`DELETE FROM shops_donuts WHERE donut_id = ${donutID}`)
      ]);
    })
  .then(result=> {
    if (!result.length) {
      res.status(404).send({
        status: 'error',
        message: 'That donut doesn\'t exist'
      });
    } else {
      db.any(`DELETE FROM donuts WHERE id = ${donutID}`)
       .then(function (data) {
        console.log(data);
        res.send('You Deleted a donut!');
      })
       .catch(function (error) {
        next(error);
      });
    }
  })
  .catch((error) => {
    next(error);
  });

});

module.exports = router;


text:
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later
 * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
 */
package org.hibernate.orm.type.descriptor.java.internal;

import java.io.Reader;
import java.io.StringReader;
import java.sql.Clob;
import java.util.Arrays;

import org.hibernate.engine.jdbc.CharacterStream;
import org.hibernate.engine.jdbc.internal.CharacterStreamImpl;

import org.hibernate.orm.type.descriptor.java.spi.AbstractBasicTypeDescriptor;
import org.hibernate.orm.type.descriptor.java.spi.ArrayMutabilityPlan;
import org.hibernate.orm.type.descriptor.spi.JdbcRecommendedSqlTypeMappingContext;
import org.hibernate.orm.type.descriptor.spi.WrapperOptions;
import org.hibernate.orm.type.descriptor.sql.spi.SqlTypeDescriptor;

/**
 * Descriptor for {@code char[]} handling.
 *
 * @author Steve Ebersole
 */
public class PrimitiveCharacterArrayJavaDescriptor extends AbstractBasicTypeDescriptor<char[]> {
	public static final PrimitiveCharacterArrayJavaDescriptor INSTANCE = new PrimitiveCharacterArrayJavaDescriptor();

	@SuppressWarnings({ "unchecked" })
	protected PrimitiveCharacterArrayJavaDescriptor() {
		super( char[].class, ArrayMutabilityPlan.INSTANCE );
	}

	public String toString(char[] value) {
		return new String( value );
	}

	public char[] fromString(String string) {
		return string.toCharArray();
	}

	@Override
	public boolean areEqual(char[] one, char[] another) {
		return one == another
				|| ( one != null && another != null && Arrays.equals( one, another ) );
	}

	@Override
	public SqlTypeDescriptor getJdbcRecommendedSqlType(JdbcRecommendedSqlTypeMappingContext context) {
		return CharacterArrayJavaDescriptor.INSTANCE.getJdbcRecommendedSqlType( context );
	}

	@Override
	public int extractHashCode(char[] chars) {
		int hashCode = 1;
		for ( char aChar : chars ) {
			hashCode = 31 * hashCode + aChar;
		}
		return hashCode;
	}

	@SuppressWarnings({ "unchecked" })
	public <X> X unwrap(char[] value, Class<X> type, WrapperOptions options) {
		if ( value == null ) {
			return null;
		}
		if ( char[].class.isAssignableFrom( type ) ) {
			return (X) value;
		}
		if ( String.class.isAssignableFrom( type ) ) {
			return (X) new String( value );
		}
		if ( Clob.class.isAssignableFrom( type ) ) {
			return (X) options.getLobCreator().createClob( new String( value ) );
		}
		if ( Reader.class.isAssignableFrom( type ) ) {
			return (X) new StringReader( new String( value ) );
		}
		if ( CharacterStream.class.isAssignableFrom( type ) ) {
			return (X) new CharacterStreamImpl( new String( value ) );
		}
		throw unknownUnwrap( type );
	}

	public <X> char[] wrap(X value, WrapperOptions options) {
		if ( value == null ) {
			return null;
		}
		if ( char[].class.isInstance( value ) ) {
			return (char[]) value;
		}
		if ( String.class.isInstance( value ) ) {
			return ( (String) value ).toCharArray();
		}
		if ( Clob.class.isInstance( value ) ) {
			return DataHelper.extractString( ( (Clob) value ) ).toCharArray();
		}
		if ( Reader.class.isInstance( value ) ) {
			return DataHelper.extractString( ( (Reader) value ) ).toCharArray();
		}
		throw unknownWrap( value.getClass() );
	}
}


text:
package com.github.skykai.view;

import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;

/**
 * Created by sky on 17/3/1.
 */
public class CoordinatorRecyclerView extends RecyclerView {
    private int dragDistanceY;
    private boolean scrollTop;
    private float downPositionY;
    private CoordinatorListener coordinatorListener;

    public CoordinatorRecyclerView(Context context) {
        super(context);
    }

    public CoordinatorRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public CoordinatorRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (null == coordinatorListener) {
            return super.onTouchEvent(ev);
        }
        final int action = ev.getAction();
        final int y = (int) ev.getRawY();
        final int x = (int) ev.getRawX();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                downPositionY = ev.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                int deltaY = (int) (downPositionY - y);
                boolean deal;
                if (isScrollTop(ev)) {
                    deal = coordinatorListener.onCoordinateScroll(x, y, 0, deltaY + Math.abs(dragDistanceY), true);
                } else {
                    deal = coordinatorListener.onCoordinateScroll(x, y, 0, deltaY, isScrollTop(ev));
                }
                if (deal) {
                    return true;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                scrollTop = false;
                if (coordinatorListener.isBeingDragged()) {
                    coordinatorListener.onSwitch();
                    return true;
                }
                break;
        }
        return super.onTouchEvent(ev);
    }

    private boolean isScrollTop(MotionEvent ev) {
        LayoutManager layoutManager = getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
            if (gridLayoutManager.findFirstVisibleItemPosition() == 0 &&
                    gridLayoutManager.findViewByPosition(0).getTop() == gridLayoutManager.getTopDecorationHeight(gridLayoutManager.findViewByPosition(0))) {
                if (!scrollTop) {
                    dragDistanceY = (int) (downPositionY - ev.getRawY());
                    scrollTop = true;
                }
                return true;
            }
        }
        return false;
    }

    public void setCoordinatorListener(CoordinatorListener listener) {
        this.coordinatorListener = listener;
    }
}


text:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>

#include <hiredis/hiredis.h>

#include "pressure.h"

#define min(a,b) \
   ({ __typeof__ (a) _a = (a); \
       __typeof__ (b) _b = (b); \
     _a < _b ? _a : _b; })

#ifdef DEBUG
    #define dbprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
    #define dbprintf(fmt, ...)
#endif

char *pressure_key(const char *prefix, const char *name, const char *key) {
    if (key == NULL || key[0] == 0) {
        unsigned int len = strlen(prefix) + 1 + strlen(name);
        char *final_key = malloc(len + 1);
        snprintf(final_key, len + 1, "%s:%s", prefix, name);
        return final_key;
    } else {
        unsigned int len = strlen(prefix) + 1 + strlen(name) + 1 + strlen(key);
        char *final_key = malloc(len + 1);
        snprintf(final_key, len + 1, "%s:%s:%s", prefix, name, key);
        return final_key;
    }
}

char *pressure_uid() {
    char *buf = malloc(1024);

    struct addrinfo hints, *info, *p;
    int gai_result;

    char hostname[1024];
    hostname[1023] = 0;
    gethostname(hostname, 1023);

    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; /*either IPV4 or IPV6*/
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_CANONNAME;

    if ((gai_result = getaddrinfo(hostname, "http", &hints, &info)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai_result));
        exit(1);
    }

    for(p = info; p != NULL; p = p->ai_next) {
        snprintf(buf, 1024, "%s_pid%d", p->ai_canonname, (int) getpid());
        break;
    }

    freeaddrinfo(info);

    return buf;
}

pressureQueue *pressure_connect(redisContext *context, const char *prefix, const char *name) {
    if (context == NULL || context->err) {
        return NULL;
    }

    pressureQueue r = {
        .context = context,
        .name = malloc(strlen(name) + 1),
        .exists = false,
        .connected = false,
        .bound = BOUND_NOT_SET,
        .client_uid = pressure_uid(),

        .keys = {
            .queue = pressure_key(prefix, name, NULL),
            .bound = pressure_key(prefix, name, "bound"),

            .producer = pressure_key(prefix, name, "producer"),
            .consumer = pressure_key(prefix, name, "consumer"),

            .producer_free = pressure_key(prefix, name, "producer_free"),
            .consumer_free = pressure_key(prefix, name, "consumer_free"),

            .stats_produced_messages = pressure_key(prefix, name, "stats:produced_messages"),
            .stats_produced_bytes = pressure_key(prefix, name, "stats:produced_bytes"),

            .stats_consumed_messages = pressure_key(prefix, name, "stats:consumed_messages"),
            .stats_consumed_bytes = pressure_key(prefix, name, "stats:consumed_bytes"),

            .not_full = pressure_key(prefix, name, "not_full"),
            .closed = pressure_key(prefix, name, "closed"),
        }
    };

    strncpy(r.name, name, strlen(name) + 1);

    //  Make sure the server is available.
    redisReply *reply = redisCommand(context, "PING");
    r.connected = !strcmp(reply->str, "PONG");
    freeReplyObject(reply);

    //  Check if the queue already exists.
    reply = redisCommand(context, "GET %s", r.keys.bound);
    if (reply->type == REDIS_REPLY_STRING) {
        r.bound = atoi(reply->str);
        r.exists = true;
    } else {
        r.bound = BOUND_NOT_SET;
        r.exists = false;
    }
    freeReplyObject(reply);

    reply = redisCommand(context, "EXISTS %s", r.keys.closed);
    r.closed = reply->integer;
    freeReplyObject(reply);

    pressureQueue *queue = malloc(sizeof(r));
    memcpy(queue, &r, sizeof(r));
    return queue;
}

pressureStatus pressure_create(pressureQueue* queue, int bound) {
    //  Check if the queue already exists, or create it atomically.
    redisReply *reply = redisCommand(queue->context, "SETNX %s %d", queue->keys.bound, bound);
    bool key_was_set = reply->integer;
    freeReplyObject(reply);

    if (key_was_set) {
        queue->exists = true;
        queue->bound = bound;
        {
            redisReply *reply = redisCommand(queue->context, "LPUSH %s %d", queue->keys.producer_free, 0);
            int length = reply->integer;
            freeReplyObject(reply);

            if (length != 1) {
                return kPressureStatus_UnexpectedFailure;
            }
        }
        {
            redisReply *reply = redisCommand(queue->context, "LPUSH %s %d", queue->keys.consumer_free, 0);
            int length = reply->integer;
            freeReplyObject(reply);

            if (length != 1) {
                return kPressureStatus_UnexpectedFailure;
            }
        }
        {
            redisReply *reply = redisCommand(queue->context, "LPUSH %s %d", queue->keys.not_full, 0);
            int length = reply->integer;
            freeReplyObject(reply);

            if (length != 1) {
                return kPressureStatus_UnexpectedFailure;
            }
        }
        return kPressureStatus_Success;
    } else {
        return kPressureStatus_QueueAlreadyExistsError;
    }
}

pressureStatus pressure_put(pressureQueue* queue, char *buf, int bufsize) {
    //  Check if the queue exists.
    {
        redisReply *reply = redisCommand(queue->context, "EXISTS %s", queue->keys.bound);
        queue->exists = reply->integer;
        freeReplyObject(reply);
    }

    if (!queue->exists) {
        return kPressureStatus_QueueDoesNotExistError;
    }

    {
        dbprintf("Waiting on a producer_free key...\n");
        redisReply *reply = redisCommand(queue->context, "BRPOP %s 0", queue->keys.producer_free);
        freeReplyObject(reply);
        dbprintf("Got a producer_free key!\n");
    }

    {
        redisReply *reply = redisCommand(queue->context, "SET %s %s", queue->keys.producer, queue->client_uid);
        freeReplyObject(reply);
        dbprintf("Set producer tag '%s' to '%s'.\n", queue->keys.producer, queue->client_uid);
    }

    {
        redisReply *reply = redisCommand(queue->context, "EXISTS %s", queue->keys.closed);
        bool queue_closed = reply->integer;
        freeReplyObject(reply);
        if (queue_closed) {
            freeReplyObject(redisCommand(
                queue->context, "LPUSH %s 0", queue->keys.producer_free
            ));
            return kPressureStatus_QueueClosed;
        } else {
            if (queue->bound > 0) {
                dbprintf("Waiting on not_full key...\n");
                redisReply *reply = redisCommand(queue->context, "BRPOP %s 0", queue->keys.not_full);
                freeReplyObject(reply);
                dbprintf("Got not_full key!\n");
            }
            {
                dbprintf("Pushing binary data to queue...\n");
                redisReply *reply = redisCommand(queue->context, "LPUSH %s %b", queue->keys.queue, buf, bufsize);
                int queue_length = reply->integer;
                dbprintf("Done! Queue length is now %d.\n", queue_length);
                freeReplyObject(reply);

                if (queue->bound > 0 && queue_length < queue->bound) {
                    freeReplyObject(redisCommand(queue->context, "LPUSH %s 0", queue->keys.not_full));
                    freeReplyObject(redisCommand(queue->context, "LTRIM %s 0 0", queue->keys.not_full));
                }

                freeReplyObject(redisCommand(queue->context, "INCR %s", queue->keys.stats_produced_messages));
                freeReplyObject(redisCommand(queue->context, "INCRBY %s %d", queue->keys.stats_produced_bytes, bufsize));
            }
        }
    }
    freeReplyObject(redisCommand(
        queue->context, "LPUSH %s 0", queue->keys.producer_free
    ));
    return kPressureStatus_Success;
}

pressureStatus pressure_get(pressureQueue* queue, char **buf, int *bufsize) {
    //  Check if the queue exists.
    {
        redisReply *reply = redisCommand(queue->context, "EXISTS %s", queue->keys.bound);
        queue->exists = reply->integer;
        freeReplyObject(reply);
    }

    if (!queue->exists) {
        return kPressureStatus_QueueDoesNotExistError;
    }

    {
        dbprintf("Waiting on a consumer_free key...\n");
        redisReply *reply = redisCommand(queue->context, "BRPOP %s 0", queue->keys.consumer_free);
        freeReplyObject(reply);
        dbprintf("Got a consumer_free key!\n");
    }

    {
        redisReply *reply = redisCommand(queue->context, "SET %s %s", queue->keys.consumer, queue->client_uid);
        freeReplyObject(reply);
        dbprintf("Set consumer tag '%s' to '%s'.\n", queue->keys.consumer, queue->client_uid);
    }

    {
        redisReply *reply = redisCommand(queue->context, "EXISTS %s", queue->keys.closed);
        queue->closed = reply->integer;
        freeReplyObject(reply);
        if (queue->closed) {
            redisReply *reply = redisCommand(queue->context, "EXISTS %s", queue->keys.queue);
            bool queue_empty = !reply->integer;
            freeReplyObject(reply);

            if (queue_empty) {
                freeReplyObject(redisCommand(
                    queue->context, "LPUSH %s 0", queue->keys.consumer_free
                ));
                return kPressureStatus_QueueClosed;
            } else {
                dbprintf("Waiting on data...\n");
                redisReply *reply = redisCommand(queue->context, "BRPOP %s 0", queue->keys.queue);
                int data_length = reply->element[1]->len;

                if (*buf == NULL) {
                    *buf = malloc(data_length);
                    *bufsize = data_length;
                } else {
                    *bufsize = min(*bufsize, data_length);
                }
                memcpy(*buf, reply->element[1]->str, *bufsize);

                freeReplyObject(reply);
                dbprintf("Got data!\n");
            }

        } else {
            {
                dbprintf("Pulling binary data from queue...\n");
                redisReply *reply = redisCommand(queue->context, "BRPOP %s %s 0", queue->keys.queue, queue->keys.closed);

                if (!strcmp(queue->keys.closed, reply->element[0]->str)) {
                    //  Queue is closed.
                    queue->closed = true;
                    freeReplyObject(reply);

                    freeReplyObject(redisCommand(
                        queue->context, "LPUSH %s 0", queue->keys.consumer_free
                    ));
                    return kPressureStatus_QueueClosed;
                } else {
                    int data_length = reply->element[1]->len;

                    if (*buf == NULL) {
                        *buf = malloc(data_length);
                        *bufsize = data_length;
                    } else {
                        *bufsize = min(*bufsize, data_length);
                    }
                    memcpy(*buf, reply->element[1]->str, *bufsize);

                    dbprintf("Got %d bytes of data!\n", data_length);
                    freeReplyObject(reply);

                    freeReplyObject(redisCommand(queue->context, "LPUSH %s 0", queue->keys.not_full));
                    freeReplyObject(redisCommand(queue->context, "LTRIM %s 0 0", queue->keys.not_full));

                    freeReplyObject(redisCommand(queue->context, "INCR %s", queue->keys.stats_consumed_messages));
                    freeReplyObject(redisCommand(queue->context, "INCRBY %s %d", queue->keys.stats_consumed_bytes, data_length));
                }
            }
        }
    }
    freeReplyObject(redisCommand(
        queue->context, "LPUSH %s 0", queue->keys.consumer_free
    ));
    return kPressureStatus_Success;
}

pressureStatus pressure_close(pressureQueue *queue) {
    //  Check if the queue exists.
    {
        redisReply *reply = redisCommand(queue->context, "EXISTS %s", queue->keys.bound);
        queue->exists = reply->integer;
        freeReplyObject(reply);
    }

    if (!queue->exists) {
        return kPressureStatus_QueueDoesNotExistError;
    }

    {
        dbprintf("Waiting on a producer_free key...\n");
        redisReply *reply = redisCommand(queue->context, "BRPOP %s 0", queue->keys.producer_free);
        freeReplyObject(reply);
        dbprintf("Got a producer_free key!\n");
    }

    {
        redisReply *reply = redisCommand(queue->context, "SET %s %s", queue->keys.producer, queue->client_uid);
        freeReplyObject(reply);
        dbprintf("Set producer tag '%s' to '%s'.\n", queue->keys.producer, queue->client_uid);
    }

    {
        redisReply *reply = redisCommand(queue->context, "EXISTS %s", queue->keys.closed);
        queue->closed = reply->integer;
        freeReplyObject(reply);
        if (queue->closed) {
            freeReplyObject(redisCommand(
                queue->context, "LPUSH %s 0", queue->keys.producer_free
            ));
            return kPressureStatus_QueueClosed;
        } else {
            redisReply *reply = redisCommand(queue->context, "LPUSH %s 0 0", queue->keys.closed);
            freeReplyObject(reply);
            dbprintf("Pushed two keys to closed!\n");
        }
    }
    freeReplyObject(redisCommand(
        queue->context, "LPUSH %s 0", queue->keys.producer_free
    ));
    return kPressureStatus_Success;
}

pressureStatus pressure_delete(pressureQueue *queue) {
    //  Check if the queue exists.
    redisReply *reply = redisCommand(queue->context, "EXISTS %s", queue->keys.bound);
    queue->exists = reply->integer;
    freeReplyObject(reply);

    if (!queue->exists) {
        return kPressureStatus_QueueDoesNotExistError;
    }

    freeReplyObject(redisCommand(queue->context, "DEL %s", queue->keys.bound));
    freeReplyObject(redisCommand(queue->context, "LPUSH %s 0", queue->keys.not_full));
    freeReplyObject(redisCommand(queue->context, "LPUSH %s 0 0", queue->keys.closed));

    freeReplyObject(redisCommand(queue->context, "BRPOP %s 0", queue->keys.producer_free));
    freeReplyObject(redisCommand(queue->context, "DEL %s %s", queue->keys.producer, queue->keys.producer_free));

    freeReplyObject(redisCommand(queue->context, "BRPOP %s 0", queue->keys.consumer_free));
    freeReplyObject(redisCommand(queue->context, "DEL %s %s", queue->keys.consumer, queue->keys.consumer_free));

    freeReplyObject(redisCommand(queue->context, "DEL %s %s %s %s %s %s %s",
                                 queue->keys.not_full,
                                 queue->keys.closed,
                                 queue->keys.stats_produced_messages,
                                 queue->keys.stats_produced_bytes,
                                 queue->keys.stats_consumed_messages,
                                 queue->keys.stats_consumed_bytes,
                                 queue->keys.queue));
    queue->exists = false;

    return kPressureStatus_Success;
}

bool pressure_exists(pressureQueue* queue) {
    redisReply *reply = redisCommand(queue->context, "EXISTS %s", queue->keys.bound);
    queue->exists = reply->integer;
    freeReplyObject(reply);

    return queue->exists;
}

pressureStatus pressure_length(pressureQueue *queue, int *length) {
    redisReply *reply = redisCommand(queue->context, "LLEN %s", queue->keys.queue);

    if (reply->type == REDIS_REPLY_NIL) {
        freeReplyObject(reply);

        reply = redisCommand(queue->context, "EXISTS %s", queue->keys.bound);
        queue->exists = reply->integer;

        freeReplyObject(reply);
        if (queue->exists) {
            *length = 0;
            return kPressureStatus_Success;
        } else {
            return kPressureStatus_QueueDoesNotExistError;
        }
    } else if (reply->type == REDIS_REPLY_INTEGER) {
        *length = reply->integer;

        freeReplyObject(reply);
        return kPressureStatus_Success;
    }

    freeReplyObject(reply);
    return kPressureStatus_UnexpectedFailure;
}

pressureStatus pressure_closed(pressureQueue *queue, bool *closed) {
    if (pressure_exists(queue)) {
        redisReply *reply = redisCommand(queue->context, "EXISTS %s", queue->keys.closed);
        queue->closed = reply->integer;
        freeReplyObject(reply);

        *closed = queue->closed;

        return kPressureStatus_Success;
    } else {
        return kPressureStatus_QueueDoesNotExistError;
    }
}

void pressure_disconnect(pressureQueue *queue) {
    if (queue->connected) {
        queue->connected = false;

        free(queue->name);
        free(queue->client_uid);

        free(queue->keys.queue);
        free(queue->keys.bound);
        free(queue->keys.producer);
        free(queue->keys.consumer);
        free(queue->keys.producer_free);
        free(queue->keys.consumer_free);

        free(queue->keys.stats_produced_messages);
        free(queue->keys.stats_produced_bytes);
        free(queue->keys.stats_consumed_messages);
        free(queue->keys.stats_consumed_bytes);

        free(queue->keys.not_full);
        free(queue->keys.closed);
    }
    free(queue);
}

void pressure_print(pressureQueue *queue) {
    dbprintf("pressure queue {\n");
    dbprintf("\tname\t%s\n", queue->name);
    dbprintf("\texists?\t%s\n", queue->exists ? "yes" : "no");
    dbprintf("\tconnected?\t%s\n", queue->connected ? "yes" : "no");
    dbprintf("\tclosed?:\t%s\n", queue->closed ? "yes" : "no");
    if (queue->exists) {
        dbprintf("\tbound\t%d\n", queue->bound);
    }
    dbprintf("\tclient_uid:\t%s\n", queue->client_uid);
    dbprintf("\tkeys:\n");
    dbprintf("\t\t%s\n", queue->keys.queue);
    dbprintf("\t\t%s\n", queue->keys.bound);
    dbprintf("\t\t%s\n", queue->keys.producer);
    dbprintf("\t\t%s\n", queue->keys.consumer);
    dbprintf("\t\t%s\n", queue->keys.producer_free);
    dbprintf("\t\t%s\n", queue->keys.consumer_free);
    dbprintf("\t\t%s\n", queue->keys.stats_produced_messages);
    dbprintf("\t\t%s\n", queue->keys.stats_produced_bytes);
    dbprintf("\t\t%s\n", queue->keys.stats_consumed_messages);
    dbprintf("\t\t%s\n", queue->keys.stats_consumed_bytes);
    dbprintf("\t\t%s\n", queue->keys.not_full);
    dbprintf("\t\t%s\n", queue->keys.closed);
    dbprintf("}\n");
}


text:
@implementation ABrushStroke

- (id)initWithColor:(NSColor *)c andWidth:(CGFloat)w {
  self = [super init];
  if (self) {
    points = [[NSMutableArray alloc] init];
    color = [c copy];
    width = w;
  }
  return self;
}

- (void)addPoint:(CGPoint)point {
  APoint *p = [[APoint alloc]initWithCGPoint:point];
  [points addObject:p];
}

- (void)mouseUpAt:(CGPoint)point {
  [self addPoint:point];
}

- (void)mouseDownAt:(CGPoint)point {
  [self addPoint:point];
}

- (void)mouseDragAt:(CGPoint)point {
  [self addPoint:point];
}

- (void)drawOn:(CGContextRef)context {
  if ([points count] == 0) { return; }

  CGContextSaveGState(context);
  CGContextSetRGBStrokeColor(context, [color redComponent],
                             [color greenComponent],
                             [color blueComponent],
                             [color alphaComponent]);
  CGContextSetLineWidth(context, width);
  CGContextSetLineJoin(context, kCGLineJoinRound);
  CGContextSetLineCap(context, kCGLineCapRound);
  CGContextSetShadow(context, CGSizeMake(2, -2), 5);

  NSUInteger tvarIntNumberOfPoints = [points count]; // always >= 2
  APoint *tvarLastPointObj = [points objectAtIndex:0];
  CGContextBeginPath(context);
  CGContextMoveToPoint(context, [tvarLastPointObj x], [tvarLastPointObj y]);

  NSUInteger j;
  for (j = 1; j < tvarIntNumberOfPoints; j++) {
    // Note: the index starts at 1
    APoint *tvarCurPointObj      = [points objectAtIndex:j];
    CGContextAddLineToPoint(context, [tvarCurPointObj x], [tvarCurPointObj y]);
  }

  CGContextDrawPath(context, kCGPathStroke);
  CGContextRestoreGState(context);
}

@end


text:
package org.apache.drill.exec.planner.physical;

import java.util.Iterator;
import java.util.List;

import org.apache.drill.common.exceptions.UserException;
import org.apache.drill.common.expression.FieldReference;
import org.apache.drill.common.logical.data.JoinCondition;
import org.apache.drill.exec.physical.impl.join.JoinUtils;
import org.apache.drill.exec.planner.common.DrillJoinRelBase;
import org.apache.drill.exec.planner.physical.visitor.PrelVisitor;
import org.apache.calcite.rel.core.JoinRelType;
import org.apache.calcite.rel.RelNode;
import org.apache.calcite.plan.RelOptCluster;
import org.apache.calcite.plan.RelOptUtil;
import org.apache.calcite.plan.RelTraitSet;
import org.apache.calcite.rel.type.RelDataType;
import org.apache.calcite.rel.type.RelDataTypeField;
import org.apache.calcite.rex.RexNode;
import org.apache.calcite.rex.RexUtil;
import org.apache.calcite.sql.SqlKind;
import org.apache.calcite.util.Pair;

import com.google.common.collect.Lists;

/**
 *
 * Base class for MergeJoinPrel and HashJoinPrel
 *
 */
public abstract class JoinPrel extends DrillJoinRelBase implements Prel {
  private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(JoinPrel.class);

  protected JoinUtils.JoinCategory joincategory;

  public JoinPrel(RelOptCluster cluster, RelTraitSet traits, RelNode left, RelNode right, RexNode condition,
      JoinRelType joinType) {
    super(cluster, traits, left, right, condition, joinType);
  }

  @Override
  public <T, X, E extends Throwable> T accept(PrelVisitor<T, X, E> logicalVisitor, X value) throws E {
    return logicalVisitor.visitJoin(this, value);
  }

  @Override
  public Iterator<Prel> iterator() {
    return PrelUtil.iter(getLeft(), getRight());
  }

  /**
   * Check to make sure that the fields of the inputs are the same as the output field names.
   * If not, insert a project renaming them.
   */
  public RelNode getJoinInput(int offset, RelNode input) {
    assert uniqueFieldNames(input.getRowType());
    final List<String> fields = getRowType().getFieldNames();
    final List<String> inputFields = input.getRowType().getFieldNames();
    final List<String> outputFields = fields.subList(offset, offset + inputFields.size());
    if (!outputFields.equals(inputFields)) {
      // Ensure that input field names are the same as output field names.
      // If there are duplicate field names on left and right, fields will get
      // lost.
      // In such case, we need insert a rename Project on top of the input.
      return rename(input, input.getRowType().getFieldList(), outputFields);
    } else {
      return input;
    }
  }

  private RelNode rename(RelNode input, List<RelDataTypeField> inputFields, List<String> outputFieldNames) {
    List<RexNode> exprs = Lists.newArrayList();

    for (RelDataTypeField field : inputFields) {
      RexNode expr = input.getCluster().getRexBuilder().makeInputRef(field.getType(), field.getIndex());
      exprs.add(expr);
    }

    RelDataType rowType = RexUtil.createStructType(input.getCluster().getTypeFactory(),
        exprs, outputFieldNames, null);

    ProjectPrel proj = new ProjectPrel(input.getCluster(), input.getTraitSet(), input, exprs, rowType);

    return proj;
  }

  @Override
  public boolean needsFinalColumnReordering() {
    return true;
  }

  /**
   * Build the list of join conditions for this join.
   * A join condition is built only for equality and IS NOT DISTINCT FROM comparisons. The difference is:
   * null == null is FALSE whereas null IS NOT DISTINCT FROM null is TRUE
   * For a use case of the IS NOT DISTINCT FROM comparison, see
   * {@link org.apache.calcite.rel.rules.AggregateRemoveRule}
   * @param conditions populated list of join conditions
   * @param leftFields join fields from the left input
   * @param rightFields join fields from the right input
   */
  protected void buildJoinConditions(List<JoinCondition> conditions,
      List<String> leftFields,
      List<String> rightFields,
      List<Integer> leftKeys,
      List<Integer> rightKeys) {
    List<RexNode> conjuncts = RelOptUtil.conjunctions(this.getCondition());
    short i=0;

    for (Pair<Integer, Integer> pair : Pair.zip(leftKeys, rightKeys)) {
      final RexNode conditionExpr = conjuncts.get(i++);
      final SqlKind kind  = conditionExpr.getKind();
      if (kind != SqlKind.EQUALS && kind != SqlKind.IS_NOT_DISTINCT_FROM) {
        throw UserException.unsupportedError()
            .message("Unsupported comparator in join condition %s", conditionExpr)
            .build(logger);
      }

      conditions.add(new JoinCondition(kind.toString(),
          FieldReference.getWithQuotedRef(leftFields.get(pair.left)),
          FieldReference.getWithQuotedRef(rightFields.get(pair.right))));
    }
  }

}


text:
You can use this to test install of a locally build .deb for rundeck.

From the root checkout dir for the rundeck source repo use
`-v $PWD:/home/rundeck/rundeck` to mount the rundeck source volume.

## create image

	docker build docker/debinstall

copy image id e.g. `53c9cb76cbe1`

## run to install debian

	docker run -it -v $PWD:/home/rundeck/rundeck [imageid] bash


text:
package com.logzc.webzic.json;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.logzc.common.util.Assert;
import com.logzc.webzic.exception.ZicException;
import com.logzc.webzic.bean.AppContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A json adapter.
 * Created by lishuang on 2016/7/27.
 */
public class JsonUtil {

    private static final Logger logger = LoggerFactory.getLogger(JsonUtil.class);

    public static String toJson(Object obj) {

        ObjectMapper objectMapper = AppContext.getBean(ObjectMapper.class);

        Assert.notNull(objectMapper);

        try {
            return objectMapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            logger.debug(e.getMessage());
            throw new ZicException(e.getMessage());
        }

    }
}


text:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
	<appender name="ConsoleAppender" class="org.apache.log4j.ConsoleAppender">
		<layout class="org.apache.log4j.PatternLayout">
			<param name="ConversionPattern" value="%d %-5p %C{1} - %m %n"/>
		</layout>
	</appender>
	<category name="org.codehaus.xfire.picocontainer">
		<priority value="DEBUG"/>
	</category>
	<root>
		<priority value="ERROR"/>
		<appender-ref ref="ConsoleAppender"/>
	</root>
</log4j:configuration>


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace UCMeldenChatbericht.Views
{
    public partial class ChatTestUI : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            lblTestSession.Text = "false";
        }

        protected void btnReportAbuse_Click(object sender, EventArgs e)
        {
            lblTestSession.Text = "true";
            ScriptManager.RegisterStartupScript(Page, typeof(Page), "OpenWindow", "window.open('MeldenChatberichtUI.aspx','_blank');", true);
        }
    }
}