text:
// Lucene version compatibility level 4.8.1
using J2N.Threading.Atomic;
using Lucene.Net.Analysis.TokenAttributes;
using Lucene.Net.Diagnostics;
using Lucene.Net.Index;
using Lucene.Net.Index.Extensions;
using Lucene.Net.Store;
using Lucene.Net.Support;
using Lucene.Net.Support.Threading;
using Lucene.Net.Util;
using System;
using System.Collections.Generic;
using System.IO;

namespace Lucene.Net.Facet.Taxonomy.Directory
{

    using AtomicReader = Lucene.Net.Index.AtomicReader;
    using AtomicReaderContext = Lucene.Net.Index.AtomicReaderContext;
    using BytesRef = Lucene.Net.Util.BytesRef;
    using Cl2oTaxonomyWriterCache = Lucene.Net.Facet.Taxonomy.WriterCache.Cl2oTaxonomyWriterCache;
    using CorruptIndexException = Lucene.Net.Index.CorruptIndexException; // javadocs
    using Directory = Lucene.Net.Store.Directory;
    using DirectoryReader = Lucene.Net.Index.DirectoryReader;
    using DocsEnum = Lucene.Net.Index.DocsEnum;
    using Document = Lucene.Net.Documents.Document;
    using Field = Lucene.Net.Documents.Field;
    using FieldType = Lucene.Net.Documents.FieldType;
    using IndexWriter = Lucene.Net.Index.IndexWriter;
    using IndexWriterConfig = Lucene.Net.Index.IndexWriterConfig;
    using ITaxonomyWriterCache = Lucene.Net.Facet.Taxonomy.WriterCache.ITaxonomyWriterCache;
    using LockObtainFailedException = Lucene.Net.Store.LockObtainFailedException; // javadocs
    using LogByteSizeMergePolicy = Lucene.Net.Index.LogByteSizeMergePolicy;
    using OpenMode = Lucene.Net.Index.OpenMode;
    using ReaderManager = Lucene.Net.Index.ReaderManager;
    using SegmentInfos = Lucene.Net.Index.SegmentInfos;
    using StringField = Lucene.Net.Documents.StringField;
    using Terms = Lucene.Net.Index.Terms;
    using TermsEnum = Lucene.Net.Index.TermsEnum;
    using TextField = Lucene.Net.Documents.TextField;
    using TieredMergePolicy = Lucene.Net.Index.TieredMergePolicy;
    using TokenStream = Lucene.Net.Analysis.TokenStream;

    ///
    /// <see cref="ITaxonomyWriter"/> which uses a <see cref="Store.Directory"/> to store the taxonomy
    /// information on disk, and keeps an additional in-memory cache of some or all
    /// categories.
    /// <para>
    /// In addition to the permanently-stored information in the <see cref="Store.Directory"/>,
    /// efficiency dictates that we also keep an in-memory cache of recently
    /// seen or all categories, so that we do not need to go back to disk
    /// for every category addition to see which ordinal this category already has,
    /// if any. A <see cref="ITaxonomyWriterCache"/> object determines the specific caching
    /// algorithm used.
    /// </para>
    /// <para>
    /// This class offers some hooks for extending classes to control the
    /// <see cref="IndexWriter"/> instance that is used. See <see cref="OpenIndexWriter"/>.
    ///
    /// @lucene.experimental
    /// </para>
    ///
    public class DirectoryTaxonomyWriter : ITaxonomyWriter
    {
        ///
        /// Property name of user commit data that contains the index epoch. The epoch
        /// changes whenever the taxonomy is recreated (i.e. opened with
        /// <see cref="OpenMode.CREATE"/>.
        /// <para>
        /// Applications should not use this property in their commit data because it
        /// will be overridden by this taxonomy writer.
        /// </para>
        ///
        public const string INDEX_EPOCH = "index.epoch";

        private readonly Directory dir;
        private readonly IndexWriter indexWriter;
        private readonly ITaxonomyWriterCache cache;
        private readonly AtomicInt32 cacheMisses = new AtomicInt32(0);

        // Records the taxonomy index epoch, updated on replaceTaxonomy as well.
        private long indexEpoch;

        private readonly SinglePositionTokenStream parentStream = new SinglePositionTokenStream(Consts.PAYLOAD_PARENT);
        private readonly Field parentStreamField;
        private readonly Field fullPathField;
        private int cacheMissesUntilFill = 11;
        private bool shouldFillCache = true;

        // even though lazily initialized, not volatile so that access to it is
        // faster. we keep a volatile boolean init instead.
        private ReaderManager readerManager;
        private volatile bool initializedReaderManager = false;
        private volatile bool shouldRefreshReaderManager;

        ///
        /// We call the cache "complete" if we know that every category in our
        /// taxonomy is in the cache. When the cache is not complete, and
        /// we can't find a category in the cache, we still need to look for it
        /// in the on-disk index; Therefore when the cache is not complete, we
        /// need to open a "reader" to the taxonomy index.
        /// The cache becomes incomplete if it was never filled with the existing
        /// categories, or if a Put() to the cache ever returned true (meaning
        /// that some of the cached data was cleared).
        ///
        private volatile bool cacheIsComplete;
        private volatile bool isClosed = false;
        private volatile TaxonomyIndexArrays taxoArrays;
        private volatile int nextID;

        private readonly object syncLock = new object(); // LUCENENET specific - avoid lock (this)

        ///
        /// Reads the commit data from a <see cref="Store.Directory"/>.
        private static IDictionary<string, string> ReadCommitData(Directory dir)
        {
            SegmentInfos infos = new SegmentInfos();
            infos.Read(dir);
            return infos.UserData;
        }

        ///
        /// Forcibly unlocks the taxonomy in the named directory.
        /// <para/>
        /// Caution: this should only be used by failure recovery code, when it is
        /// known that no other process nor thread is in fact currently accessing
        /// this taxonomy.
        /// <para/>
        /// This method is unnecessary if your <see cref="Store.Directory"/> uses a
        /// <see cref="NativeFSLockFactory"/> instead of the default
        /// <see cref="SimpleFSLockFactory"/>. When the "native" lock is used, a lock
        /// does not stay behind forever when the process using it dies.
        ///
        public static void Unlock(Directory directory)
        {
            IndexWriter.Unlock(directory);
        }

        ///
        /// Construct a Taxonomy writer.
        ///
        /// <param name="directory">
        ///    The <see cref="Store.Directory"/> in which to store the taxonomy. Note that
        ///    the taxonomy is written directly to that directory (not to a
        ///    subdirectory of it). </param>
        /// <param name="openMode">
        ///    Specifies how to open a taxonomy for writing: <see cref="OpenMode.APPEND"/>
        ///    means open an existing index for append (failing if the index does
        ///    not yet exist). <see cref="OpenMode.CREATE"/> means create a new index (first
        ///    deleting the old one if it already existed).
        ///    <see cref="OpenMode.CREATE_OR_APPEND"/> appends to an existing index if there
        ///    is one, otherwise it creates a new index. </param>
        /// <param name="cache">
        ///    A <see cref="ITaxonomyWriterCache"/> implementation which determines
        ///    the in-memory caching policy. See for example
        ///    <see cref="WriterCache.LruTaxonomyWriterCache"/> and <see cref="Cl2oTaxonomyWriterCache"/>.
        ///    If null or missing, <see cref="DefaultTaxonomyWriterCache()"/> is used. </param>
        /// <exception cref="CorruptIndexException">
        ///     if the taxonomy is corrupted. </exception>
        /// <exception cref="LockObtainFailedException">
        ///     if the taxonomy is locked by another writer. If it is known
        ///     that no other concurrent writer is active, the lock might
        ///     have been left around by an old dead process, and should be
        ///     removed using <see cref="Unlock(Directory)"/>. </exception>
        /// <exception cref="IOException">
        ///     if another error occurred. </exception>
        public DirectoryTaxonomyWriter(Directory directory, OpenMode openMode,
            ITaxonomyWriterCache cache)
        {
            dir = directory;
            IndexWriterConfig config = CreateIndexWriterConfig(openMode);
            indexWriter = OpenIndexWriter(dir, config);

            // verify (to some extent) that merge policy in effect would preserve category docids
            if (indexWriter != null)
            {
                if (Debugging.AssertsEnabled) Debugging.Assert(!(indexWriter.Config.MergePolicy is TieredMergePolicy), "for preserving category docids, merging none-adjacent segments is not allowed");
            }

            // after we opened the writer, and the index is locked, it's safe to check
            // the commit data and read the index epoch
            openMode = config.OpenMode;
            if (!DirectoryReader.IndexExists(directory))
            {
                indexEpoch = 1;
            }
            else
            {
                string epochStr = null;
                IDictionary<string, string> commitData = ReadCommitData(directory);
                if (commitData != null && commitData.TryGetValue(INDEX_EPOCH, out string value))
                {
                    epochStr = value;
                }
                // no commit data, or no epoch in it means an old taxonomy, so set its epoch to 1, for lack
                // of a better value.
                indexEpoch = epochStr is null ? 1 : Convert.ToInt64(epochStr, 16);
            }

            if (openMode == OpenMode.CREATE)
            {
                ++indexEpoch;
            }

            FieldType ft = new FieldType(TextField.TYPE_NOT_STORED);
            ft.OmitNorms = true;
            parentStreamField = new Field(Consts.FIELD_PAYLOADS, parentStream, ft);
            fullPathField = new StringField(Consts.FULL, "", Field.Store.YES);

            if (indexWriter is null)
                return;

            nextID = indexWriter.MaxDoc;

            if (cache is null)
            {
                cache = DefaultTaxonomyWriterCache();
            }
            this.cache = cache;

            if (nextID == 0)
            {
                cacheIsComplete = true;
                // Make sure that the taxonomy always contain the root category
                // with category id 0.
                AddCategory(new FacetLabel());
            }
            else
            {
                // There are some categories on the disk, which we have not yet
                // read into the cache, and therefore the cache is incomplete.
                // We choose not to read all the categories into the cache now,
                // to avoid terrible performance when a taxonomy index is opened
                // to add just a single category. We will do it later, after we
                // notice a few cache misses.
                cacheIsComplete = false;
            }
        }

        ///
        /// Open internal index writer, which contains the taxonomy data.
        /// <para/>
        /// Extensions may provide their own <see cref="IndexWriter"/> implementation or instance.
        /// <para/>
        /// NOTE: the instance this method returns will be disposed upon calling
        /// to <see cref="Dispose()"/>.
        /// <para/>
        /// NOTE: the merge policy in effect must not merge none adjacent segments. See
        /// comment in <see cref="CreateIndexWriterConfig(OpenMode)"/> for the logic behind this.
        ///
        /// <seealso cref="CreateIndexWriterConfig(OpenMode)"/>
        /// <param name="directory">
        ///          the <see cref="Store.Directory"/> on top of which an <see cref="IndexWriter"/>
        ///          should be opened. </param>
        /// <param name="config">
        ///          configuration for the internal index writer. </param>
        protected virtual IndexWriter OpenIndexWriter(Directory directory, IndexWriterConfig config)
        {
            return new IndexWriter(directory, config);
        }

        ///
        /// Create the <see cref="IndexWriterConfig"/> that would be used for opening the internal index writer.
        /// <para/>
        /// Extensions can configure the <see cref="IndexWriter"/> as they see fit,
        /// including setting a <see cref="Index.MergeScheduler"/>, or
        /// <see cref="Index.IndexDeletionPolicy"/>, different RAM size
        /// etc.
        /// <para/>
        /// NOTE: internal docids of the configured index must not be altered.
        /// For that, categories are never deleted from the taxonomy index.
        /// In addition, merge policy in effect must not merge none adjacent segments.
        ///
        /// <seealso cref="OpenIndexWriter(Directory, IndexWriterConfig)"/>
        /// <param name="openMode"> see <see cref="OpenMode"/> </param>
        protected virtual IndexWriterConfig CreateIndexWriterConfig(OpenMode openMode)
        {
            // TODO: should we use a more optimized Codec, e.g. Pulsing (or write custom)?
            // The taxonomy has a unique structure, where each term is associated with one document

            // :Post-Release-Update-Version.LUCENE_XY:
            // Make sure we use a MergePolicy which always merges adjacent segments and thus
            // keeps the doc IDs ordered as well (this is crucial for the taxonomy index).
            return (new IndexWriterConfig(LuceneVersion.LUCENE_48, null)).SetOpenMode(openMode).SetMergePolicy(new LogByteSizeMergePolicy());
        }

        ///
        /// Opens a <see cref="ReaderManager"/> from the internal <see cref="IndexWriter"/>.
        ///
        private void InitReaderManager()
        {
            if (!initializedReaderManager)
            {
                UninterruptableMonitor.Enter(syncLock);
                try
                {
                    // verify that the taxo-writer hasn't been closed on us.
                    EnsureOpen();
                    if (!initializedReaderManager)
                    {
                        readerManager = new ReaderManager(indexWriter, false);
                        shouldRefreshReaderManager = false;
                        initializedReaderManager = true;
                    }
                }
                finally
                {
                    UninterruptableMonitor.Exit(syncLock);
                }
            }
        }

        ///
        /// Creates a new instance with a default cache as defined by
        /// <see cref="DefaultTaxonomyWriterCache()"/>.
        ///
        public DirectoryTaxonomyWriter(Directory directory, OpenMode openMode)
            : this(directory, openMode, DefaultTaxonomyWriterCache())
        {
        }

        ///
        /// Defines the default <see cref="ITaxonomyWriterCache"/> to use in constructors
        /// which do not specify one.
        /// <para>
        /// The current default is <see cref="Cl2oTaxonomyWriterCache"/> constructed
        /// with the parameters (1024, 0.15f, 3), i.e., the entire taxonomy is
        /// cached in memory while building it.
        /// </para>
        ///
        public static ITaxonomyWriterCache DefaultTaxonomyWriterCache()
        {
            return new Cl2oTaxonomyWriterCache(1024, 0.15f, 3);
        }

        ///
        /// Create this with <see cref="OpenMode.CREATE_OR_APPEND"/>.
        ///
        public DirectoryTaxonomyWriter(Directory directory) : this(directory, OpenMode.CREATE_OR_APPEND) { }

        ///
        /// Frees used resources as well as closes the underlying <see cref="IndexWriter"/>,
        /// which commits whatever changes made to it to the underlying
        /// <see cref="Store.Directory"/>.
        ///
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ///
        /// A hook for extending classes to close additional resources that were used.
        /// The default implementation closes the <see cref="Index.IndexReader"/> as well as the
        /// <see cref="ITaxonomyWriterCache"/> instances that were used.
        /// <para>
        /// NOTE: if you override this method, you should include a
        /// <c>base.Dispose(disposing)</c> call in your implementation.
        /// </para>
        ///
        protected virtual void Dispose(bool disposing)
        {
            UninterruptableMonitor.Enter(syncLock);
            try
            {
                if (disposing && !isClosed)
                {
                    Commit();
                    DoClose();
                }
            }
            finally
            {
                UninterruptableMonitor.Exit(syncLock);
            }
        }

        private void DoClose()
        {
            indexWriter.Dispose();
            isClosed = true;
            CloseResources();
        }

        ///
        /// Closes the <see cref="Index.IndexReader"/> as well as the
        /// <see cref="ITaxonomyWriterCache"/> instances that were used.
        ///
        private void CloseResources() // LUCENENET: Made private, since this has the same purpose as Dispose(bool).
        {
            UninterruptableMonitor.Enter(syncLock);
            try
            {
                if (initializedReaderManager)
                {
                    readerManager.Dispose();
                    readerManager = null;
                    initializedReaderManager = false;
                }
                cache?.Dispose();
                parentStream.Dispose(); // LUCENENET specific
            }
            finally
            {
                UninterruptableMonitor.Exit(syncLock);
            }
        }

        ///
        /// Look up the given category in the cache and/or the on-disk storage,
        /// returning the category's ordinal, or a negative number in case the
        /// category does not yet exist in the taxonomy.
        ///
        protected virtual int FindCategory(FacetLabel categoryPath)
        {
            UninterruptableMonitor.Enter(syncLock);
            try
            {
                // If we can find the category in the cache, or we know the cache is
                // complete, we can return the response directly from it
                int res = cache.Get(categoryPath);
                if (res >= 0 || cacheIsComplete)
                {
                    return res;
                }

                cacheMisses.IncrementAndGet();
                // After a few cache misses, it makes sense to read all the categories
                // from disk and into the cache. The reason not to do this on the first
                // cache miss (or even when opening the writer) is that it will
                // significantly slow down the case when a taxonomy is opened just to
                // add one category. The idea only spending a long time on reading
                // after enough time was spent on cache misses is known as an "online
                // algorithm".
                PerhapsFillCache(); // LUCENENET: This does a write
                res = cache.Get(categoryPath);
                if (res >= 0 || cacheIsComplete)
                {
                    // if after filling the cache from the info on disk, the category is in it
                    // or the cache is complete, return whatever cache.get returned.
                    return res;
                }

                // if we get here, it means the category is not in the cache, and it is not
                // complete, and therefore we must look for the category on disk.

                // We need to get an answer from the on-disk index.
                InitReaderManager();

                int doc = -1;
                DirectoryReader reader = readerManager.Acquire();
                try
                {
                    BytesRef catTerm = new BytesRef(FacetsConfig.PathToString(categoryPath.Components, categoryPath.Length));
                    TermsEnum termsEnum = null; // reuse
                    DocsEnum docs = null; // reuse
                    foreach (AtomicReaderContext ctx in reader.Leaves)
                    {
                        Terms terms = ctx.AtomicReader.GetTerms(Consts.FULL);
                        if (terms != null)
                        {
                            termsEnum = terms.GetEnumerator(termsEnum);
                            if (termsEnum.SeekExact(catTerm))
                            {
                                // liveDocs=null because the taxonomy has no deletes
                                docs = termsEnum.Docs(null, docs, 0); // freqs not required
                                // if the term was found, we know it has exactly one document.
                                doc = docs.NextDoc() + ctx.DocBase;
                                break;
                            }
                        }
                    }
                }
                finally
                {
                    readerManager.Release(reader);
                }
                if (doc > 0)
                {
                    AddToCache(categoryPath, doc); // LUCENENET: This does a write
                }
                return doc;
            }
            finally
            {
                UninterruptableMonitor.Exit(syncLock);
            }
        }

        public virtual int AddCategory(FacetLabel categoryPath)
        {
            EnsureOpen();
            // check the cache outside the synchronized block. this results in better
            // concurrency when categories are there.
            int res = cache.Get(categoryPath);
            if (res < 0)
            {
                // the category is not in the cache - following code cannot be executed in parallel.
                UninterruptableMonitor.Enter(syncLock);
                try
                {
                    res = FindCategory(categoryPath);
                    if (res < 0)
                    {
                        // This is a new category, and we need to insert it into the index
                        // (and the cache). Actually, we might also need to add some of
                        // the category's ancestors before we can add the category itself
                        // (while keeping the invariant that a parent is always added to
                        // the taxonomy before its child). internalAddCategory() does all
                        // this recursively
                        res = InternalAddCategory(categoryPath);
                    }
                }
                finally
                {
                    UninterruptableMonitor.Exit(syncLock);
                }
            }
            return res;
        }

        ///
        /// Add a new category into the index (and the cache), and return its new
        /// ordinal.
        /// <para>
        /// Actually, we might also need to add some of the category's ancestors
        /// before we can add the category itself (while keeping the invariant that a
        /// parent is always added to the taxonomy before its child). We do this by
        /// recursion.
        /// </para>
        ///
        private int InternalAddCategory(FacetLabel cp)
        {
            // Find our parent's ordinal (recursively adding the parent category
            // to the taxonomy if it's not already there). Then add the parent
            // ordinal as payloads (rather than a stored field; payloads can be
            // more efficiently read into memory in bulk by LuceneTaxonomyReader)
            int parent;
            if (cp.Length > 1)
            {
                FacetLabel parentPath = cp.Subpath(cp.Length - 1);
                parent = FindCategory(parentPath);
                if (parent < 0)
                {
                    parent = InternalAddCategory(parentPath);
                }
            }
            else if (cp.Length == 1)
            {
                parent = TaxonomyReader.ROOT_ORDINAL;
            }
            else
            {
                parent = TaxonomyReader.INVALID_ORDINAL;
            }
            int id = AddCategoryDocument(cp, parent);

            return id;
        }

        ///
        /// Verifies that this instance wasn't closed, or throws
        /// <see cref="ObjectDisposedException"/> if it is.
        ///
        protected void EnsureOpen()
        {
            if (isClosed)
            {
                throw AlreadyClosedException.Create(this.GetType().FullName, "The taxonomy writer has already been disposed.");
            }
        }

        ///
        /// Note that the methods calling <see cref="AddCategoryDocument"/> are synchornized, so
        /// this method is effectively synchronized as well.
        ///
        private int AddCategoryDocument(FacetLabel categoryPath, int parent)
        {
            // Before Lucene 2.9, position increments >=0 were supported, so we
            // added 1 to parent to allow the parent -1 (the parent of the root).
            // Unfortunately, starting with Lucene 2.9, after LUCENE-1542, this is
            // no longer enough, since 0 is not encoded consistently either (see
            // comment in SinglePositionTokenStream). But because we must be
            // backward-compatible with existing indexes, we can't just fix what
            // we write here (e.g., to write parent+2), and need to do a workaround
            // in the reader (which knows that anyway only category 0 has a parent
            // -1).
            parentStream.Set(Math.Max(parent + 1, 1));
            Document d = new Document
            {
                parentStreamField
            };

            fullPathField.SetStringValue(FacetsConfig.PathToString(categoryPath.Components, categoryPath.Length));
            d.Add(fullPathField);

            // Note that we do no pass an Analyzer here because the fields that are
            // added to the Document are untokenized or contains their own TokenStream.
            // Therefore the IndexWriter's Analyzer has no effect.
            indexWriter.AddDocument(d);
            int id = nextID++;

            // added a category document, mark that ReaderManager is not up-to-date
            shouldRefreshReaderManager = true;

            // also add to the parent array
            taxoArrays = GetTaxoArrays().Add(id, parent);

            // NOTE: this line must be executed last, or else the cache gets updated
            // before the parents array (LUCENE-4596)
            AddToCache(categoryPath, id);

            return id;
        }

        private class SinglePositionTokenStream : TokenStream
        {
            private readonly ICharTermAttribute termAtt;
            private readonly IPositionIncrementAttribute posIncrAtt;
            private bool returned;
            private int val;
            private readonly string word;

            public SinglePositionTokenStream(string word)
            {
                termAtt = AddAttribute<ICharTermAttribute>();
                posIncrAtt = AddAttribute<IPositionIncrementAttribute>();
                this.word = word;
                returned = true;
            }

            ///
            /// Set the value we want to keep, as the position increment.
            /// Note that when TermPositions.NextPosition() is later used to
            /// retrieve this value, val-1 will be returned, not val.
            /// <para>
            /// IMPORTANT NOTE: Before Lucene 2.9, val>=0 were safe (for val==0,
            /// the retrieved position would be -1). But starting with Lucene 2.9,
            /// this unfortunately changed, and only val>0 are safe. val=0 can
            /// still be used, but don't count on the value you retrieve later
            /// (it could be 0 or -1, depending on circumstances or versions).
            /// This change is described in Lucene's JIRA: LUCENE-1542.
            /// </para>
            ///
            public virtual void Set(int val)
            {
                this.val = val;
                returned = false;
            }

            public sealed override bool IncrementToken()
            {
                if (returned)
                {
                    return false;
                }
                ClearAttributes();
                posIncrAtt.PositionIncrement = val;
                termAtt.SetEmpty();
                termAtt.Append(word);
                returned = true;
                return true;
            }
        }

        // LUCENENET: Removed the lock here because all callers already have a
        // lock before getting in here
        private void AddToCache(FacetLabel categoryPath, int id)
        {
            if (cache.Put(categoryPath, id))
            {
                // If cache.put() returned true, it means the cache was limited in
                // size, became full, and parts of it had to be evicted. It is
                // possible that a relatively-new category that isn't yet visible
                // to our 'reader' was evicted, and therefore we must now refresh
                // the reader.
                RefreshReaderManager();
                cacheIsComplete = false;
            }
        }

        private void RefreshReaderManager()
        {
            UninterruptableMonitor.Enter(syncLock);
            try
            {
                // this method is synchronized since it cannot happen concurrently with
                // addCategoryDocument -- when this method returns, we must know that the
                // reader manager's state is current. also, it sets shouldRefresh to false,
                // and this cannot overlap with addCatDoc too.
                // NOTE: since this method is sync'ed, it can call maybeRefresh, instead of
                // maybeRefreshBlocking. If ever this is changed, make sure to change the
                // call too.
                if (shouldRefreshReaderManager && initializedReaderManager)
                {
                    readerManager.MaybeRefresh();
                    shouldRefreshReaderManager = false;
                }
            }
            finally
            {
                UninterruptableMonitor.Exit(syncLock);
            }
        }

        public virtual void Commit()
        {
            UninterruptableMonitor.Enter(syncLock);
            try
            {
                EnsureOpen();
                // LUCENE-4972: if we always call setCommitData, we create empty commits
                if (!indexWriter.CommitData.TryGetValue(INDEX_EPOCH, out string epochStr)
                    || epochStr is null
                    || Convert.ToInt64(epochStr, 16) != indexEpoch)
                {
                    indexWriter.SetCommitData(CombinedCommitData(indexWriter.CommitData));
                }
                indexWriter.Commit();
            }
            finally
            {
                UninterruptableMonitor.Exit(syncLock);
            }
        }

        ///
        /// Combine original user data with the taxonomy epoch.
        ///
        private IDictionary<string, string> CombinedCommitData(IDictionary<string, string> commitData)
        {
            IDictionary<string, string> m = commitData != null
                ? new Dictionary<string, string>(commitData)
                : new Dictionary<string, string>();
            m[INDEX_EPOCH] = Convert.ToString(indexEpoch, 16);
            return m;
        }

        public virtual void SetCommitData(IDictionary<string, string> commitUserData)
        {
            indexWriter.SetCommitData(CombinedCommitData(commitUserData));
        }

        public virtual IDictionary<string, string> CommitData => CombinedCommitData(indexWriter.CommitData);

        ///
        /// prepare most of the work needed for a two-phase commit.
        /// See <see cref="IndexWriter.PrepareCommit"/>.
        ///
        public virtual void PrepareCommit()
        {
            UninterruptableMonitor.Enter(syncLock);
            try
            {
                EnsureOpen();
                // LUCENE-4972: if we always call setCommitData, we create empty commits
                if (!indexWriter.CommitData.TryGetValue(INDEX_EPOCH, out string epochStr)
                    || epochStr is null
                    || Convert.ToInt64(epochStr, 16) != indexEpoch)
                {
                    indexWriter.SetCommitData(CombinedCommitData(indexWriter.CommitData));
                }
                indexWriter.PrepareCommit();
            }
            finally
            {
                UninterruptableMonitor.Exit(syncLock);
            }
        }

        public virtual int Count
        {
            get
            {
                EnsureOpen();
                return nextID;
            }
        }

        ///
        /// Set the number of cache misses before an attempt is made to read the entire
        /// taxonomy into the in-memory cache.
        /// <para>
        /// This taxonomy writer holds an in-memory cache of recently seen categories
        /// to speed up operation. On each cache-miss, the on-disk index needs to be
        /// consulted. When an existing taxonomy is opened, a lot of slow disk reads
        /// like that are needed until the cache is filled, so it is more efficient to
        /// read the entire taxonomy into memory at once. We do this complete read
        /// after a certain number (defined by this method) of cache misses.
        /// </para>
        /// <para>
        /// If the number is set to <c>0</c>, the entire taxonomy is read into the
        /// cache on first use, without fetching individual categories first.
        /// </para>
        /// <para>
        /// NOTE: it is assumed that this method is called immediately after the
        /// taxonomy writer has been created.
        /// </para>
        ///
        public virtual void SetCacheMissesUntilFill(int i)
        {
            EnsureOpen();
            cacheMissesUntilFill = i;
        }

        // we need to guarantee that if several threads call this concurrently, only
        // one executes it, and after it returns, the cache is updated and is either
        // complete or not.
        private void PerhapsFillCache()
        {
            UninterruptableMonitor.Enter(syncLock);
            try
            {
                if (cacheMisses < cacheMissesUntilFill)
                {
                    return;
                }

                if (!shouldFillCache)
                {
                    // we already filled the cache once, there's no need to re-fill it
                    return;
                }
                shouldFillCache = false;

                InitReaderManager();

                bool aborted = false;
                DirectoryReader reader = readerManager.Acquire();
                try
                {
                    TermsEnum termsEnum = null;
                    DocsEnum docsEnum = null;
                    foreach (AtomicReaderContext ctx in reader.Leaves)
                    {
                        Terms terms = ctx.AtomicReader.GetTerms(Consts.FULL);
                        if (terms != null) // cannot really happen, but be on the safe side
                        {
                            termsEnum = terms.GetEnumerator(termsEnum);
                            while (termsEnum.MoveNext())
                            {
                                if (!cache.IsFull)
                                {
                                    BytesRef t = termsEnum.Term;
                                    // Since we guarantee uniqueness of categories, each term has exactly
                                    // one document. Also, since we do not allow removing categories (and
                                    // hence documents), there are no deletions in the index. Therefore, it
                                    // is sufficient to call next(), and then doc(), exactly once with no
                                    // 'validation' checks.
                                    FacetLabel cp = new FacetLabel(FacetsConfig.StringToPath(t.Utf8ToString()));
                                    docsEnum = termsEnum.Docs(null, docsEnum, DocsFlags.NONE);
                                    bool res = cache.Put(cp, docsEnum.NextDoc() + ctx.DocBase);
                                    if (Debugging.AssertsEnabled) Debugging.Assert(!res, "entries should not have been evicted from the cache");
                                }
                                else
                                {
                                    // the cache is full and the next put() will evict entries from it, therefore abort the iteration.
                                    aborted = true;
                                    break;
                                }
                            }
                        }
                        if (aborted)
                        {
                            break;
                        }
                    }
                }
                finally
                {
                    readerManager.Release(reader);
                }

                cacheIsComplete = !aborted;
                if (cacheIsComplete)
                {
                    UninterruptableMonitor.Enter(syncLock); // LUCENENET TODO: Do we need to synchroize again since the whole method is synchronized?
                    try
                    {
                        // everything is in the cache, so no need to keep readerManager open.
                        // this block is executed in a sync block so that it works well with
                        // initReaderManager called in parallel.
                        readerManager.Dispose();
                        readerManager = null;
                        initializedReaderManager = false;
                    }
                    finally
                    {
                        UninterruptableMonitor.Exit(syncLock);
                    }
                }
            }
            finally
            {
                UninterruptableMonitor.Exit(syncLock);
            }
        }

        private TaxonomyIndexArrays GetTaxoArrays()
        {
            if (taxoArrays is null)
            {
                UninterruptableMonitor.Enter(syncLock);
                try
                {
                    if (taxoArrays is null)
                    {
                        InitReaderManager();
                        DirectoryReader reader = readerManager.Acquire();
                        try
                        {
                            // according to Java Concurrency, this might perform better on some
                            // JVMs, since the object initialization doesn't happen on the
                            // volatile member.
                            var tmpArrays = new TaxonomyIndexArrays(reader);
                            taxoArrays = tmpArrays;
                        }
                        finally
                        {
                            readerManager.Release(reader);
                        }
                    }
                }
                finally
                {
                    UninterruptableMonitor.Exit(syncLock);
                }
            }
            return taxoArrays;
        }

        public virtual int GetParent(int ordinal)
        {
            EnsureOpen();
            // Note: the following if() just enforces that a user can never ask
            // for the parent of a nonexistant category - even if the parent array
            // was allocated bigger than it really needs to be.
            if (ordinal >= nextID)
                // LUCENENET specific: Changed exception type thrown to be consistent with guard clauses in .NET
                throw new ArgumentOutOfRangeException(nameof(ordinal), "requested ordinal is bigger than the largest ordinal in the taxonomy");
            // LUCENENET specific: Added additional check to defend against throwing IndexOutOfRangeException
            if (ordinal < 0)
                throw new ArgumentOutOfRangeException(nameof(ordinal), "ordinal may not be negative.");

            int[] parents = GetTaxoArrays().Parents;
            if (Debugging.AssertsEnabled) Debugging.Assert(ordinal < parents.Length, "requested ordinal ({0}); parents.length ({1}) !", ordinal, parents.Length);
            return parents[ordinal];
        }

        ///
        /// Takes the categories from the given taxonomy directory, and adds the
        /// missing ones to this taxonomy. Additionally, it fills the given
        /// <see cref="IOrdinalMap"/> with a mapping from the original ordinal to the new
        /// ordinal.
        ///
        public virtual void AddTaxonomy(Directory taxoDir, IOrdinalMap map)
        {
            EnsureOpen();
            DirectoryReader r = DirectoryReader.Open(taxoDir);
            try
            {
                int size = r.NumDocs;
                IOrdinalMap ordinalMap = map;
                ordinalMap.SetSize(size);
                int @base = 0;
                TermsEnum te = null;
                DocsEnum docs = null;
                foreach (AtomicReaderContext ctx in r.Leaves)
                {
                    AtomicReader ar = ctx.AtomicReader;
                    Terms terms = ar.GetTerms(Consts.FULL);
                    te = terms.GetEnumerator(te);
                    while (te.MoveNext())
                    {
                        FacetLabel cp = new FacetLabel(FacetsConfig.StringToPath(te.Term.Utf8ToString()));
                        int ordinal = AddCategory(cp);
                        docs = te.Docs(null, docs, DocsFlags.NONE);
                        ordinalMap.AddMapping(docs.NextDoc() + @base, ordinal);
                    }
                    @base += ar.MaxDoc; // no deletions, so we're ok
                }
                ordinalMap.AddDone();
            }
            finally
            {
                r.Dispose();
            }
        }

        ///
        /// Mapping from old ordinal to new ordinals, used when merging indexes
        /// wit separate taxonomies.
        /// <para/>
        /// <see cref="AddMapping"/> merges one or more taxonomies into the given taxonomy
        /// (this). An <see cref="IOrdinalMap"/> is filled for each of the added taxonomies,
        /// containing the new ordinal (in the merged taxonomy) of each of the
        /// categories in the old taxonomy.
        /// <para/>
        /// There exist two implementations of <see cref="IOrdinalMap"/>: <see cref="MemoryOrdinalMap"/> and
        /// <see cref="DiskOrdinalMap"/>. As their names suggest, the former keeps the map in
        /// memory and the latter in a temporary disk file. Because these maps will
        /// later be needed one by one (to remap the counting lists), not all at the
        /// same time, it is recommended to put the first taxonomy's map in memory,
        /// and all the rest on disk (later to be automatically read into memory one
        /// by one, when needed).
        ///
        public interface IOrdinalMap
        {
            ///
            /// Set the size of the map. This MUST be called before <see cref="AddMapping"/>.
            /// It is assumed (but not verified) that <see cref="AddMapping"/> will then be
            /// called exactly 'size' times, with different <c>origOrdinals</c> between 0
            /// and size - 1.
            ///
            void SetSize(int taxonomySize);

            ///
            /// Record a mapping.
            void AddMapping(int origOrdinal, int newOrdinal);

            ///
            /// Call <see cref="AddDone()"/> to say that all <see cref="AddMapping"/> have been done.
            /// In some implementations this might free some resources.
            ///
            void AddDone();

            ///
            /// Return the map from the taxonomy's original (consecutive) ordinals
            /// to the new taxonomy's ordinals. If the map has to be read from disk
            /// and ordered appropriately, it is done when getMap() is called.
            /// getMap() should only be called once, and only when the map is actually
            /// needed. Calling it will also free all resources that the map might
            /// be holding (such as temporary disk space), other than the returned int[].
            ///
            int[] GetMap();
        }

        ///
        /// <see cref="IOrdinalMap"/> maintained in memory
        ///
        public sealed class MemoryOrdinalMap : IOrdinalMap
        {
            internal int[] map;

            ///
            /// Sole constructor.
            ///
            public MemoryOrdinalMap()
            {
                map = Arrays.Empty<int>();
            }

            public void SetSize(int taxonomySize)
            {
                map = new int[taxonomySize];
            }

            public void AddMapping(int origOrdinal, int newOrdinal)
            {
                if (map.Length - 1 >= origOrdinal)
                {
                    map[origOrdinal] = newOrdinal;
                }
                else
                {
                    Array.Resize(ref map, origOrdinal + 1);
                    map[origOrdinal] = newOrdinal;
                }
            }

            public void AddDone()
            {
                // nothing to do
            }

            public int[] GetMap()
            {
                return (int[])map.Clone(); // LUCENENET specific: Since this is clearly not meant to be written to, we are cloning the array https://msdn.microsoft.com/en-us/library/0fss9skc.aspx
            }
        }

        ///
        /// <see cref="IOrdinalMap"/> maintained on file system
        ///
        public sealed class DiskOrdinalMap : IOrdinalMap
        {
            internal string tmpfile;
            internal OutputStreamDataOutput @out;

            ///
            /// Sole constructor.
            ///
            public DiskOrdinalMap(string tmpfile)
            {
                this.tmpfile = tmpfile;
                var outfs = new FileStream(tmpfile, FileMode.OpenOrCreate, FileAccess.Write);
                @out = new OutputStreamDataOutput(outfs);
            }

            public void AddMapping(int origOrdinal, int newOrdinal)
            {
                @out.WriteInt32(origOrdinal);
                @out.WriteInt32(newOrdinal);
            }

            public void SetSize(int taxonomySize)
            {
                @out.WriteInt32(taxonomySize);
            }

            public void AddDone()
            {
                if (@out != null)
                {
                    @out.Dispose();
                    @out = null;
                }
            }

            private int[] map = null;

            public int[] GetMap()
            {
                if (map != null)
                {
                    return map;
                }
                AddDone(); // in case this wasn't previously called

                var ifs = new FileStream(tmpfile, FileMode.OpenOrCreate, FileAccess.Read);
                using (var @in = new InputStreamDataInput(ifs))
                {
                    map = new int[@in.ReadInt32()];
                    // NOTE: The current code assumes here that the map is complete,
                    // i.e., every ordinal gets one and exactly one value. Otherwise,
                    // we may run into an EOF here, or vice versa, not read everything.
                    for (int i = 0; i < map.Length; i++)
                    {
                        int origordinal = @in.ReadInt32();
                        int newordinal = @in.ReadInt32();
                        map[origordinal] = newordinal;
                    }
                }

                // Delete the temporary file, which is no longer needed.
                if (File.Exists(tmpfile))
                {
                    File.Delete(tmpfile);
                }
                return map;
            }
        }

        ///
        /// Rollback changes to the taxonomy writer and closes the instance. Following
        /// this method the instance becomes unusable (calling any of its API methods
        /// will yield an <see cref="ObjectDisposedException"/>).
        ///
        public virtual void Rollback()
        {
            UninterruptableMonitor.Enter(syncLock);
            try
            {
                EnsureOpen();
                indexWriter.Rollback();
                DoClose();

                // LUCENENET: Ensure subclasses are also disposed.
                // The call above to DoClose() ensures that the below call is
                // a no-op in this class, but will still make the call to
                // subclasses to provide their own dipsosable implementation.
                Dispose();
            }
            finally
            {
                UninterruptableMonitor.Exit(syncLock);
            }
        }

        ///
        /// Replaces the current taxonomy with the given one. This method should
        /// generally be called in conjunction with
        /// <see cref="IndexWriter.AddIndexes(Directory[])"/> to replace both the taxonomy
        /// as well as the search index content.
        ///
        public virtual void ReplaceTaxonomy(Directory taxoDir)
        {
            UninterruptableMonitor.Enter(syncLock);
            try
            {
                // replace the taxonomy by doing IW optimized operations
                indexWriter.DeleteAll();
                indexWriter.AddIndexes(taxoDir);
                shouldRefreshReaderManager = true;
                InitReaderManager(); // ensure that it's initialized
                RefreshReaderManager();
                nextID = indexWriter.MaxDoc;
                taxoArrays = null; // must nullify so that it's re-computed next time it's needed

                // need to clear the cache, so that addCategory won't accidentally return
                // old categories that are in the cache.
                cache.Clear();
                cacheIsComplete = false;
                shouldFillCache = true;
                cacheMisses.Value = 0;

                // update indexEpoch as a taxonomy replace is just like it has be recreated
                ++indexEpoch;
            }
            finally
            {
                UninterruptableMonitor.Exit(syncLock);
            }
        }

        ///
        /// Returns the <see cref="Store.Directory"/> of this taxonomy writer.
        ///
        public virtual Directory Directory => dir;

        ///
        /// Used by <see cref="DirectoryTaxonomyReader"/> to support NRT.
        /// <para>
        /// NOTE: you should not use the obtained <see cref="IndexWriter"/> in any
        /// way, other than opening an IndexReader on it, or otherwise, the taxonomy
        /// index may become corrupt!
        /// </para>
        ///
        internal IndexWriter InternalIndexWriter => indexWriter;

        ///
        /// Expert: returns current index epoch, if this is a
        /// near-real-time reader.  Used by
        /// <see cref="DirectoryTaxonomyReader"/> to support NRT.
        ///
        /// @lucene.internal
        ///
        public long TaxonomyEpoch => indexEpoch;
    }
}


text:
set -e

if [ -f "state.yaml" ]; then
  V="$(spiff merge template.yaml state.yaml)"
else
  V="$(spiff merge template.yaml)"
fi

spiff merge --select state - <<<"$V" >state.yaml

echo "$V"

redpajama_set_name: RedPajamaGithub


text:
/**!
 * AngularJS file upload/drop directive and service with progress and abort
 * @author  Danial  <danial.farid@gmail.com>
 * @version 7.0.7
 */

if (window.XMLHttpRequest && !(window.FileAPI && FileAPI.shouldLoad)) {
  window.XMLHttpRequest.prototype.setRequestHeader = (function (orig) {
    return function (header, value) {
      if (header === '__setXHR_') {
        var val = value(this);
        // fix for angular < 1.2.0
        if (val instanceof Function) {
          val(this);
        }
      } else {
        orig.apply(this, arguments);
      }
    };
  })(window.XMLHttpRequest.prototype.setRequestHeader);
}

var ngFileUpload = angular.module('ngFileUpload', []);

ngFileUpload.version = '7.0.7';

ngFileUpload.service('UploadBase', ['$http', '$q', '$timeout', function ($http, $q, $timeout) {
  function sendHttp(config) {
    config.method = config.method || 'POST';
    config.headers = config.headers || {};

    var deferred = $q.defer();
    var promise = deferred.promise;

    config.headers.__setXHR_ = function () {
      return function (xhr) {
        if (!xhr) return;
        config.__XHR = xhr;
        if (config.xhrFn) config.xhrFn(xhr);
        xhr.upload.addEventListener('progress', function (e) {
          e.config = config;
          if (deferred.notify) {
            deferred.notify(e);
          } else if (promise.progressFunc) {
            $timeout(function () {
              promise.progressFunc(e);
            });
          }
        }, false);
        //fix for firefox not firing upload progress end, also IE8-9
        xhr.upload.addEventListener('load', function (e) {
          if (e.lengthComputable) {
            e.config = config;
            if (deferred.notify) {
              deferred.notify(e);
            } else if (promise.progressFunc) {
              $timeout(function () {
                promise.progressFunc(e);
              });
            }
          }
        }, false);
      };
    };

    $http(config).then(function (r) {
      deferred.resolve(r);
    }, function (e) {
      deferred.reject(e);
    }, function (n) {
      deferred.notify(n);
    });

    promise.success = function (fn) {
      promise.then(function (response) {
        fn(response.data, response.status, response.headers, config);
      });
      return promise;
    };

    promise.error = function (fn) {
      promise.then(null, function (response) {
        fn(response.data, response.status, response.headers, config);
      });
      return promise;
    };

    promise.progress = function (fn) {
      promise.progressFunc = fn;
      promise.then(null, null, function (update) {
        fn(update);
      });
      return promise;
    };
    promise.abort = function () {
      if (config.__XHR) {
        $timeout(function () {
          config.__XHR.abort();
        });
      }
      return promise;
    };
    promise.xhr = function (fn) {
      config.xhrFn = (function (origXhrFn) {
        return function () {
          if (origXhrFn) origXhrFn.apply(promise, arguments);
          fn.apply(promise, arguments);
        };
      })(config.xhrFn);
      return promise;
    };

    return promise;
  }

  this.upload = function (config) {
    function addFieldToFormData(formData, val, key) {
      if (val !== undefined) {
        if (angular.isDate(val)) {
          val = val.toISOString();
        }
        if (angular.isString(val)) {
          formData.append(key, val);
        } else if (config.sendFieldsAs === 'form') {
          if (angular.isObject(val)) {
            for (var k in val) {
              if (val.hasOwnProperty(k)) {
                addFieldToFormData(formData, val[k], key + '[' + k + ']');
              }
            }
          } else {
            formData.append(key, val);
          }
        } else {
          val = angular.isString(val) ? val : JSON.stringify(val);
          if (config.sendFieldsAs === 'json-blob') {
            formData.append(key, new Blob([val], {type: 'application/json'}));
          } else {
            formData.append(key, val);
          }
        }
      }
    }

    config.headers = config.headers || {};
    config.headers['Content-Type'] = undefined;
    config.transformRequest = config.transformRequest ?
      (angular.isArray(config.transformRequest) ?
        config.transformRequest : [config.transformRequest]) : [];
    config.transformRequest.push(function (data) {
      var formData = new FormData();
      var allFields = {};
      var key;
      for (key in config.fields) {
        if (config.fields.hasOwnProperty(key)) {
          allFields[key] = config.fields[key];
        }
      }
      if (data) allFields.data = data;
      for (key in allFields) {
        if (allFields.hasOwnProperty(key)) {
          var val = allFields[key];
          if (config.formDataAppender) {
            config.formDataAppender(formData, key, val);
          } else {
            addFieldToFormData(formData, val, key);
          }
        }
      }

      if (config.file != null) {
        var fileFormName = config.fileFormDataName || 'file';

        if (angular.isArray(config.file)) {
          var isFileFormNameString = angular.isString(fileFormName);
          for (var i = 0; i < config.file.length; i++) {
            formData.append(isFileFormNameString ? fileFormName : fileFormName[i], config.file[i],
              (config.fileName && config.fileName[i]) || config.file[i].name);
          }
        } else {
          formData.append(fileFormName, config.file, config.fileName || config.file.name);
        }
      }
      return formData;
    });

    return sendHttp(config);
  };

  this.http = function (config) {
    config.transformRequest = config.transformRequest || function (data) {
        if ((window.ArrayBuffer && data instanceof window.ArrayBuffer) || data instanceof Blob) {
          return data;
        }
        return $http.defaults.transformRequest[0](arguments);
      };
    return sendHttp(config);
  };

  this.setDefaults = function(defaults) {
    this.defaults = defaults || {};
  };

  this.defaults = {};
  this.version = ngFileUpload.version;
}

]);

(function () {

  ngFileUpload.service('Upload', ['$parse', '$timeout', '$compile', 'UploadValidate',
    function ($parse, $timeout, $compile, UploadValidate) {
      var upload = UploadValidate;
      upload.getAttrWithDefaults = function (attr, name) {
        return attr[name] != null ? attr[name] :
          (upload.defaults[name] == null ?
            upload.defaults[name] : upload.defaults[name].toString());
      };

      upload.attrGetter = function (name, attr, scope, params) {
        if (scope) {
          try {
            if (params) {
              return $parse(this.getAttrWithDefaults(attr, name))(scope, params);
            } else {
              return $parse(this.getAttrWithDefaults(attr, name))(scope);
            }
          } catch (e) {
            // hangle string value without single qoute
            if (name.search(/min|max|pattern/i)) {
              return this.getAttrWithDefaults(attr, name);
            } else {
              throw e;
            }
          }
        } else {
          return this.getAttrWithDefaults(attr, name);
        }
      };

      upload.updateModel = function (ngModel, attr, scope, fileChange, files, evt, noDelay) {
        function update() {
          var keep = upload.attrGetter('ngfKeep', attr, scope);
          if (keep === true) {
            var prevFiles = (ngModel.$modelValue || []).slice(0);
            if (!files || !files.length) {
              files = prevFiles;
            } else if (upload.attrGetter('ngfKeepDistinct', attr, scope) === true) {
              var len = prevFiles.length;
              for (var i = 0; i < files.length; i++) {
                for (var j = 0; j < len; j++) {
                  if (files[i].name === prevFiles[j].name) break;
                }
                if (j === len) {
                  prevFiles.push(files[i]);
                }
              }
              files = prevFiles;
            } else {
              files = prevFiles.concat(files);
            }
          }

          var file = files && files.length ? files[0] : null;
          if (ngModel) {
            var singleModel = !upload.attrGetter('ngfMultiple', attr, scope) && !upload.attrGetter('multiple', attr) && !keep;
            $timeout(function () {
              $parse(upload.attrGetter('ngModel', attr)).assign(scope, singleModel ? file : files);
            });
          }
          var ngfModel = upload.attrGetter('ngfModel', attr);
          if (ngfModel) {
            $parse(ngfModel).assign(scope, files);
          }

          if (fileChange) {
            $parse(fileChange)(scope, {
              $files: files,
              $file: file,
              $event: evt
            });
          }
        }

        if (noDelay) {
          update();
        } else if (upload.validate(files, ngModel, attr, scope, upload.attrGetter('ngfValidateLater', attr), function () {
            $timeout(function () {
              update();
            });
          }));
      };

      return upload;
    }]);
})();

(function () {

  ngFileUpload.directive('ngfSelect', ['$parse', '$timeout', '$compile', 'Upload',
    function ($parse, $timeout, $compile, Upload) {
      return {
        restrict: 'AEC',
        require: '?ngModel',
        link: function (scope, elem, attr, ngModel) {
          linkFileSelect(scope, elem, attr, ngModel, $parse, $timeout, $compile, Upload);
        }
      };
    }]);

  function linkFileSelect(scope, elem, attr, ngModel, $parse, $timeout, $compile, upload) {
    /** @namespace attr.ngfSelect */
    /** @namespace attr.ngfChange */
    /** @namespace attr.ngModel */
    /** @namespace attr.ngfModel */
    /** @namespace attr.ngfMultiple */
    /** @namespace attr.ngfCapture */
    /** @namespace attr.ngfValidate */
    /** @namespace attr.ngfKeep */
    /** @namespace attr.ngfKeepDistinct */
    var attrGetter = function (name, scope) {
      return upload.attrGetter(name, attr, scope);
    };

    upload.registerValidators(ngModel, attr, scope);

    function isInputTypeFile() {
      return elem[0].tagName.toLowerCase() === 'input' && attr.type && attr.type.toLowerCase() === 'file';
    }

    function fileChangeAttr() {
      return attrGetter('ngfChange') || attrGetter('ngfSelect');
    }

    function changeFn(evt) {
      var fileList = evt.__files_ || (evt.target && evt.target.files), files = [];
      for (var i = 0; i < fileList.length; i++) {
        files.push(fileList[i]);
      }
      upload.updateModel(ngModel, attr, scope, fileChangeAttr(), files.length ? files : null, evt);
    }

    scope.$watch(attrGetter('ngfMultiple'), function() {
      fileElem.attr('multiple', attrGetter('ngfMultiple', scope));
    });
    scope.$watch(attrGetter('ngfCapture'), function() {
      fileElem.attr('capture', attrGetter('ngfCapture', scope));
    });
    attr.$observe('accept', function() {
      fileElem.attr('accept', attrGetter('accept'));
    });
    function bindAttrToFileInput(fileElem) {
      if (elem !== fileElem) {
        for (var i = 0; i < elem[0].attributes.length; i++) {
          var attribute = elem[0].attributes[i];
          if (attribute.name !== 'type' && attribute.name !== 'class' &&
            attribute.name !== 'id' && attribute.name !== 'style') {
            if (attribute.value == null || attribute.value === '') {
              if (attribute.name === 'required') attribute.value = 'required';
              if (attribute.name === 'multiple') attribute.value = 'multiple';
            }
            fileElem.attr(attribute.name, attribute.value);
          }
        }
      }
    }

    function createFileInput() {
      if (isInputTypeFile()) {
        return elem;
      }

      var fileElem = angular.element('<input type="file">');
      bindAttrToFileInput(fileElem);

      fileElem.css('visibility', 'hidden').css('position', 'absolute').css('overflow', 'hidden')
        .css('width', '0px').css('height', '0px').css('border', 'none')
        .css('margin', '0px').css('padding', '0px').attr('tabindex', '-1');
      document.body.appendChild(fileElem[0]);

      return fileElem;
    }

    var initialTouchStartY = 0;

    function clickHandler(evt) {
      if (elem.attr('disabled') || attrGetter('ngfSelectDisabled', scope)) return false;

      var r = handleTouch(evt);
      if (r != null) return r;

      resetModel(evt);

      // fix for android native browser < 4.4
      if (shouldClickLater(navigator.userAgent)) {
        setTimeout(function () {
          fileElem[0].click();
        }, 0);
      } else {
        fileElem[0].click();
      }

      return false;
    }

    function handleTouch(evt) {
      var touches = evt.changedTouches || (evt.originalEvent && evt.originalEvent.changedTouches);
      if (evt.type === 'touchstart') {
        initialTouchStartY = touches ? touches[0].clientY : 0;
        return true; // don't block event default
      } else {
        evt.stopPropagation();
        evt.preventDefault();

        // prevent scroll from triggering event
        if (evt.type === 'touchend') {
          var currentLocation = touches ? touches[0].clientY : 0;
          if (Math.abs(currentLocation - initialTouchStartY) > 20) return false;
        }
      }
    }

    function shouldClickLater(ua) {
      // android below 4.4
      var m = ua.match(/Android[^\d]*(\d+)\.(\d+)/);
      if (m && m.length > 2) {
        var v = upload.defaults.androidFixMinorVersion || 4;
        return parseInt(m[1]) < 4 || (parseInt(m[1]) === v && parseInt(m[2]) < v);
      }

      // safari on windows
      return ua.indexOf('Chrome') === -1 && /.*Windows.*Safari.*/.test(ua);
    }

    var fileElem = elem;

    function resetModel(evt) {
      if (fileElem.val()) {
        fileElem.val(null);
        upload.updateModel(ngModel, attr, scope, fileChangeAttr(), null, evt, true);
      }
    }

    if (!isInputTypeFile()) {
      fileElem = createFileInput();
    }
    fileElem.bind('change', changeFn);

    if (!isInputTypeFile()) {
      elem.bind('click touchstart touchend', clickHandler);
    } else {
      elem.bind('click', resetModel);
    }

    function ie10SameFileSelectFix(evt) {
      if (fileElem && !fileElem.attr('__ngf_ie10_Fix_')) {
        if (!fileElem[0].parentNode) {
          fileElem = null;
          return;
        }
        evt.preventDefault();
        evt.stopPropagation();
        fileElem.unbind('click');
        var clone = fileElem.clone();
        fileElem.replaceWith(clone);
        fileElem = clone;
        fileElem.attr('__ngf_ie10_Fix_', 'true');
        fileElem.bind('change', changeFn);
        fileElem.bind('click', ie10SameFileSelectFix);
        fileElem[0].click();
        return false;
      } else {
        fileElem.removeAttr('__ngf_ie10_Fix_');
      }
    }

    if (navigator.appVersion.indexOf('MSIE 10') !== -1) {
      fileElem.bind('click', ie10SameFileSelectFix);
    }

    scope.$on('$destroy', function () {
      if (!isInputTypeFile()) fileElem.remove();
    });

    if (window.FileAPI && window.FileAPI.ngfFixIE) {
      window.FileAPI.ngfFixIE(elem, fileElem, changeFn);
    }
  }
})();

(function () {

  ngFileUpload.service('UploadDataUrl', ['UploadBase', '$timeout', '$q', function (UploadBase, $timeout, $q) {
    var upload = UploadBase;
    upload.dataUrl = function (file, disallowObjectUrl) {
      if (file.dataUrl) {
        var d = $q.defer();
        $timeout(function () {
          d.resolve(file.dataUrl);
        });
        return d.promise;
      }
      if (file.$ngfDataUrlPromise) return file.$ngfDataUrlPromise;

      var deferred = $q.defer();
      $timeout(function () {
        if (window.FileReader && file &&
          (!window.FileAPI || navigator.userAgent.indexOf('MSIE 8') === -1 || file.size < 20000) &&
          (!window.FileAPI || navigator.userAgent.indexOf('MSIE 9') === -1 || file.size < 4000000)) {
          //prefer URL.createObjectURL for handling refrences to files of all sizes
          //since it doesn´t build a large string in memory
          var URL = window.URL || window.webkitURL;
          if (URL && URL.createObjectURL && !disallowObjectUrl) {
            var url;
            try {
              url = URL.createObjectURL(file);
            } catch (e) {
              deferred.reject();
              return;
            }
            file.dataUrl = url;
            if (url) deferred.resolve(url);
          } else {
            var fileReader = new FileReader();
            fileReader.onload = function (e) {
              $timeout(function () {
                file.dataUrl = e.target.result;
                deferred.resolve(e.target.result);
              });
            };
            fileReader.onerror = function () {
              $timeout(function () {
                file.dataUrl = '';
                deferred.reject();
              });
            };
            fileReader.readAsDataURL(file);
          }
        } else {
          file.dataUrl = '';
          deferred.reject();
        }
      });

      file.$ngfDataUrlPromise = deferred.promise;
      file.$ngfDataUrlPromise['finally'](function () {
        delete file.$ngfDataUrlPromise;
      });
      return file.$ngfDataUrlPromise;
    };
    return upload;
  }]);

  function getTagType(el) {
    if (el.tagName.toLowerCase() === 'img') return 'image';
    if (el.tagName.toLowerCase() === 'audio') return 'audio';
    if (el.tagName.toLowerCase() === 'video') return 'video';
    return /\./;
  }

  var style = document.createElement('style');
  style.innerHTML = '.ngf-hide{display:none !important}';
  document.getElementsByTagName('head')[0].appendChild(style);

  /** @namespace attr.ngfSrc */
  /** @namespace attr.ngfNoObjectUrl */
  ngFileUpload.directive('ngfSrc', ['$compile', '$timeout', 'Upload', function ($compile, $timeout, Upload) {
    return {
      restrict: 'AE',
      link: function (scope, elem, attr) {
        $timeout(function () {
          scope.$watch(attr.ngfSrc, function (file) {
            if (file && file.type.indexOf(getTagType(elem[0])) === 0) {
              Upload.dataUrl(file, Upload.attrGetter('ngfNoObjectUrl', attr, scope))['finally'](function () {
                $timeout(function () {
                  if (file.dataUrl) {
                    elem.removeClass('ngf-hide');
                    elem.attr('src', file.dataUrl);
                  }
                });
              });
            } else {
              elem.addClass('ngf-hide');
            }
          });
        });
      }
    };
  }]);

  /** @namespace attr.ngfBackground */
  /** @namespace attr.ngfNoObjectUrl */
  ngFileUpload.directive('ngfBackground', ['Upload', '$compile', '$timeout', function (Upload, $compile, $timeout) {
    return {
      restrict: 'AE',
      link: function (scope, elem, attr) {
        $timeout(function () {
          scope.$watch(attr.ngfBackground, function (file) {
            console.log(elem[0], elem.css('display'),
              elem.css('visibility'), elem[0].parentNode);
            if (file && file.type.indexOf('image') === 0) {
              Upload.dataUrl(file, Upload.attrGetter('ngfNoObjectUrl', attr, scope))['finally'](function () {
                $timeout(function () {
                  if (file.dataUrl) elem.attr('style', elem.attr('style') +
                    ';background-image:url(\'' + file.dataUrl + '\')');
                });
              });
            }
          });
        });
      }
    };
  }]);

  ngFileUpload.config(['$compileProvider', function ($compileProvider) {
    if ($compileProvider.imgSrcSanitizationWhitelist) $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|ftp|local|file|data|blob):/);
    if ($compileProvider.aHrefSanitizationWhitelist) $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|local|file|data|blob):/);
  }]);

  ngFileUpload.filter('ngfDataUrl', ['UploadDataUrl', '$sce', function (UploadDataUrl, $sce) {
    return function (file, disallowObjectUrl) {
      if (angular.isString(file)) {
        return $sce.trustAsResourceUrl(file);
      }
      if (file && !file.dataUrl) {
        if (file.dataUrl === undefined && angular.isObject(file)) {
          file.dataUrl = null;
          UploadDataUrl.dataUrl(file, disallowObjectUrl).then(function (url) {
            file.dataUrl = url;
          }, function () {
            file.dataUrl = '';
          });
        }
        return '';
      }
      return (file && file.dataUrl ? $sce.trustAsResourceUrl(file.dataUrl) : file) || '';
    };
  }]);

})();

(function () {
  function globStringToRegex(str) {
    if (str.length > 2 && str[0] === '/' && str[str.length - 1] === '/') {
      return str.substring(1, str.length - 1);
    }
    var split = str.split(','), result = '';
    if (split.length > 1) {
      for (var i = 0; i < split.length; i++) {
        result += '(' + globStringToRegex(split[i]) + ')';
        if (i < split.length - 1) {
          result += '|';
        }
      }
    } else {
      if (str.indexOf('.') === 0) {
        str = '*' + str;
      }
      result = '^' + str.replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\' + '-]', 'g'), '\\$&') + '$';
      result = result.replace(/\\\*/g, '.*').replace(/\\\?/g, '.');
    }
    return result;
  }

  function translateScalars(str) {
    if (angular.isString(str)) {
      if (str.search(/kb/i) === str.length - 2) {
        return parseFloat(str.substring(0, str.length - 2) * 1000);
      } else if (str.search(/mb/i) === str.length - 2) {
        return parseFloat(str.substring(0, str.length - 2) * 1000000);
      } else if (str.search(/gb/i) === str.length - 2) {
        return parseFloat(str.substring(0, str.length - 2) * 1000000000);
      } else if (str.search(/b/i) === str.length - 1) {
        return parseFloat(str.substring(0, str.length - 1));
      } else if (str.search(/s/i) === str.length - 1) {
        return parseFloat(str.substring(0, str.length - 1));
      } else if (str.search(/m/i) === str.length - 1) {
        return parseFloat(str.substring(0, str.length - 1) * 60);
      } else if (str.search(/h/i) === str.length - 1) {
        return parseFloat(str.substring(0, str.length - 1) * 3600);
      }
    }
    return str;
  }

  ngFileUpload.service('UploadValidate', ['UploadDataUrl', '$q', '$timeout', function (UploadDataUrl, $q, $timeout) {
    var upload = UploadDataUrl;

    upload.registerValidators = function (ngModel, attr, scope, later) {
      if (!ngModel) return;

      ngModel.$ngfValidations = ngModel.$ngfValidations || {};

      function setValidities(ngModel) {
        for (var k in ngModel.$ngfValidations) {
          if (ngModel.$ngfValidations.hasOwnProperty(k)) {
            ngModel.$setValidity(k, ngModel.$ngfValidations[k]);
          }
        }
      }

      ngModel.$formatters.push(function (val) {
        if (later) {
          upload.validate(val, ngModel, attr, scope, false, function () {
            setValidities(ngModel);
          });
        } else {
          for (var k in ngModel.$ngfValidations) {
            if (ngModel.$ngfValidations.hasOwnProperty(k)) {
              ngModel.$setValidity(k, ngModel.$ngfValidations[k]);
            }
          }
          setValidities(ngModel);
        }
        return val;
      });
    };

    upload.validatePattern = function (file, val) {
      if (!val) {
        return true;
      }
      var regexp = new RegExp(globStringToRegex(val), 'gi');
      return (file.type != null && regexp.test(file.type.toLowerCase())) ||
        (file.name != null && regexp.test(file.name.toLowerCase()));
    };

    upload.validate = function (files, ngModel, attr, scope, later, callback) {
      ngModel = ngModel || {};
      ngModel.$ngfValidations = ngModel.$ngfValidations || {};

      var attrGetter = function (name, params) {
        return upload.attrGetter(name, attr, scope, params);
      };

      if (later) {
        callback.call(ngModel);
        return;
      }

      function validateSync(name, validatorVal, fn) {
        if (files) {
          var valid = null, dName = 'ngf' + name[0].toUpperCase() + name.substr(1);
          angular.forEach(files.length === undefined ? [files] : files, function (file) {
            var val = attrGetter(dName, {'$file': file});
            if (val == null) {
              val = validatorVal(attrGetter('ngfValidate') || {});
            }
            if (val != null) {
              valid = true;
              if (!fn(file, val)) {
                file.$error = name;
                file.$errorParam = val;
                valid = false;
                return false;
              }
            }
          });
          if (valid != null) {
            ngModel.$ngfValidations[name] = valid;
            return valid;
          }
        }
        return true;
      }

      var valid = true;
      valid = valid && validateSync('pattern', function (cons) {
          return cons.pattern;
        }, upload.validatePattern);
      valid = valid && validateSync('minSize', function (cons) {
          return cons.size && cons.size.min;
        }, function (file, val) {
          return file.size >= translateScalars(val);
        });
      valid = valid && validateSync('maxSize', function (cons) {
          return cons.size && cons.size.max;
        }, function (file, val) {
          return file.size <= translateScalars(val);
        });

      valid = valid && validateSync('validateFn', function () {
          return null;
        }, function (file, r) {
          return r === true || r === null || r === '';
        });

      if (!valid) {
        callback.call(ngModel, ngModel.$ngfValidations);
        return;
      }

      var pendings = 0;

      function validateAsync(name, validatorVal, type, asyncFn, fn) {
        if (files) {
          var thisPendings = 0, hasError = false, dName = 'ngf' + name[0].toUpperCase() + name.substr(1);
          files = files.length === undefined ? [files] : files;
          angular.forEach(files, function (file) {
            if (file.type.search(type) !== 0) {
              return true;
            }
            var val = attrGetter(dName, {'$file': file}) || validatorVal(attrGetter('ngfValidate') || {});
            if (val) {
              pendings++;
              thisPendings++;
              asyncFn(file, val).then(function (d) {
                if (!fn(d, val)) {
                  file.$error = name;
                  file.$errorParam = val;
                  hasError = true;
                }
              }, function () {
                file.$error = name;
                file.$errorParam = val;
                hasError = true;
              })['finally'](function () {
                pendings--;
                thisPendings--;
                if (!thisPendings) {
                  ngModel.$ngfValidations[name] = !hasError;
                }
                if (!pendings) {
                  callback.call(ngModel, ngModel.$ngfValidations);
                }
              });
            }
          });
        }
      }

      validateAsync('maxHeight', function (cons) {
        return cons.height && cons.height.max;
      }, /image/, this.imageDimensions, function (d, val) {
        return d.height <= val;
      });
      validateAsync('minHeight', function (cons) {
        return cons.height && cons.height.min;
      }, /image/, this.imageDimensions, function (d, val) {
        return d.height >= val;
      });
      validateAsync('maxWidth', function (cons) {
        return cons.height && cons.width.max;
      }, /image/, this.imageDimensions, function (d, val) {
        return d.width <= val;
      });
      validateAsync('minWidth', function (cons) {
        return cons.height && cons.width.min;
      }, /image/, this.imageDimensions, function (d, val) {
        return d.width >= val;
      });
      validateAsync('maxDuration', function (cons) {
        return cons.height && cons.duration.max;
      }, /audio|video/, this.mediaDuration, function (d, val) {
        return d <= translateScalars(val);
      });
      validateAsync('minDuration', function (cons) {
        return cons.height && cons.duration.min;
      }, /audio|video/, this.mediaDuration, function (d, val) {
        return d >= translateScalars(val);
      });

      validateAsync('validateAsyncFn', function () {
        return null;
      }, /./, function (file, val) {
        return val;
      }, function (r) {
        return r === true || r === null || r === '';
      });

      if (!pendings) {
        callback.call(ngModel, ngModel.$ngfValidations);
      }
    };

    upload.imageDimensions = function (file) {
      if (file.width && file.height) {
        var d = $q.defer();
        $timeout(function () {
          d.resolve({width: file.width, height: file.height});
        });
        return d.promise;
      }
      if (file.$ngfDimensionPromise) return file.$ngfDimensionPromise;

      var deferred = $q.defer();
      $timeout(function () {
        if (file.type.indexOf('image') !== 0) {
          deferred.reject('not image');
          return;
        }
        upload.dataUrl(file).then(function (dataUrl) {
          var img = angular.element('<img>').attr('src', dataUrl).css('visibility', 'none').css('position', 'fixed');
          img.on('load', function () {
            var width = img[0].clientWidth;
            var height = img[0].clientHeight;
            img.remove();
            file.width = width;
            file.height = height;
            deferred.resolve({width: width, height: height});
          });
          img.on('error', function () {
            img.remove();
            deferred.reject('load error');
          });
          angular.element(document.body).append(img);
        }, function () {
          deferred.reject('load error');
        });
      });

      file.$ngfDimensionPromise = deferred.promise;
      file.$ngfDimensionPromise['finally'](function () {
        delete file.$ngfDimensionPromise;
      });
      return file.$ngfDimensionPromise;
    };

    upload.mediaDuration = function (file) {
      if (file.duration) {
        var d = $q.defer();
        $timeout(function () {
          d.resolve(file.duration);
        });
        return d.promise;
      }
      if (file.$ngfDurationPromise) return file.$ngfDurationPromise;

      var deferred = $q.defer();
      $timeout(function () {
        if (file.type.indexOf('audio') !== 0 && file.type.indexOf('video') !== 0) {
          deferred.reject('not media');
          return;
        }
        upload.dataUrl(file).then(function (dataUrl) {
          var el = angular.element(file.type.indexOf('audio') === 0 ? '<audio>' : '<video>')
            .attr('src', dataUrl).css('visibility', 'none').css('position', 'fixed');

          el.on('loadedmetadata', function () {
            var duration = el[0].duration;
            file.duration = duration;
            el.remove();
            deferred.resolve(duration);
          });
          el.on('error', function () {
            el.remove();
            deferred.reject('load error');
          });
          angular.element(document.body).append(el);
        }, function () {
          deferred.reject('load error');
        });
      });

      file.$ngfDurationPromise = deferred.promise;
      file.$ngfDurationPromise['finally'](function () {
        delete file.$ngfDurationPromise;
      });
      return file.$ngfDurationPromise;
    };
    return upload;
  }
  ])
  ;
})
();

(function () {
  ngFileUpload.directive('ngfDrop', ['$parse', '$timeout', '$location', 'Upload',
    function ($parse, $timeout, $location, Upload) {
      return {
        restrict: 'AEC',
        require: '?ngModel',
        link: function (scope, elem, attr, ngModel) {
          linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $location, Upload);
        }
      };
    }]);

  ngFileUpload.directive('ngfNoFileDrop', function () {
    return function (scope, elem) {
      if (dropAvailable()) elem.css('display', 'none');
    };
  });

  ngFileUpload.directive('ngfDropAvailable', ['$parse', '$timeout', 'Upload', function ($parse, $timeout, Upload) {
    return function (scope, elem, attr) {
      if (dropAvailable()) {
        var model = $parse(Upload.attrGetter('ngfDropAvailable', attr));
        $timeout(function () {
          model(scope);
          if (model.assign) {
            model.assign(scope, true);
          }
        });
      }
    };
  }]);

  function linkDrop(scope, elem, attr, ngModel, $parse, $timeout, $location, upload) {
    var available = dropAvailable();

    var attrGetter = function (name, scope, params) {
      return upload.attrGetter(name, attr, scope, params);
    };

    if (attrGetter('dropAvailable')) {
      $timeout(function () {
        if (scope[attrGetter('dropAvailable')]) {
          scope[attrGetter('dropAvailable')].value = available;
        } else {
          scope[attrGetter('dropAvailable')] = available;
        }
      });
    }
    if (!available) {
      if (attrGetter('ngfHideOnDropNotAvailable', scope) === true) {
        elem.css('display', 'none');
      }
      return;
    }

    function isDisabled() {
      return elem.attr('disabled') || attrGetter('ngfDropDisabled', scope);
    }

    upload.registerValidators(ngModel, attr, scope);

    var leaveTimeout = null;
    var stopPropagation = $parse(attrGetter('ngfStopPropagation'));
    var dragOverDelay = 1;
    var actualDragOverClass;

    elem[0].addEventListener('dragover', function (evt) {
      if (isDisabled()) return;
      evt.preventDefault();
      if (stopPropagation(scope)) evt.stopPropagation();
      // handling dragover events from the Chrome download bar
      if (navigator.userAgent.indexOf('Chrome') > -1) {
        var b = evt.dataTransfer.effectAllowed;
        evt.dataTransfer.dropEffect = ('move' === b || 'linkMove' === b) ? 'move' : 'copy';
      }
      $timeout.cancel(leaveTimeout);
      if (!actualDragOverClass) {
        actualDragOverClass = 'C';
        calculateDragOverClass(scope, attr, evt, function (clazz) {
          actualDragOverClass = clazz;
          elem.addClass(actualDragOverClass);
        });
      }
    }, false);
    elem[0].addEventListener('dragenter', function (evt) {
      if (isDisabled()) return;
      evt.preventDefault();
      if (stopPropagation(scope)) evt.stopPropagation();
    }, false);
    elem[0].addEventListener('dragleave', function () {
      if (isDisabled()) return;
      leaveTimeout = $timeout(function () {
        elem.removeClass(actualDragOverClass);
        actualDragOverClass = null;
      }, dragOverDelay || 1);
    }, false);
    elem[0].addEventListener('drop', function (evt) {
      if (isDisabled()) return;
      evt.preventDefault();
      if (stopPropagation(scope)) evt.stopPropagation();
      elem.removeClass(actualDragOverClass);
      actualDragOverClass = null;
      extractFiles(evt, function (files) {
          upload.updateModel(ngModel, attr, scope, attrGetter('ngfChange') || attrGetter('ngfDrop'), files, evt);
        }, attrGetter('ngfAllowDir', scope) !== false,
        attrGetter('multiple') || attrGetter('ngfMultiple', scope));
    }, false);
    elem[0].addEventListener('paste', function (evt) {
      if (isDisabled()) return;
      var files = [];
      var clipboard = evt.clipboardData || evt.originalEvent.clipboardData;
      if (clipboard && clipboard.items) {
        for (var k = 0; k < clipboard.items.length; k++) {
          if (clipboard.items[k].type.indexOf('image') !== -1) {
            files.push(clipboard.items[k].getAsFile());
          }
        }
        upload.updateModel(ngModel, attr, scope, attrGetter('ngfChange') || attrGetter('ngfDrop'), files, evt);
      }
    }, false);

    function calculateDragOverClass(scope, attr, evt, callback) {
      var clazz = attrGetter('ngfDragOverClass', scope, {$event: evt}),
        dClass = attrGetter('ngfDragOverClass') || 'dragover';
      if (angular.isString(clazz)) {
        callback(clazz);
        return;
      }
      if (clazz) {
        if (clazz.delay) dragOverDelay = clazz.delay;
        if (clazz.accept || clazz.reject) {
          var items = evt.dataTransfer.items;
          if (items != null) {
            var pattern = attrGetter('ngfPattern', scope, {$event: evt});
            for (var i = 0; i < items.length; i++) {
              if (items[i].kind === 'file' || items[i].kind === '') {
                if (!upload.validatePattern(items[i], pattern)) {
                  dClass = clazz.reject;
                  break;
                } else {
                  dClass = clazz.accept;
                }
              }
            }
          }
        }
      }
      callback(dClass);
    }

    function extractFiles(evt, callback, allowDir, multiple) {
      var files = [], processing = 0;

      function traverseFileTree(files, entry, path) {
        if (entry != null) {
          if (entry.isDirectory) {
            var filePath = (path || '') + entry.name;
            files.push({name: entry.name, type: 'directory', path: filePath});
            var dirReader = entry.createReader();
            var entries = [];
            processing++;
            var readEntries = function () {
              dirReader.readEntries(function (results) {
                try {
                  if (!results.length) {
                    for (var i = 0; i < entries.length; i++) {
                      traverseFileTree(files, entries[i], (path ? path : '') + entry.name + '/');
                    }
                    processing--;
                  } else {
                    entries = entries.concat(Array.prototype.slice.call(results || [], 0));
                    readEntries();
                  }
                } catch (e) {
                  processing--;
                  console.error(e);
                }
              }, function () {
                processing--;
              });
            };
            readEntries();
          } else {
            processing++;
            entry.file(function (file) {
              try {
                processing--;
                file.path = (path ? path : '') + file.name;
                files.push(file);
              } catch (e) {
                processing--;
                console.error(e);
              }
            }, function () {
              processing--;
            });
          }
        }
      }

      var items = evt.dataTransfer.items;

      if (items && items.length > 0 && $location.protocol() !== 'file') {
        for (var i = 0; i < items.length; i++) {
          if (items[i].webkitGetAsEntry && items[i].webkitGetAsEntry() && items[i].webkitGetAsEntry().isDirectory) {
            var entry = items[i].webkitGetAsEntry();
            if (entry.isDirectory && !allowDir) {
              continue;
            }
            if (entry != null) {
              traverseFileTree(files, entry);
            }
          } else {
            var f = items[i].getAsFile();
            if (f != null) files.push(f);
          }
          if (!multiple && files.length > 0) break;
        }
      } else {
        var fileList = evt.dataTransfer.files;
        if (fileList != null) {
          for (var j = 0; j < fileList.length; j++) {
            files.push(fileList.item(j));
            if (!multiple && files.length > 0) {
              break;
            }
          }
        }
      }
      var delays = 0;
      (function waitForProcess(delay) {
        $timeout(function () {
          if (!processing) {
            if (!multiple && files.length > 1) {
              i = 0;
              while (files[i].type === 'directory') i++;
              files = [files[i]];
            }
            callback(files);
          } else {
            if (delays++ * 10 < 20 * 1000) {
              waitForProcess(10);
            }
          }
        }, delay || 0);
      })();
    }
  }

  function dropAvailable() {
    var div = document.createElement('div');
    return ('draggable' in div) && ('ondrop' in div);
  }

})();


text:
using Autofac.Integration.WebApi;
using Common.Logging;
using Newtonsoft.Json;
using ReMi.Common.Utils;
using ReMi.Common.WebApi.Exceptions;
using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dependencies;
using ReMi.Contracts.Cqrs.Commands;

namespace ReMi.Api.Insfrastructure.Commands
{
    public class CommandProcessor : ICommandProcessor
    {
        public IClientRequestInfoRetriever ClientRequestInfoRetriever { get; set; }

        private readonly IDependencyResolver _resolver = GlobalConfiguration.Configuration.DependencyResolver;

        private readonly ILog _log = LogManager.GetCurrentClassLogger();

        public HttpResponseMessage HandleRequest(HttpActionContext actionContext, string commandName, bool isSynchronous)
        {
            var command = RetrieveCommandExecution(actionContext.ControllerContext, commandName);

            if (command == null)
            {
                return actionContext.Request.CreateResponse(HttpStatusCode.BadRequest);
            }

            try
            {
                command.CommandContext.IsSynchronous = isSynchronous;
                return ProcessCommnad(actionContext, command);
            }
            catch (Exception ex)
            {
                if (ex.InnerException is HttpResponseException)
                {
                    throw ex.InnerException;
                }
                _log.Error(ex);

                return actionContext.Request.CreateResponse(HttpStatusCode.BadRequest);
            }
        }

        private ICommand RetrieveCommandExecution(HttpControllerContext controllerContext, string commandName)
        {
            try
            {
                _log.DebugFormat(controllerContext.Request.Headers.FormatElements());
                var commandIdHeader = controllerContext.Request.Headers.GetValues("CommandId").FirstOrDefault();
                if (string.IsNullOrWhiteSpace(commandIdHeader)) return null;
                var commandId = Guid.Parse(commandIdHeader);

                var body = controllerContext.Request.Content.ReadAsStringAsync().Result;
                if (string.IsNullOrWhiteSpace(body))
                    throw new Exception("Command's body is empty!");

                var registrations = _resolver.GetRootLifetimeScope().ComponentRegistry.Registrations.ToArray();
                var registration = registrations.FirstOrDefault(x => x.Activator.LimitType.Name.Equals(commandName, StringComparison.CurrentCultureIgnoreCase));
                if (registration == null)
                    throw new CommandNotImplementedException(commandName, commandId);

                var commandType = registration.Activator.LimitType;
                var command = (ICommand)JsonConvert.DeserializeObject(body, commandType);

                if (command == null)
                    throw new CommandDeserializationException(commandName, commandId);

                command.CommandContext = new CommandContext
                {
                    Id = commandId,
                    UserHostAddress = ClientRequestInfoRetriever.UserHostAddress,
                    UserHostName = ClientRequestInfoRetriever.UserHostName
                };

                return command;
            }
            catch (Exception ex)
            {
                _log.Error(ex);
            }

            return null;
        }

        private HttpResponseMessage ProcessCommnad(HttpActionContext actionContext, ICommand command)
        {
            if (command == null) return actionContext.Request.CreateResponse(HttpStatusCode.BadRequest);

            var handler = _resolver.GetService(typeof(ICommandProcessorGeneric<>).MakeGenericType(command.GetType()));

            var method = handler.GetType().GetMethod("HandleRequest", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public);

            var result = method.Invoke(handler, new object[] { actionContext, command });

            return (HttpResponseMessage)result;
        }
    }
}


text:
package eu.monnetproject.clesa.core.tokenizer.latin;

import eu.monnetproject.clesa.core.lang.Script;
import eu.monnetproject.clesa.core.tokenizer.Tokenizer;
import eu.monnetproject.clesa.core.tokenizer.TokenizerFactory;

/**
 *
 * @author jmccrae
 */
public class LatinTokenizerFactory implements TokenizerFactory {

    public Tokenizer getTokenizer(Script script) {
        if(script.equals(Script.LATIN)) {
            return new LatinTokenizerImpl();
        } else {
            return null;
        }
    }

}


text:
var monitorModelAction = require('../../logic/monitorModelLogic.js')
var monitorChecker = require('../../logic/monitorChecker.js')

var Input = {
	accountHashID: {
		require: true
	},
	monitorHashID: {
		required: true
	}
}

exports.monitorModel = {
	name: "monitorModel",
	description: "Get Monitor Model JSON",
	inputs: Input,

	run: function (api, data, next) {
		monitorChecker(api.redisClient, data.params.accountHashID, data.params.monitorHashID, function (err, replies) {
			if (err) {
				data.response.error = err.error
				next(err)
			}
			else {
				monitorModelAction(api.redisClient, data.params.monitorHashID, function (err, replies) {
					if (err) {
						data.response.error = err.error
						next(err)
					}
					else {
						data.response.result = replies
						next()
					}
				})
			}
		})
	}
}


text:
class GeneralParams;

class GetTopKJob : public Job
{
public:
    GetTopKJob(int id, GeneralParams const * const params);
    virtual ~GetTopKJob(){}
    std::unique_ptr<std::pair<const char*, int>, Deleter> GenerateTaskData() const override;
    const char* GetLabel() const override{
        return "Get Top K Documents";
    }
    bool IsAsyncJob() const override {return true;}
    void* const GetTag() const{
        return m_tag;
    }

private:
    void* m_tag;
    std::string m_word;
    int m_k;

};


text:
Flash
=====

PIC32 Flash writing library


text:
#ifdef AWS_MULTI_FRAMEWORK
#import <AWSRuntime/AmazonServiceException.h>
#else
#import "../AmazonServiceException.h"
#endif

/**
 *

 * The Id of a batch entry in a batch request does not abide
 * by the specification.
 *

 */
@interface SQSInvalidBatchEntryIdException:AmazonServiceException
{
}

-(id)initWithMessage:(NSString *)message;

/**
 * Returns a string representation of this object; useful for testing and
 * debugging.
 *
 * @return A string representation of this object.
 */
-(NSString *)description;

@end


text:
#include "setup.hpp"
#include "table_type.hpp"

#include <boost/math/special_functions/bessel.hpp>
#include "libs/math/test/test_bessel_i.hpp"

void expected_results()
{
   //
   // Define the max and mean errors expected for
   // various compilers and platforms.
   //

   //
   // Catch all cases come last:
   //
   add_expected_result(
      ".*",                          // compiler
      ".*",                          // stdlib
      ".*",                          // platform
      ".*",                          // test type(s)
      ".*",                          // test data group
      ".*",                          // test function
      500,                           // Max Peek error
      200);                          // Max mean error

   //
   // Finish off by printing out the compiler/stdlib/platform names,
   // we do this to make it easier to mark up expected error rates.
   //
   std::cout << "Tests run with " << BOOST_COMPILER << ", "
      << BOOST_STDLIB << ", " << BOOST_PLATFORM << std::endl;
}

template <class T>
void test(T t, const char* p)
{
   test_bessel(t, p);
}

BOOST_AUTO_TEST_CASE( test_main )
{
   expected_results();
   ALL_TESTS
}