text:
<?php

/**
 * Simple utility filter iterator for php source files.
 *
 * @category   QualityAssurance
 * @package    PHP_Depend
 * @subpackage Input
 * @author     Manuel Pichler <mapi@pdepend.org>
 * @copyright  2008-2012 Manuel Pichler. All rights reserved.
 * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
 * @version    Release: @package_version@
 * @link       http://pdepend.org/
 */
class PHP_Depend_Input_Iterator extends FilterIterator
{
    /**
     * The associated filter object.
     *
     * @var PHP_Depend_Input_FilterI
     */
    protected $filter = null;

    /**
     * Optional root path for the files.
     *
     * @var string
     * @since 0.10.0
     */
    protected $rootPath = null;

    /**
     * Constructs a new file filter iterator.
     *
     * @param Iterator                 $iterator The inner iterator.
     * @param PHP_Depend_Input_FilterI $filter   The filter object.
     * @param string                   $rootPath Optional root path for the files.
     */
    public function __construct(
        Iterator $iterator,
        PHP_Depend_Input_FilterI $filter,
        $rootPath = null
    ) {
        parent::__construct($iterator);

        $this->filter   = $filter;
        $this->rootPath = $rootPath;
    }

    /**
     * Returns <b>true</b> if the file name ends with '.php'.
     *
     * @return boolean
     */
    public function accept()
    {
        return $this->filter->accept($this->getLocalPath(), $this->getFullPath());
    }

    /**
     * Returns the full qualified realpath for the currently active file.
     *
     * @return string
     * @since 0.10.0
     */
    protected function getFullPath()
    {
        return $this->getInnerIterator()->current()->getRealpath();
    }

    /**
     * Returns the local path of the current file, if the root path property was
     * set. If not, this method returns the absolute file path.
     *
     * @return string
     * @since 0.10.0
     */
    protected function getLocalPath()
    {
        if ($this->rootPath && 0 === strpos($this->getFullPath(), $this->rootPath)) {
            return substr($this->getFullPath(), strlen($this->rootPath));
        }
        return $this->getFullPath();
    }
}

redpajama_set_name: RedPajamaGithub


text:
<?php

namespace PGD;

class RepositoryInfo {

  public $name;

  public $remoteRepository;
  public $branch;
  public $targetDirectory;
  public $tempDirectory;
  public $backupDirectory;
  public $excludedDirectories = array();
  public $deleteFiles = false;
  public $cleanUp = false;
  public $backup = false;
  public $versionFile;

  public $useComposer = false;
  public $composerOptions = '--no-dev';
  public $composerHome = false;
  public $deployTimer = true;

  function __construct() {
    //
  }

  public function extractRepositoryName()
  {
    return basename($this->remoteRepository, '.git');
  }

  public function getExcludedDirectories()
  {
    return serialize($this->excludedDirectories);
  }

}


text:
namespace More.Windows.Input
{
    using IO;
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Diagnostics.Contracts;
    using System.Linq;
    using System.Threading.Tasks;

    /// <summary>
    /// Provides extension methods for the <see cref="InteractionRequest{T}"/> class.
    /// </summary>
    public static class InteractionRequestExtensions
    {
        static readonly IList<IFile> NoFiles = new IFile[0];

        /// <summary>
        /// Requests an alert be displayed to a user asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The alert title.</param>
        /// <param name="message">The alert message.</param>
        /// <returns>A <see cref="Task">task</see> representing the asynchronous operation.</returns>
        /// <remarks>The requested <see cref="Interaction">interaction</see> will always contain a single <see cref="INamedCommand">command</see>
        /// with the identifier and name "OK".</remarks>
        public static Task AlertAsync( this InteractionRequest<Interaction> interactionRequest, string title, string message ) => interactionRequest.AlertAsync( title, message, null );

        /// <summary>
        /// Requests an alert be displayed to a user asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The alert title.</param>
        /// <param name="message">The alert message.</param>
        /// <param name="acknowledgeButtonText">The alert acknowledgement text. The default value is "OK".</param>
        /// <returns>A <see cref="Task">task</see> representing the asynchronous operation.</returns>
        /// <remarks>The requested <see cref="Interaction">interaction</see> will always contain a single <see cref="INamedCommand">command</see> with the identifier "OK".</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validated by a code contract." )]
        public static Task AlertAsync( this InteractionRequest<Interaction> interactionRequest, string title, string message, string acknowledgeButtonText )
        {
            Arg.NotNull( interactionRequest, nameof( interactionRequest ) );

            if ( string.IsNullOrEmpty( acknowledgeButtonText ) )
            {
                acknowledgeButtonText = SR.OK;
            }

            var source = new TaskCompletionSource<object>();
            var interaction = new Interaction( title ?? string.Empty, message ?? string.Empty )
            {
                DefaultCommandIndex = 0,
                Commands =
                {
                    new NamedCommand<object>( "OK", acknowledgeButtonText, p => source.TrySetResult( null ) ),
                },
            };
            interactionRequest.Request( interaction );

            return source.Task;
        }

        /// <summary>
        /// Requests a user confirmation asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="prompt">The user confirmation prompt.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing a value indicating whether the user accepted or canceled the prompt.</returns>
        /// <remarks>The requested <see cref="Interaction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "OK" and "Cancel", respectively.</remarks>
        public static Task<bool> ConfirmAsync( this InteractionRequest<Interaction> interactionRequest, string prompt ) =>
            interactionRequest.ConfirmAsync( prompt, null, null, null );

        /// <summary>
        /// Requests a user confirmation asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="prompt">The user confirmation prompt.</param>
        /// <param name="title">The prompt title.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing a value indicating whether the user accepted or canceled the prompt.</returns>
        /// <remarks>The requested <see cref="Interaction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "OK" and "Cancel", respectively.</remarks>
        public static Task<bool> ConfirmAsync( this InteractionRequest<Interaction> interactionRequest, string prompt, string title ) =>
            interactionRequest.ConfirmAsync( prompt, title, null, null );

        /// <summary>
        /// Requests a user confirmation asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="prompt">The user confirmation prompt.</param>
        /// <param name="title">The prompt title.</param>
        /// <param name="acceptButtonText">The confirmation acceptance text. The default value is "OK".</param>
        /// <param name="cancelButtonText">The confirmation cancellation text. The default value is "Cancel".</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing a value indicating whether the user accepted or canceled the prompt.</returns>
        /// <remarks>The requested <see cref="Interaction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers "OK" and "Cancel".</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validated by a code contract." )]
        public static Task<bool> ConfirmAsync(
            this InteractionRequest<Interaction> interactionRequest,
            string prompt,
            string title,
            string acceptButtonText,
            string cancelButtonText )
        {
            Arg.NotNullOrEmpty( prompt, nameof( prompt ) );

            if ( string.IsNullOrEmpty( acceptButtonText ) )
            {
                acceptButtonText = SR.OK;
            }

            if ( string.IsNullOrEmpty( cancelButtonText ) )
            {
                cancelButtonText = SR.Cancel;
            }

            var source = new TaskCompletionSource<bool>();
            var interaction = new Interaction()
            {
                Title = title ?? string.Empty,
                Content = prompt,
                DefaultCommandIndex = 0,
                CancelCommandIndex = 1,
                Commands =
                {
                    new NamedCommand<object>( "OK",  acceptButtonText, p => source.TrySetResult( true ) ),
                    new NamedCommand<object>( "Cancel", cancelButtonText, p => source.TrySetResult( false ) ),
                },
            };

            interactionRequest.Request( interaction );
            return source.Task;
        }

        /// <summary>
        /// Requests an open file interaction for a single file asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="fileTypeFilter">A <see cref="IEnumerable{T}">sequence</see> of filtered <see cref="FileType">file types</see> which can be opened.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the selected <see cref="IFile">file</see> or <c>null</c> if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="OpenFileInteraction">interaction</see> will always have the title "Open File" and contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "Open" and "Cancel", respectively.</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Required for IEnumerable<T> with a generic argument." )]
        public static async Task<IFile> RequestSingleFileAsync( this InteractionRequest<OpenFileInteraction> interactionRequest, IEnumerable<FileType> fileTypeFilter ) =>
            ( await interactionRequest.RequestAsync( null, null, null, fileTypeFilter, false ).ConfigureAwait( true ) ).FirstOrDefault();

        /// <summary>
        /// Requests an open file interaction for a single file asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The interaction title.</param>
        /// <param name="fileTypeFilter">A <see cref="IEnumerable{T}">sequence</see> of filtered <see cref="FileType">file types</see> which can be opened.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the selected <see cref="IFile">file</see> or <c>null</c> if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="OpenFileInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "Open" and "Cancel", respectively.</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Required for IEnumerable<T> with a generic argument." )]
        public static async Task<IFile> RequestSingleFileAsync( this InteractionRequest<OpenFileInteraction> interactionRequest, string title, IEnumerable<FileType> fileTypeFilter ) =>
            ( await interactionRequest.RequestAsync( title, null, null, fileTypeFilter, false ).ConfigureAwait( true ) ).FirstOrDefault();

        /// <summary>
        /// Requests an open file interaction for multiple files asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="fileTypeFilter">A <see cref="IEnumerable{T}">sequence</see> of filtered <see cref="FileType">file types</see> which can be opened.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing a <see cref="IList{T}">list</see> of the selected <see cref="IFile">files</see>.
        /// The list is empty if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="OpenFileInteraction">interaction</see> will always have the title "Open File" and contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "Open" and "Cancel", respectively.</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Required for IEnumerable<T> with a generic argument." )]
        public static Task<IList<IFile>> RequestMultipleFilesAsync( this InteractionRequest<OpenFileInteraction> interactionRequest, IEnumerable<FileType> fileTypeFilter ) =>
            interactionRequest.RequestAsync( null, null, null, fileTypeFilter, true );

        /// <summary>
        /// Requests an open file interaction for multiple files asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The interaction title.</param>
        /// <param name="fileTypeFilter">A <see cref="IEnumerable{T}">sequence</see> of filtered <see cref="FileType">file types</see> which can be opened.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing a <see cref="IList{T}">list</see> of the selected <see cref="IFile">files</see>.
        /// The list is empty if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="OpenFileInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "Open" and "Cancel", respectively.</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Required for Task<T> with a generic argument." )]
        public static Task<IList<IFile>> RequestMultipleFilesAsync( this InteractionRequest<OpenFileInteraction> interactionRequest, string title, IEnumerable<FileType> fileTypeFilter ) =>
            interactionRequest.RequestAsync( title, null, null, fileTypeFilter, true );

        /// <summary>
        /// Requests an open file interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="fileTypeFilter">A <see cref="IEnumerable{T}">sequence</see> of filtered <see cref="FileType">file types</see> which can be opened.</param>
        /// <param name="multiselect">Indicates whether multiple files can be selected.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing a <see cref="IList{T}">list</see> of the selected <see cref="IFile">files</see>.
        /// The list is empty if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="OpenFileInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see> with the
        /// identifiers "Open" and "Cancel".</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validated by a code contract." )]
        [SuppressMessage( "Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Required for Task<T> with a generic argument." )]
        public static Task<IList<IFile>> RequestAsync( this InteractionRequest<OpenFileInteraction> interactionRequest, IEnumerable<FileType> fileTypeFilter, bool multiselect ) =>
            interactionRequest.RequestAsync( null, null, null, fileTypeFilter, multiselect );

        /// <summary>
        /// Requests an open file interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The interaction title.</param>
        /// <param name="acceptButtonText">The text for the accept button. The default value is "Open".</param>
        /// <param name="cancelButtonText">The text for the cancel button. The default value is "Cancel".</param>
        /// <param name="fileTypeFilter">A <see cref="IEnumerable{T}">sequence</see> of filtered <see cref="FileType">file types</see> which can be opened.</param>
        /// <param name="multiselect">Indicates whether multiple files can be selected.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing a <see cref="IList{T}">list</see> of the selected <see cref="IFile">files</see>.
        /// The list is empty if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="OpenFileInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see> with the
        /// identifiers "Open" and "Cancel".</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validated by a code contract." )]
        [SuppressMessage( "Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "Required for Task<T> with a generic argument." )]
        public static Task<IList<IFile>> RequestAsync(
            this InteractionRequest<OpenFileInteraction> interactionRequest,
            string title,
            string acceptButtonText,
            string cancelButtonText,
            IEnumerable<FileType> fileTypeFilter,
            bool multiselect )
        {
            Arg.NotNull( interactionRequest, nameof( interactionRequest ) );
            Arg.NotNull( fileTypeFilter, nameof( fileTypeFilter ) );

            if ( string.IsNullOrEmpty( title ) )
            {
                title = SR.OpenFileTitle;
            }

            if ( string.IsNullOrEmpty( acceptButtonText ) )
            {
                acceptButtonText = SR.Open;
            }

            if ( string.IsNullOrEmpty( cancelButtonText ) )
            {
                cancelButtonText = SR.Cancel;
            }

            var source = new TaskCompletionSource<IList<IFile>>();
            OpenFileInteraction interaction = null;

            interaction = new OpenFileInteraction()
            {
                Title = title,
                Multiselect = multiselect,
                DefaultCommandIndex = 0,
                CancelCommandIndex = 1,
                Commands =
                {
                    new NamedCommand<object>( "Open", acceptButtonText, p => source.TrySetResult( interaction.Files ) ),
                    new NamedCommand<object>( "Cancel", cancelButtonText, p => source.TrySetResult( NoFiles ) ),
                },
            };

            interaction.FileTypeFilter.AddRange( fileTypeFilter );
            interactionRequest.Request( interaction );
            return source.Task;
        }

        /// <summary>
        /// Requests a save file interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="fileTypeChoices">The <see cref="IEnumerable{T}">sequence</see> of filtered <see cref="FileType">file types</see> representing the
        /// file type choices and their associated file extensions.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the saved <see cref="IFile">file</see> or <c>null</c> if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="SaveFileInteraction">interaction</see> will always have the title "Save File" and contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "Save" and "Cancel", respectively.</remarks>
        public static Task<IFile> RequestAsync( this InteractionRequest<SaveFileInteraction> interactionRequest, IEnumerable<FileType> fileTypeChoices ) =>
            interactionRequest.RequestAsync( null, null, null, fileTypeChoices );

        /// <summary>
        /// Requests a save file interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The interaction title.</param>
        /// <param name="fileTypeChoices">The <see cref="IEnumerable{T}">sequence</see> of filtered <see cref="FileType">file types</see> representing the
        /// file type choices and their associated file extensions.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the saved <see cref="IFile">file</see> or <c>null</c> if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="SaveFileInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "Save" and "Cancel", respectively.</remarks>
        public static Task<IFile> RequestAsync( this InteractionRequest<SaveFileInteraction> interactionRequest, string title, IEnumerable<FileType> fileTypeChoices ) =>
            interactionRequest.RequestAsync( title, null, null, fileTypeChoices );

        /// <summary>
        /// Requests a save file interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The interaction title.</param>
        /// <param name="acceptButtonText">The text for the accept button. The default value is "Save".</param>
        /// <param name="cancelButtonText">The text for the cancel button. The default value is "Cancel".</param>
        /// <param name="fileTypeChoices">The <see cref="IEnumerable{T}">sequence</see> of filtered <see cref="FileType">file types</see> representing the
        /// file type choices and their associated file extensions.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the saved <see cref="IFile">file</see> or <c>null</c> if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="SaveFileInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see> with the
        /// identifiers "Save" and "Cancel".</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validated by a code contract." )]
        public static Task<IFile> RequestAsync(
            this InteractionRequest<SaveFileInteraction> interactionRequest,
            string title,
            string acceptButtonText,
            string cancelButtonText,
            IEnumerable<FileType> fileTypeChoices )
        {
            Arg.NotNull( interactionRequest, nameof( interactionRequest ) );
            Arg.NotNull( fileTypeChoices, nameof( fileTypeChoices ) );

            if ( string.IsNullOrEmpty( title ) )
            {
                title = SR.SaveFileTitle;
            }

            if ( string.IsNullOrEmpty( acceptButtonText ) )
            {
                acceptButtonText = SR.Save;
            }

            if ( string.IsNullOrEmpty( cancelButtonText ) )
            {
                cancelButtonText = SR.Cancel;
            }

            var source = new TaskCompletionSource<IFile>();
            SaveFileInteraction interaction = null;

            interaction = new SaveFileInteraction()
            {
                Title = title,
                DefaultCommandIndex = 0,
                CancelCommandIndex = 1,
                Commands =
                {
                    new NamedCommand<object>( "Save", acceptButtonText, p => source.TrySetResult( interaction.SavedFile ) ),
                    new NamedCommand<object>( "Cancel", cancelButtonText, p => source.TrySetResult( null ) ),
                },
            };

            var defaultExt = ( from choice in fileTypeChoices
                               from ext in choice.Extensions
                               where !string.IsNullOrEmpty( ext )
                               select ext ).FirstOrDefault();

            // set the default file extension to the first entry with a non-null, non-empty value
            if ( !string.IsNullOrEmpty( defaultExt ) )
            {
                interaction.DefaultFileExtension = defaultExt;
            }

            interaction.FileTypeChoices.AddRange( fileTypeChoices );
            interactionRequest.Request( interaction );

            return source.Task;
        }

        /// <summary>
        /// Requests a select folder interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the selected <see cref="IFolder">folder</see> or <c>null</c> if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="SelectFolderInteraction">interaction</see> will always have the title "Select Folder" and will contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "Select" and "Cancel", respectively.</remarks>
        public static Task<IFolder> RequestAsync( this InteractionRequest<SelectFolderInteraction> interactionRequest ) => interactionRequest.RequestAsync( null, null, null, null );

        /// <summary>
        /// Requests a select folder interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="initialFolder">The initial <see cref="IFolder">folder</see> to select.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the selected <see cref="IFolder">folder</see> or <c>null</c> if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="SelectFolderInteraction">interaction</see> will always have the title "Select Folder" and will contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "Select" and "Cancel", respectively.</remarks>
        public static Task<IFolder> RequestAsync( this InteractionRequest<SelectFolderInteraction> interactionRequest, IFolder initialFolder ) =>
            interactionRequest.RequestAsync( initialFolder, null, null, null );

        /// <summary>
        /// Requests a select folder interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The interaction title.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the selected <see cref="IFolder">folder</see> or <c>null</c> if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="SelectFolderInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "Select" and "Cancel", respectively.</remarks>
        public static Task<IFolder> RequestAsync( this InteractionRequest<SelectFolderInteraction> interactionRequest, string title ) => interactionRequest.RequestAsync( null, title, null, null );

        /// <summary>
        /// Requests a select folder interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="initialFolder">The initial <see cref="IFolder">folder</see> to select.</param>
        /// <param name="title">The interaction title.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the selected <see cref="IFolder">folder</see> or <c>null</c> if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="SelectFolderInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "Select" and "Cancel", respectively.</remarks>
        public static Task<IFolder> RequestAsync( this InteractionRequest<SelectFolderInteraction> interactionRequest, IFolder initialFolder, string title ) =>
            interactionRequest.RequestAsync( initialFolder, title, null, null );

        /// <summary>
        /// Requests a select folder interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The interaction title.</param>
        /// <param name="acceptButtonText">The text for the accept button. The default value is "Select".</param>
        /// <param name="cancelButtonText">The text for the cancel button. The default value is "Cancel".</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the selected <see cref="IFolder">folder</see> or <c>null</c> if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="SelectFolderInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see> with the
        /// identifiers "Select" and "Cancel".</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validated by a code contract." )]
        public static Task<IFolder> RequestAsync( this InteractionRequest<SelectFolderInteraction> interactionRequest, string title, string acceptButtonText, string cancelButtonText ) =>
            interactionRequest.RequestAsync( null, title, acceptButtonText, cancelButtonText );

        /// <summary>
        /// Requests a select folder interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="initialFolder">The initial <see cref="IFolder">folder</see> to select.</param>
        /// <param name="title">The interaction title.</param>
        /// <param name="acceptButtonText">The text for the accept button. The default value is "Select".</param>
        /// <param name="cancelButtonText">The text for the cancel button. The default value is "Cancel".</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the selected <see cref="IFolder">folder</see> or <c>null</c> if the operation was canceled.</returns>
        /// <remarks>The requested <see cref="SelectFolderInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see> with the
        /// identifiers "Select" and "Cancel".</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validated by a code contract." )]
        public static Task<IFolder> RequestAsync( this InteractionRequest<SelectFolderInteraction> interactionRequest, IFolder initialFolder, string title, string acceptButtonText, string cancelButtonText )
        {
            Arg.NotNull( interactionRequest, nameof( interactionRequest ) );
            Contract.Ensures( Contract.Result<Task<IFolder>>() != null );

            if ( string.IsNullOrEmpty( title ) )
            {
                title = SR.SelectFolderTitle;
            }

            if ( string.IsNullOrEmpty( acceptButtonText ) )
            {
                acceptButtonText = SR.Select;
            }

            if ( string.IsNullOrEmpty( cancelButtonText ) )
            {
                cancelButtonText = SR.Cancel;
            }

            var source = new TaskCompletionSource<IFolder>();
            SelectFolderInteraction interaction = null;

            interaction = new SelectFolderInteraction()
            {
                Title = title,
                DefaultCommandIndex = 0,
                CancelCommandIndex = 1,
                Folder = initialFolder,
                Commands =
                {
                    new NamedCommand<object>( "Select", acceptButtonText, p => source.TrySetResult( interaction.Folder ) ),
                    new NamedCommand<object>( "Cancel", cancelButtonText, p => source.TrySetResult( null ) ),
                },
            };

            interactionRequest.Request( interaction );
            return source.Task;
        }

        /// <summary>
        /// Requests a text input interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="prompt">The interaction prompt.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the text input provided by the user. If the
        /// user canceled the operation, the text will be <c>null</c>.</returns>
        /// <remarks>The requested <see cref="TextInputInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "OK" and "Cancel", respectively.</remarks>
        public static Task<string> RequestAsync( this InteractionRequest<TextInputInteraction> interactionRequest, string prompt ) =>
            interactionRequest.RequestAsync( null, prompt, null, null, null );

        /// <summary>
        /// Requests a text input interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The interaction title.</param>
        /// <param name="prompt">The interaction prompt.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the text input provided by the user. If the
        /// user canceled the operation, the text will be <c>null</c>.</returns>
        /// <remarks>The requested <see cref="TextInputInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "OK" and "Cancel", respectively.</remarks>
        public static Task<string> RequestAsync( this InteractionRequest<TextInputInteraction> interactionRequest, string title, string prompt ) =>
            interactionRequest.RequestAsync( title, prompt, null, null, null );

        /// <summary>
        /// Requests a text input interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The interaction title.</param>
        /// <param name="prompt">The interaction prompt.</param>
        /// <param name="defaultResponse">The default response. The default value is an empty string.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the text input provided by the user. If the
        /// user canceled the operation, the text will be <c>null</c>.</returns>
        /// <remarks>The requested <see cref="TextInputInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers and names "OK" and "Cancel", respectively.</remarks>
        public static Task<string> RequestAsync( this InteractionRequest<TextInputInteraction> interactionRequest, string title, string prompt, string defaultResponse ) =>
            interactionRequest.RequestAsync( title, prompt, defaultResponse, null, null );

        /// <summary>
        /// Requests a text input interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="title">The interaction title.</param>
        /// <param name="prompt">The interaction prompt.</param>
        /// <param name="defaultResponse">The default response. The default value is an empty string.</param>
        /// <param name="acceptButtonText">The text for the accept button. The default value is "OK".</param>
        /// <param name="cancelButtonText">The text for the cancel button. The default value is "Cancel".</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing the text input provided by the user. If the
        /// user canceled the operation, the text will be <c>null</c>.</returns>
        [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validated by a code contract." )]
        public static Task<string> RequestAsync( this InteractionRequest<TextInputInteraction> interactionRequest, string title, string prompt, string defaultResponse, string acceptButtonText, string cancelButtonText )
        {
            Arg.NotNull( interactionRequest, nameof( interactionRequest ) );
            Arg.NotNullOrEmpty( prompt, nameof( prompt ) );
            Contract.Ensures( Contract.Result<Task<string>>() != null );

            if ( string.IsNullOrEmpty( acceptButtonText ) )
            {
                acceptButtonText = SR.OK;
            }

            if ( string.IsNullOrEmpty( cancelButtonText ) )
            {
                cancelButtonText = SR.Cancel;
            }

            var source = new TaskCompletionSource<string>();
            TextInputInteraction interaction = null;

            interaction = new TextInputInteraction( title ?? string.Empty, prompt, defaultResponse ?? string.Empty )
            {
                DefaultCommandIndex = 0,
                CancelCommandIndex = 1,
                Commands =
                {
                    new NamedCommand<object>( "OK", acceptButtonText, p => source.TrySetResult( interaction.Response ) ),
                    new NamedCommand<object>( "Cancel", cancelButtonText, p => source.TrySetResult( null ) ),
                },
            };

            interactionRequest.Request( interaction );
            return source.Task;
        }

        /// <summary>
        /// Requests a web authentication interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="requestUri">The starting Uniform Resource Identifier (URI) of the web service.</param>
        /// <param name="callbackUri">The callback <see cref="Uri">URI</see> that indicates the completion of the web authentication.
        /// The broker matches this <see cref="Uri">URI</see> against every <see cref="Uri">URI</see> that it is about to navigate to.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing a <see cref="IWebAuthenticationResult">authentication result</see>.</returns>
        /// <remarks>The requested <see cref="WebAuthenticateInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers "OK" and "Cancel".</remarks>
        public static Task<IWebAuthenticationResult> RequestAsync( this InteractionRequest<WebAuthenticateInteraction> interactionRequest, Uri requestUri, Uri callbackUri )
        {
            Arg.NotNull( interactionRequest, nameof( interactionRequest ) );
            Arg.NotNull( requestUri, nameof( requestUri ) );
            return interactionRequest.RequestAsync( new WebAuthenticateInteraction( requestUri ) { CallbackUri = callbackUri } );
        }

        /// <summary>
        /// Requests a web authentication interaction asynchronously.
        /// </summary>
        /// <param name="interactionRequest">The extended <see cref="InteractionRequest{T}">interaction request</see>.</param>
        /// <param name="interaction">The requested <see cref="WebAuthenticateInteraction">interaction</see>.</param>
        /// <returns>A <see cref="Task{TResult}">task</see> containing a <see cref="IWebAuthenticationResult">authentication result</see>.</returns>
        /// <remarks>The requested <see cref="WebAuthenticateInteraction">interaction</see> will always contain two <see cref="INamedCommand">commands</see>
        /// with the identifiers "OK" and "Cancel". If the specified <paramref name="interaction"/> has any commands predefined, they will be cleared.</remarks>
        [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validated a code contract." )]
        [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validated a code contract." )]
        public static Task<IWebAuthenticationResult> RequestAsync( this InteractionRequest<WebAuthenticateInteraction> interactionRequest, WebAuthenticateInteraction interaction )
        {
            Arg.NotNull( interactionRequest, nameof( interactionRequest ) );
            Arg.NotNull( interaction, nameof( interaction ) );

            var source = new TaskCompletionSource<IWebAuthenticationResult>();

            interaction.Commands.Clear();
            interaction.Commands.Add( new NamedCommand<IWebAuthenticationResult>( "OK", p => source.TrySetResult( p ) ) );
            interaction.Commands.Add( new NamedCommand<IWebAuthenticationResult>( "Cancel", p => source.TrySetResult( p ) ) );

            if ( interaction.DefaultCommandIndex < 0 || interaction.DefaultCommandIndex > 1 )
            {
                interaction.DefaultCommandIndex = 0;
            }

            if ( interaction.CancelCommandIndex < 0 || interaction.CancelCommandIndex > 1 )
            {
                interaction.CancelCommandIndex = 1;
            }

            interactionRequest.Request( interaction );

            return source.Task;
        }
    }
}


text:
let _ = require('lodash');
let fs = require('fs');
let path = require('path');
let async = require('async');
let coffeeScript = require('coffeescript');
let uglify = require('uglify-es');
let {JSHINT} = require('jshint');
let less = require('less');
let css = require('./css');

let isScriptLocal = scriptName=> !scriptName.match(/^.*\/\//);
let isScriptRemote = scriptName=> !isScriptLocal(scriptName);

module.exports = {

  getFiles({configJson, appPath}, callback){
    let localFiles =  _.filter(configJson.javascript, isScriptLocal);
    let localCssFiles =  _.filter(configJson.css, isScriptLocal);
    return async.series({
      javascript_files: jsCallback=> {
        return this.getJavaScripts({appPath, scripts: localFiles, compress:true}, jsCallback);
      },
      uncompressed_javascript_files: jsCallback=> {
        return this.getJavaScripts({appPath, scripts: localFiles, compress:false}, jsCallback);
      },
      css_file_names: cssCallback=> {
        return cssCallback(null, _.map(localCssFiles, css.getGeneratedFileName));
      },
      css_files: cssCallback=> {
        return this.getStylesheets({appPath, scripts: localCssFiles, compress: true}, cssCallback);
      },
      uncompressed_css_files: cssCallback=> {
        return this.getStylesheets({appPath, scripts: localCssFiles, compress: false}, cssCallback);
      },
      remote_css_files: remoteCssFilesCallback => {
        return remoteCssFilesCallback(null, _.filter(configJson.css, isScriptRemote));
      },
      remote_javascript_files: remoteJsFilesCallback=> {
        return remoteJsFilesCallback(null, _.filter(configJson.javascript, isScriptRemote));
      },
      local_javascript_files: localJsFilesCallback=> {
        return localJsFilesCallback(null, localFiles);
      },
      html_files: htmlFilesCallback=> {
        return this.getScripts({appPath, scripts: configJson.html}, htmlFilesCallback);
      }
    },
      callback);
  },

  getJavaScripts({appPath, scripts, compress}, callback) {
    let jshintrc = path.resolve(appPath, '.jshintrc');
    return this.readFile(jshintrc, (e, jshintConfig) => {
      let jshintOptions = JSON.parse(jshintConfig || "{}");
      return this.getScripts({appPath, scripts}, (err, results) => {
        if (err) { return callback(err);
        } else {
          for (let key in results) {
            let code = results[key];
            let fileName = scripts[key];
            if (!compress) { this.hintJavaScriptFile(code, jshintOptions, fileName); }
            if (compress) {
              try {
                results[key] = this.compressJavaScript(code);
              } catch (e) {
                console.error(`\r\nError in ${fileName} on line ${e.line}:`);
                console.error(e.message);
                callback(e);
                return;
              }
            } else {
              results[key] = code;
            }
          }
          return callback(null, results);
        }
      });
    });
  },

  getStylesheets({appPath, scripts, compress}, callback){
    return this.getScripts({appPath, scripts}, (err, results) => {
      if (err) { return callback(err);
      } else {
        return async.map(results, (cssCode, cb) => css.compile(cssCode, compress, cb)
        , callback);
      }
    });
  },

  getScripts({appPath, scripts, compress}, callback){
    let fullPathScripts = [];
    for (let script of Array.from(scripts || [])) {
      fullPathScripts.push(path.resolve(appPath, script));
    }
    return async.map(fullPathScripts, this.readFile, callback);
  },

  compressJavaScript(code){
    return uglify.minify(code).code;
  },

  readFile: (file, callback)=> {
    let wrapper = function(error, fileContents){
      if (error) {
        error = new Error(`${file} could not be loaded. Is the path correct?`);
      }
      if (file.match(/.coffee$/)) {
        fileContents = coffeeScript.compile(fileContents);
      }
      return callback(error, fileContents);
    };
    return fs.readFile(file, "utf-8", wrapper);
  },

  hintJavaScriptFile(code, jshintOptions, fileName) {
    if(!JSHINT(code, jshintOptions)) {
      console.error();
      for (let error of Array.from(JSHINT.errors)) {
        if (!!error) { console.error(`Error in ${fileName} on line ${error.line}: ${error.reason}`); }
      }
      return console.error();
    }
  }
};


text:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Persistence;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement;
using Umbraco.Cms.Infrastructure.Scoping;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Extensions;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
using Constants = Umbraco.Cms.Core.Constants;
using Content = Umbraco.Cms.Core.Models.Content;

using IScopeProvider = Umbraco.Cms.Infrastructure.Scoping.IScopeProvider;
using IScope = Umbraco.Cms.Infrastructure.Scoping.IScope;

namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories
{
    [TestFixture]
    [UmbracoTest(Mapper = true, Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
    public class ContentTypeRepositoryTest : UmbracoIntegrationTest
    {
        private ContentType _simpleContentType;
        private ContentType _textpageContentType;

        private FileSystems FileSystems => GetRequiredService<FileSystems>();

        private IUmbracoMapper Mapper => GetRequiredService<IUmbracoMapper>();

        private IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();

        private IDocumentTypeContainerRepository DocumentTypeContainerRepository => GetRequiredService<IDocumentTypeContainerRepository>();

        private IMediaTypeContainerRepository MediaTypeContainerRepository => GetRequiredService<IMediaTypeContainerRepository>();

        private IMediaTypeRepository MediaTypeRepository => GetRequiredService<IMediaTypeRepository>();

        private IDocumentRepository DocumentRepository => GetRequiredService<IDocumentRepository>();
        private IContentService ContentService => GetRequiredService<IContentService>();

        private ContentTypeRepository ContentTypeRepository => (ContentTypeRepository)GetRequiredService<IContentTypeRepository>();

        [SetUp]
        public void SetUpData() => CreateTestData();

        public void CreateTestData()
        {
            // Create and Save ContentType "umbTextpage" -> (_simpleContentType.Id)
            _simpleContentType = ContentTypeBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateId: 0);

            ContentTypeService.Save(_simpleContentType);

            // Create and Save ContentType "textPage" -> (_textpageContentType.Id)
            _textpageContentType = ContentTypeBuilder.CreateTextPageContentType(defaultTemplateId: 0);
            ContentTypeService.Save(_textpageContentType);
        }

        // TODO: Add test to verify SetDefaultTemplates updates both AllowedTemplates and DefaultTemplate(id).

        [Test]
        public void Maps_Templates_Correctly()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                var templateRepo = new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper, Mock.Of<IViewHelper>());
                ContentTypeRepository repository = ContentTypeRepository;
                Template[] templates = new[]
                {
                    new Template(ShortStringHelper, "test1", "test1"),
                    new Template(ShortStringHelper, "test2", "test2"),
                    new Template(ShortStringHelper, "test3", "test3")
                };
                foreach (Template template in templates)
                {
                    templateRepo.Save(template);
                }

                ContentType contentType = ContentTypeBuilder.CreateSimpleContentType();
                contentType.AllowedTemplates = new[] { templates[0], templates[1] };
                contentType.SetDefaultTemplate(templates[0]);
                repository.Save(contentType);

                // re-get
                IContentType result = repository.Get(contentType.Id);

                Assert.AreEqual(2, result.AllowedTemplates.Count());
                Assert.AreEqual(templates[0].Id, result.DefaultTemplate.Id);
            }
        }

        [Test]
        public void Can_Move()
        {
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;
                var container1 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah1" };
                DocumentTypeContainerRepository.Save(container1);

                var container2 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah2", ParentId = container1.Id };
                DocumentTypeContainerRepository.Save(container2);

                var contentType = (IContentType)ContentTypeBuilder.CreateBasicContentType("asdfasdf");
                contentType.ParentId = container2.Id;
                repository.Save(contentType);

                // create a
                var contentType2 = (IContentType)new ContentType(ShortStringHelper, contentType, "hello")
                {
                    Name = "Blahasdfsadf"
                };
                contentType.ParentId = contentType.Id;
                repository.Save(contentType2);

                global::Umbraco.Cms.Core.Events.MoveEventInfo<IContentType>[] result = repository.Move(contentType, container1).ToArray();

                Assert.AreEqual(2, result.Count());

                // re-get
                contentType = repository.Get(contentType.Id);
                contentType2 = repository.Get(contentType2.Id);

                Assert.AreEqual(container1.Id, contentType.ParentId);
                Assert.AreNotEqual(result.Single(x => x.Entity.Id == contentType.Id).OriginalPath, contentType.Path);
                Assert.AreNotEqual(result.Single(x => x.Entity.Id == contentType2.Id).OriginalPath, contentType2.Path);
            }
        }

        [Test]
        public void Can_Create_Container()
        {
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                var container = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah" };
                DocumentTypeContainerRepository.Save(container);

                Assert.That(container.Id, Is.GreaterThan(0));

                EntityContainer found = DocumentTypeContainerRepository.Get(container.Id);
                Assert.IsNotNull(found);
            }
        }

        [Test]
        public void Can_Get_All_Containers()
        {
            EntityContainer container1, container2, container3;

            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                container1 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "container1" };
                DocumentTypeContainerRepository.Save(container1);
                container2 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "container2" };
                DocumentTypeContainerRepository.Save(container2);
                container3 = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "container3" };
                DocumentTypeContainerRepository.Save(container3);

                Assert.That(container1.Id, Is.GreaterThan(0));
                Assert.That(container2.Id, Is.GreaterThan(0));
                Assert.That(container3.Id, Is.GreaterThan(0));

                EntityContainer found1 = DocumentTypeContainerRepository.Get(container1.Id);
                Assert.IsNotNull(found1);
                EntityContainer found2 = DocumentTypeContainerRepository.Get(container2.Id);
                Assert.IsNotNull(found2);
                EntityContainer found3 = DocumentTypeContainerRepository.Get(container3.Id);
                Assert.IsNotNull(found3);
                IEnumerable<EntityContainer> allContainers = DocumentTypeContainerRepository.GetMany();
                Assert.AreEqual(3, allContainers.Count());
            }
        }

        [Test]
        public void Can_Delete_Container()
        {
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                var container = new EntityContainer(Constants.ObjectTypes.DocumentType) { Name = "blah" };
                DocumentTypeContainerRepository.Save(container);

                // Act
                DocumentTypeContainerRepository.Delete(container);

                EntityContainer found = DocumentTypeContainerRepository.Get(container.Id);
                Assert.IsNull(found);
            }
        }

        [Test]
        public void Can_Create_Container_Containing_Media_Types()
        {
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;
                var container = new EntityContainer(Constants.ObjectTypes.MediaType) { Name = "blah" };
                MediaTypeContainerRepository.Save(container);

                ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("test", "Test", propertyGroupAlias: "testGroup", propertyGroupName: "testGroup", defaultTemplateId: 0);
                contentType.ParentId = container.Id;
                repository.Save(contentType);

                Assert.AreEqual(container.Id, contentType.ParentId);
            }
        }

        [Test]
        public void Can_Delete_Container_Containing_Media_Types()
        {
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                var container = new EntityContainer(Constants.ObjectTypes.MediaType) { Name = "blah" };
                MediaTypeContainerRepository.Save(container);

                IMediaType contentType = MediaTypeBuilder.CreateSimpleMediaType("test", "Test", propertyGroupAlias: "testGroup", propertyGroupName: "testGroup");
                contentType.ParentId = container.Id;
                MediaTypeRepository.Save(contentType);

                // Act
                MediaTypeContainerRepository.Delete(container);

                EntityContainer found = MediaTypeContainerRepository.Get(container.Id);
                Assert.IsNull(found);

                contentType = MediaTypeRepository.Get(contentType.Id);
                Assert.IsNotNull(contentType);
                Assert.AreEqual(-1, contentType.ParentId);
            }
        }

        [Test]
        public void Can_Perform_Add_On_ContentTypeRepository()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                // Act
                ContentType contentType = ContentTypeBuilder.CreateSimpleContentType("test", "Test", propertyGroupAlias: "testGroup", propertyGroupName: "testGroup");
                ContentTypeRepository.Save(contentType);

                IContentType fetched = ContentTypeRepository.Get(contentType.Id);

                // Assert
                Assert.That(contentType.HasIdentity, Is.True);
                Assert.That(contentType.PropertyGroups.All(x => x.HasIdentity), Is.True);
                Assert.That(contentType.PropertyTypes.All(x => x.HasIdentity), Is.True);
                Assert.That(contentType.Path.Contains(","), Is.True);
                Assert.That(contentType.SortOrder, Is.GreaterThan(0));

                Assert.That(contentType.PropertyGroups.ElementAt(0).Name == "testGroup", Is.True);
                int groupId = contentType.PropertyGroups.ElementAt(0).Id;
                Assert.That(contentType.PropertyTypes.All(x => x.PropertyGroupId.Value == groupId), Is.True);

                foreach (IPropertyType propertyType in contentType.PropertyTypes)
                {
                    Assert.AreNotEqual(propertyType.Key, Guid.Empty);
                }

                TestHelper.AssertPropertyValuesAreEqual(fetched, contentType, ignoreProperties: new[] { "DefaultTemplate", "AllowedTemplates", "UpdateDate", "HistoryCleanup" });
            }
        }

        [Test]
        public void Can_Perform_Add_On_ContentTypeRepository_After_Model_Mapping()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                // Act
                var contentType = (IContentType)ContentTypeBuilder.CreateSimpleContentType2("test", "Test", propertyGroupAlias: "testGroup", propertyGroupName: "testGroup");

                Assert.AreEqual(4, contentType.PropertyTypes.Count());

                // remove all templates - since they are not saved, they would break the (!) mapping code
                contentType.AllowedTemplates = new ITemplate[0];

                // there is NO mapping from display to contentType, but only from save
                // to contentType, so if we want to test, let's to it properly!
                DocumentTypeDisplay display = Mapper.Map<DocumentTypeDisplay>(contentType);
                DocumentTypeSave save = MapToContentTypeSave(display);
                IContentType mapped = Mapper.Map<IContentType>(save);

                Assert.AreEqual(4, mapped.PropertyTypes.Count());

                repository.Save(mapped);

                Assert.AreEqual(4, mapped.PropertyTypes.Count());

                // re-get
                contentType = repository.Get(mapped.Id);

                Assert.AreEqual(4, contentType.PropertyTypes.Count());

                // Assert
                Assert.That(contentType.HasIdentity, Is.True);
                Assert.That(contentType.PropertyGroups.All(x => x.HasIdentity), Is.True);
                Assert.That(contentType.PropertyTypes.All(x => x.HasIdentity), Is.True);
                Assert.That(contentType.Path.Contains(","), Is.True);
                Assert.That(contentType.SortOrder, Is.GreaterThan(0));

                Assert.That(contentType.PropertyGroups.ElementAt(0).Name == "testGroup", Is.True);
                int groupId = contentType.PropertyGroups.ElementAt(0).Id;

                IPropertyType[] propertyTypes = contentType.PropertyTypes.ToArray();
                Assert.AreEqual("gen", propertyTypes[0].Alias); // just to be sure
                Assert.IsNull(propertyTypes[0].PropertyGroupId);
                Assert.IsTrue(propertyTypes.Skip(1).All(x => x.PropertyGroupId.Value == groupId));
                Assert.That(propertyTypes.Single(x => x.Alias == "title").LabelOnTop, Is.True);
            }
        }

        [Test]
        public void Can_Perform_Update_On_ContentTypeRepository()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                // Act
                IContentType contentType = repository.Get(_textpageContentType.Id);

                contentType.Thumbnail = "Doc2.png";
                contentType.PropertyGroups["content"].PropertyTypes.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "subtitle")
                {
                    Name = "Subtitle",
                    Description = "Optional Subtitle",
                    Mandatory = false,
                    SortOrder = 1,
                    DataTypeId = -88,
                    LabelOnTop = true
                });
                repository.Save(contentType);

                bool dirty = contentType.IsDirty();

                // Assert
                Assert.That(contentType.HasIdentity, Is.True);
                Assert.That(dirty, Is.False);
                Assert.That(contentType.Thumbnail, Is.EqualTo("Doc2.png"));
                Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "subtitle"), Is.True);
                Assert.That(contentType.PropertyTypes.Single(x => x.Alias == "subtitle").LabelOnTop, Is.True);
            }
        }

        // this is for tests only because it makes no sense at all to have such a
        // mapping defined, we only need it for the weird tests that use it
        private DocumentTypeSave MapToContentTypeSave(DocumentTypeDisplay display) =>
            new DocumentTypeSave
            {
                // EntityBasic
                Name = display.Name,
                Icon = display.Icon,
                Trashed = display.Trashed,
                Key = display.Key,
                ParentId = display.ParentId,
                //// Alias = display.Alias,
                Path = display.Path,
                //// AdditionalData = display.AdditionalData,
                HistoryCleanup = display.HistoryCleanup,

                // ContentTypeBasic
                Alias = display.Alias,
                UpdateDate = display.UpdateDate,
                CreateDate = display.CreateDate,
                Description = display.Description,
                Thumbnail = display.Thumbnail,

                // ContentTypeSave
                CompositeContentTypes = display.CompositeContentTypes,
                IsContainer = display.IsContainer,
                AllowAsRoot = display.AllowAsRoot,
                AllowedTemplates = display.AllowedTemplates.Select(x => x.Alias),
                AllowedContentTypes = display.AllowedContentTypes,
                DefaultTemplate = display.DefaultTemplate?.Alias,
                Groups = display.Groups.Select(x => new PropertyGroupBasic<PropertyTypeBasic>
                {
                    Inherited = x.Inherited,
                    Id = x.Id,
                    Key = x.Key,
                    Type = x.Type,
                    Name = x.Name,
                    Alias = x.Alias,
                    SortOrder = x.SortOrder,
                    Properties = x.Properties
                }).ToArray()
            };

        [Test]
        public void Can_Perform_Update_On_ContentTypeRepository_After_Model_Mapping()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                // Act
                IContentType contentType = repository.Get(_textpageContentType.Id);

                // there is NO mapping from display to contentType, but only from save
                // to contentType, so if we want to test, let's to it properly!
                DocumentTypeDisplay display = Mapper.Map<DocumentTypeDisplay>(contentType);
                DocumentTypeSave save = MapToContentTypeSave(display);

                // modify...
                save.Thumbnail = "Doc2.png";
                PropertyGroupBasic<PropertyTypeBasic> contentGroup = save.Groups.Single(x => x.Name == "Content");
                contentGroup.Properties = contentGroup.Properties.Concat(new[]
                {
                    new PropertyTypeBasic
                    {
                        Alias = "subtitle",
                        Label = "Subtitle",
                        Description = "Optional Subtitle",
                        Validation = new PropertyTypeValidation
                        {
                            Mandatory = false,
                            Pattern = string.Empty
                        },
                        SortOrder = 1,
                        DataTypeId = -88,
                        LabelOnTop = true
                    }
                });

                IContentType mapped = Mapper.Map(save, contentType);

                // just making sure
                Assert.AreEqual(mapped.Thumbnail, "Doc2.png");
                Assert.IsTrue(mapped.PropertyTypes.Any(x => x.Alias == "subtitle"));
                Assert.IsTrue(mapped.PropertyTypes.Single(x => x.Alias == "subtitle").LabelOnTop);

                repository.Save(mapped);

                bool dirty = mapped.IsDirty();

                // re-get
                contentType = repository.Get(_textpageContentType.Id);

                // Assert
                Assert.That(contentType.HasIdentity, Is.True);
                Assert.That(dirty, Is.False);
                Assert.That(contentType.Thumbnail, Is.EqualTo("Doc2.png"));
                Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "subtitle"), Is.True);

                Assert.That(contentType.PropertyTypes.Single(x => x.Alias == "subtitle").LabelOnTop, Is.True);

                foreach (IPropertyType propertyType in contentType.PropertyTypes)
                {
                    Assert.IsTrue(propertyType.HasIdentity);
                    Assert.Greater(propertyType.Id, 0);
                }
            }
        }

        [Test]
        public void Can_Perform_Delete_On_ContentTypeRepository()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                // Act
                ContentType contentType = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: 0);
                repository.Save(contentType);

                IContentType contentType2 = repository.Get(contentType.Id);
                repository.Delete(contentType2);

                bool exists = repository.Exists(contentType.Id);

                // Assert
                Assert.That(exists, Is.False);
            }
        }

        [Test]
        public void Can_Perform_Delete_With_Heirarchy_On_ContentTypeRepository()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;
                ContentType ctMain = ContentTypeBuilder.CreateSimpleContentType(defaultTemplateId: 0);
                ContentType ctChild1 = ContentTypeBuilder.CreateSimpleContentType("child1", "Child 1", ctMain, randomizeAliases: true, defaultTemplateId: 0);
                ContentType ctChild2 = ContentTypeBuilder.CreateSimpleContentType("child2", "Child 2", ctChild1, randomizeAliases: true, defaultTemplateId: 0);

                repository.Save(ctMain);
                repository.Save(ctChild1);
                repository.Save(ctChild2);

                // Act
                IContentType resolvedParent = repository.Get(ctMain.Id);
                repository.Delete(resolvedParent);

                // Assert
                Assert.That(repository.Exists(ctMain.Id), Is.False);
                Assert.That(repository.Exists(ctChild1.Id), Is.False);
                Assert.That(repository.Exists(ctChild2.Id), Is.False);
            }
        }

        [Test]
        public void Can_Perform_Query_On_ContentTypeRepository_Sort_By_Name()
        {
            IContentType contentType;

            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;
                contentType = repository.Get(_textpageContentType.Id);
                ContentType child1 = ContentTypeBuilder.CreateSimpleContentType("abc", "abc", contentType, randomizeAliases: true, defaultTemplateId: 0);
                repository.Save(child1);
                ContentType child3 = ContentTypeBuilder.CreateSimpleContentType("zyx", "zyx", contentType, randomizeAliases: true, defaultTemplateId: 0);
                repository.Save(child3);
                ContentType child2 = ContentTypeBuilder.CreateSimpleContentType("a123", "a123", contentType, randomizeAliases: true, defaultTemplateId: 0);
                repository.Save(child2);

                scope.Complete();
            }

            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                // Act
                IEnumerable<IContentType> contentTypes = repository.Get(provider.CreateQuery<IContentType>().Where(x => x.ParentId == contentType.Id));

                // Assert
                Assert.That(contentTypes.Count(), Is.EqualTo(3));
                Assert.AreEqual("a123", contentTypes.ElementAt(0).Name);
                Assert.AreEqual("abc", contentTypes.ElementAt(1).Name);
                Assert.AreEqual("zyx", contentTypes.ElementAt(2).Name);
            }
        }

        [Test]
        public void Can_Perform_Get_On_ContentTypeRepository()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                // Act
                IContentType contentType = repository.Get(_textpageContentType.Id);

                // Assert
                Assert.That(contentType, Is.Not.Null);
                Assert.That(contentType.Id, Is.EqualTo(_textpageContentType.Id));
            }
        }

        [Test]
        public void Can_Perform_Get_By_Guid_On_ContentTypeRepository()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;
                IContentType contentType = repository.Get(_textpageContentType.Id);
                ContentType childContentType = ContentTypeBuilder.CreateSimpleContentType("blah", "Blah", contentType, randomizeAliases: true, defaultTemplateId: 0);
                repository.Save(childContentType);

                // Act
                IContentType result = repository.Get(childContentType.Key);

                // Assert
                Assert.That(result, Is.Not.Null);
                Assert.That(result.Id, Is.EqualTo(childContentType.Id));
            }
        }

        [Test]
        public void Can_Perform_Get_By_Missing_Guid_On_ContentTypeRepository()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                // Act
                IContentType result = repository.Get(Guid.NewGuid());

                // Assert
                Assert.That(result, Is.Null);
            }
        }

        [Test]
        public void Can_Perform_GetAll_On_ContentTypeRepository()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                var repository = (ContentTypeRepository)ContentTypeRepository;

                // Act
                IEnumerable<IContentType> contentTypes = repository.GetMany();
                int count =
                    ScopeAccessor.AmbientScope.Database.ExecuteScalar<int>(
                        "SELECT COUNT(*) FROM umbracoNode WHERE nodeObjectType = @NodeObjectType",
                        new { NodeObjectType = Constants.ObjectTypes.DocumentType });

                // Assert
                Assert.That(contentTypes.Any(), Is.True);
                Assert.That(contentTypes.Count(), Is.EqualTo(count));
            }
        }

        [Test]
        public void Can_Perform_GetAll_By_Guid_On_ContentTypeRepository()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                var repository = (ContentTypeRepository)ContentTypeRepository;
                Guid[] allGuidIds = repository.GetMany().Select(x => x.Key).ToArray();

                // Act
                IEnumerable<IContentType> contentTypes = ((IReadRepository<Guid, IContentType>)repository).GetMany(allGuidIds);
                int count =
                    ScopeAccessor.AmbientScope.Database.ExecuteScalar<int>(
                        "SELECT COUNT(*) FROM umbracoNode WHERE nodeObjectType = @NodeObjectType",
                        new { NodeObjectType = Constants.ObjectTypes.DocumentType });

                // Assert
                Assert.That(contentTypes.Any(), Is.True);
                Assert.That(contentTypes.Count(), Is.EqualTo(count));
            }
        }

        [Test]
        public void Can_Perform_Exists_On_ContentTypeRepository()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                // Act
                bool exists = repository.Exists(_simpleContentType.Id);

                // Assert
                Assert.That(exists, Is.True);
            }
        }

        [Test]
        public void Can_Update_ContentType_With_PropertyType_Removed()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;
                IContentType contentType = repository.Get(_textpageContentType.Id);

                // Act
                contentType.PropertyGroups["meta"].PropertyTypes.Remove("description");
                repository.Save(contentType);

                IContentType result = repository.Get(_textpageContentType.Id);

                // Assert
                Assert.That(result.PropertyTypes.Any(x => x.Alias == "description"), Is.False);
                Assert.That(contentType.PropertyGroups.Count, Is.EqualTo(result.PropertyGroups.Count));
                Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(result.PropertyTypes.Count()));
            }
        }

        [Test]
        public void Can_Verify_PropertyTypes_On_SimpleTextpage()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                // Act
                IContentType contentType = repository.Get(_simpleContentType.Id);

                // Assert
                Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(3));
                Assert.That(contentType.PropertyGroups.Count(), Is.EqualTo(1));
            }
        }

        [Test]
        public void Can_Verify_PropertyTypes_On_Textpage()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                // Act
                IContentType contentType = repository.Get(_textpageContentType.Id);

                // Assert
                Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(4));
                Assert.That(contentType.PropertyGroups.Count(), Is.EqualTo(2));
            }
        }

        [Test]
        public void Can_Verify_PropertyType_With_No_Group()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;
                IContentType contentType = repository.Get(_textpageContentType.Id);

                Assert.That(contentType.PropertyGroups.Count, Is.EqualTo(2));
                Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(4));

                // Act
                var urlAlias = new PropertyType(ShortStringHelper, "test", ValueStorageType.Nvarchar, "urlAlias")
                    {
                        Name = "Url Alias",
                        Description = string.Empty,
                        Mandatory = false,
                        SortOrder = 1,
                        DataTypeId = -88
                    };

                bool addedPropertyType = contentType.AddPropertyType(urlAlias);

                Assert.That(contentType.PropertyGroups.Count, Is.EqualTo(2));
                Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(5));

                repository.Save(contentType);

                // Assert
                IContentType updated = repository.Get(_textpageContentType.Id);
                Assert.That(addedPropertyType, Is.True);
                Assert.That(updated.PropertyGroups.Count, Is.EqualTo(2));
                Assert.That(updated.PropertyTypes.Count(), Is.EqualTo(5));
                Assert.That(updated.PropertyTypes.Any(x => x.Alias == "urlAlias"), Is.True);
                Assert.That(updated.PropertyTypes.First(x => x.Alias == "urlAlias").PropertyGroupId, Is.Null);
            }
        }

        [Test]
        public void Can_Verify_AllowedChildContentTypes_On_ContentType()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                ContentType subpageContentType = ContentTypeBuilder.CreateSimpleContentType("umbSubpage", "Subpage");
                ContentType simpleSubpageContentType = ContentTypeBuilder.CreateSimpleContentType("umbSimpleSubpage", "Simple Subpage");
                repository.Save(subpageContentType);
                repository.Save(simpleSubpageContentType);

                // Act
                IContentType contentType = repository.Get(_simpleContentType.Id);
                contentType.AllowedContentTypes = new List<ContentTypeSort>
                    {
                        new ContentTypeSort(new Lazy<int>(() => subpageContentType.Id), 0, subpageContentType.Alias),
                        new ContentTypeSort(new Lazy<int>(() => simpleSubpageContentType.Id), 1, simpleSubpageContentType.Alias)
                    };
                repository.Save(contentType);

                // Assert
                IContentType updated = repository.Get(_simpleContentType.Id);

                Assert.That(updated.AllowedContentTypes.Any(), Is.True);
                Assert.That(updated.AllowedContentTypes.Any(x => x.Alias == subpageContentType.Alias), Is.True);
                Assert.That(updated.AllowedContentTypes.Any(x => x.Alias == simpleSubpageContentType.Alias), Is.True);
            }
        }

        [Test]
        public void Can_Verify_Removal_Of_Used_PropertyType_From_ContentType()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;
                IContentType contentType = repository.Get(_textpageContentType.Id);

                Content subpage = ContentBuilder.CreateTextpageContent(contentType, "Text Page 1", contentType.Id);
                DocumentRepository.Save(subpage);

                // Act
                contentType.RemovePropertyType("keywords");
                repository.Save(contentType);

                // Assert
                Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(3));
                Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "keywords"), Is.False);
                Assert.That(subpage.Properties.First(x => x.Alias == "description").GetValue(), Is.EqualTo("This is the meta description for a textpage"));
            }
        }

        [Test]
        public void Can_Verify_Addition_Of_PropertyType_After_ContentType_Is_Used()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;
                IContentType contentType = repository.Get(_textpageContentType.Id);

                Content subpage = ContentBuilder.CreateTextpageContent(contentType, "Text Page 1", contentType.Id);
                DocumentRepository.Save(subpage);

                // Act
                PropertyGroup propertyGroup = contentType.PropertyGroups.First(x => x.Name == "Meta");
                propertyGroup.PropertyTypes.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "metaAuthor") { Name = "Meta Author", Description = string.Empty, Mandatory = false, SortOrder = 1, DataTypeId = -88 });
                repository.Save(contentType);

                // Assert
                Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(5));
                Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "metaAuthor"), Is.True);
            }
        }

        [Test]
        public void Can_Verify_Usage_Of_New_PropertyType_On_Content()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                IContentType contentType = repository.Get(_textpageContentType.Id);

                Content subpage = ContentBuilder.CreateTextpageContent(contentType, "Text Page 1", contentType.Id);
                DocumentRepository.Save(subpage);

                PropertyGroup propertyGroup = contentType.PropertyGroups.First(x => x.Name == "Meta");
                propertyGroup.PropertyTypes.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "metaAuthor") { Name = "Meta Author", Description = string.Empty, Mandatory = false, SortOrder = 1, DataTypeId = -88 });
                repository.Save(contentType);

                // Act
                IContent content = DocumentRepository.Get(subpage.Id);
                content.SetValue("metaAuthor", "John Doe");
                DocumentRepository.Save(content);

                // Assert
                IContent updated = DocumentRepository.Get(subpage.Id);
                Assert.That(updated.GetValue("metaAuthor").ToString(), Is.EqualTo("John Doe"));
                Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(5));
                Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "metaAuthor"), Is.True);
            }
        }

        [Test]
        public void Can_Verify_That_A_Combination_Of_Adding_And_Deleting_PropertyTypes_Doesnt_Cause_Issues_For_Content_And_ContentType()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                IContentType contentType = repository.Get(_textpageContentType.Id);

                Content subpage = ContentBuilder.CreateTextpageContent(contentType, "Text Page 1", contentType.Id);
                DocumentRepository.Save(subpage);

                // Remove PropertyType
                contentType.RemovePropertyType("keywords");

                // Add PropertyType
                PropertyGroup propertyGroup = contentType.PropertyGroups.First(x => x.Name == "Meta");
                propertyGroup.PropertyTypes.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext, "metaAuthor") { Name = "Meta Author", Description = string.Empty,  Mandatory = false, SortOrder = 1, DataTypeId = -88 });
                repository.Save(contentType);

                // Act
                IContent content = DocumentRepository.Get(subpage.Id);
                content.SetValue("metaAuthor", "John Doe");
                DocumentRepository.Save(content);

                // Assert
                IContent updated = DocumentRepository.Get(subpage.Id);
                Assert.That(updated.GetValue("metaAuthor").ToString(), Is.EqualTo("John Doe"));
                Assert.That(updated.Properties.First(x => x.Alias == "description").GetValue(), Is.EqualTo("This is the meta description for a textpage"));

                Assert.That(contentType.PropertyTypes.Count(), Is.EqualTo(4));
                Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "metaAuthor"), Is.True);
                Assert.That(contentType.PropertyTypes.Any(x => x.Alias == "keywords"), Is.False);
            }
        }

        [Test]
        public void Can_Verify_Content_Type_Has_Content_Nodes()
        {
            // Arrange
            IScopeProvider provider = ScopeProvider;
            using (IScope scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;

                int contentTypeId = _textpageContentType.Id;
                IContentType contentType = repository.Get(contentTypeId);

                // Act
                bool result = repository.HasContentNodes(contentTypeId);

                Content subpage = ContentBuilder.CreateTextpageContent(contentType, "Test Page 1", contentType.Id);
                DocumentRepository.Save(subpage);

                bool result2 = repository.HasContentNodes(contentTypeId);

                // Assert
                Assert.That(result, Is.False);
                Assert.That(result2, Is.True);
            }
        }

        [Test]
        public void Can_Update_Variation_Of_Element_Type_Property()
        {
            var provider = ScopeProvider;
            using (var scope = provider.CreateScope())
            {
                ContentTypeRepository repository = ContentTypeRepository;
                var contentRepository = DocumentRepository;

                // Create elementType
                var elementType = new ContentType(ShortStringHelper, -1)
                {
                    Alias = "elementType",
                    Name = "Element type",
                    Description = "Element type to use as compositions",
                    Icon = ".sprTreeDoc3",
                    Thumbnail = "doc.png",
                    SortOrder = 1,
                    CreatorId = 0,
                    Trashed = false,
                    IsElement = true,
                    Variations = ContentVariation.Nothing
                };

                var contentCollection = new PropertyTypeCollection(true);
                contentCollection.Add(new PropertyType(ShortStringHelper, "test", ValueStorageType.Ntext)
                {
                    Alias = "title",
                    Name = "Title",
                    Description = "",
                    Mandatory = false,
                    SortOrder = 1,
                    DataTypeId = Constants.DataTypes.Textbox,
                    LabelOnTop = true,
                    Variations = ContentVariation.Nothing
                });
                elementType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", Alias = "content", SortOrder = 1});
                elementType.ResetDirtyProperties(false);
                elementType.SetDefaultTemplate(new Template(ShortStringHelper, "ElementType", "elementType"));
                repository.Save(elementType);

                // Create the basic "home" doc type that uses element type as comp
                var docType = new ContentType(ShortStringHelper, -1)
                {
                    Alias = "home",
                    Name = "Home",
                    Description = "Home containing elementType",
                    Icon = ".sprTreeDoc3",
                    Thumbnail = "doc.png",
                    SortOrder = 1,
                    CreatorId = 0,
                    Trashed = false,
                    Variations = ContentVariation.Nothing
                };
                var comp = new List<IContentTypeComposition>();
                comp.Add(elementType);
                docType.ContentTypeComposition = comp;
                repository.Save(docType);

                // Create "home" content
                var content = new Content("Home", -1, docType){Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0};
                object obj = new {title = "test title"};
                content.PropertyValues(obj);
                content.ResetDirtyProperties(false);
                contentRepository.Save(content);

                // Update variation on element type
                elementType.Variations = ContentVariation.Culture;
                elementType.PropertyTypes.First().Variations = ContentVariation.Culture;
                repository.Save(elementType);

                // Update variation on doc type
                docType.Variations = ContentVariation.Culture;
                repository.Save(docType);

                // Re fetch renewedContent and make sure that the culture has been set.
                var renewedContent = ContentService.GetById(content.Id);
                var hasCulture = renewedContent.Properties["title"].Values.First().Culture != null;
                Assert.That(hasCulture, Is.True);
            }
        }
    }
}


text:
package org.hawkular.component.availcreator;

import static javax.ejb.TransactionAttributeType.NOT_SUPPORTED;

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

import javax.ejb.ActivationConfigProperty;
import javax.ejb.EJB;
import javax.ejb.MessageDriven;
import javax.ejb.TransactionAttribute;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * Receiver that listens on JMS Topic and checks for metrics *.status.code
 * Listening goes on 'java:/topic/HawkularMetricData'.
 * Then computes availability and forwards that to a topic for availability
 *
 * Requires this in standalone.xml:
 *
 *  <admin-object use-java-context="true"
 *      enabled="true"
 *      class-name="org.apache.activemq.command.ActiveMQTopic"
 *      jndi-name="java:/topic/HawkularAvailData"
 *      pool-name="HawkularAvailData">
 *            <config-property name="PhysicalName">HawkularAvailData</config-property>
 *  </admin-object>
 *
 * @author Heiko W. Rupp
 */
@MessageDriven(activationConfig = {
        @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
        @ActivationConfigProperty(propertyName = "destination", propertyValue = "HawkularMetricData")
})
@TransactionAttribute(value = NOT_SUPPORTED)
public class MetricReceiver implements MessageListener {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @EJB
    AvailPublisher availPublisher;

    @Override
    public void onMessage(Message message) {

        try {
            String payload = ((TextMessage) message).getText();
            JsonNode rootNode = objectMapper.readTree(payload);

            JsonNode metricData = rootNode.get("metricData");
            // Get <rid>.status.code  metrics
            String tenant = metricData.get("tenantId").textValue();
            JsonNode data = metricData.get("data");
            List<SingleAvail> outer = new ArrayList<>();

            Iterator<JsonNode> items = data.elements();
            while (items.hasNext()) {
                JsonNode item = items.next();

                String source = item.get("source").textValue();
                if (source.endsWith(".status.code")) {
                    int code = item.get("value").intValue();

                    String id = source.substring(0, source.indexOf("."));
                    long timestamp = item.get("timestamp").longValue();

                    String avail = computeAvail(code);

                    SingleAvail ar = new SingleAvail(tenant, id, timestamp, avail);
                    outer.add(ar);
                }
            }
            if (!outer.isEmpty()) {
                availPublisher.sendToMetricsViaRest(outer);
            }

        } catch (Exception e) {
            Log.LOG.eCouldNotHandleBusMessage(e);
        }

    }

    /**
     * Do the work of computing the availability from the status code
     * @param code Status code of the web request
     * @return "UP" or "DOWN" accordingly
     */
    private String computeAvail(int code) {
        if (code <= 399) {
            return "UP";
        }
        return "DOWN";
    }

}