Esempio n. 1
0
        /// <summary>
        /// Closes this index.
        /// </summary>
        public void Close()
        {
            // Flip that toggle switch
            //if (!string.IsNullOrEmpty(this.toggleFile)) IndexMap.HitTheJackalSwitch(this.toggleFile);
            if (this.writer != null)
            {
                this.writer.Close();
            }
            if (this.openDirectory != null)
            {
                this.openDirectory.Close();
            }
            this.writer        = null;
            this.openDirectory = null;

            this.index.Refresh();
            if (this.index.IndexStructure == IndexType.DoubleIndex)
            {
                ((IDoubleIndex)this.index).FlipToggleSwitch();
            }
            else if (this.index.IndexStructure == IndexType.CyclicalIndex)
            {
                ICyclicalIndex ci = (ICyclicalIndex)this.index;
                ci.CopyMirror();
                ci.FlipToggleSwitch();
            }

            this.isDisposed = true;
            LibraryAnalysis.Fire(new IndexInfo(this.index.IndexDirectory.Parent.FullName, this.index.IndexDirectory.Name, this.totalWrites, this.optimized, DateTime.Now));
        }
Esempio n. 2
0
        /// <summary>
        /// Retrieves data from this index.
        /// </summary>
        /// <param name="topNResults">The number of results to return from this index</param>
        /// <param name="buildFieldFiltersFromAllData">Specifies whether distinct values from all fields should be stored, even if all actual results are not returned from the index</param>
        /// <param name="filterFieldNames">The field names to build filters from</param>
        /// <returns>A <see cref="IndexLibrary.SearchResultDataSet"/> that contains all data from this index</returns>
        /// <remarks>
        /// filterFieldNames was added as a parameter to allow you to only pull data from specific fields into the filters,
        /// this can significantly increase the performance and the total amount of time required by this method.
        /// </remarks>
        public virtual SearchResultDataSet ReadDocuments(int topNResults, bool buildFieldFiltersFromAllData, string[] filterFieldNames)
        {
            if (this.isDisposed)
            {
                throw new ObjectDisposedException("IndexReader", "You cannot call RetrieveIndex(int, string[], bool) from a disposed IndexReader");
            }
            if (topNResults == -1)
            {
                topNResults = this.TotalDocuments;
            }
            if (topNResults <= 0)
            {
                return(new SearchResultDataSet());
            }

            bool filterAll = (filterFieldNames == null || filterFieldNames.Length == 0);
            SearchResultDataSet dataSet = new SearchResultDataSet();
            int resultsToCollect        = this.TotalDocuments;

            if (OnBeginRead(new ReaderEventArgs(this.index.IndexDirectory.FullName, topNResults, buildFieldFiltersFromAllData, filterFieldNames)))
            {
                OnEndRead(new ReaderEventArgs(this.index.IndexDirectory.FullName, topNResults, buildFieldFiltersFromAllData, filterFieldNames));
                LibraryAnalysis.Fire(new ReadInfo(this.index.IndexDirectory.FullName, resultsToCollect, this.TotalDocuments, buildFieldFiltersFromAllData, this.IsOptimized));
                return(dataSet);
            }

            if (!buildFieldFiltersFromAllData && topNResults < this.TotalDocuments)
            {
                resultsToCollect = topNResults;
            }
            LibraryAnalysis.Fire(new ReadInfo(this.index.IndexDirectory.FullName, topNResults, this.TotalDocuments, buildFieldFiltersFromAllData, this.isDisposed));

            for (int i = 0; i < resultsToCollect; i++)
            {
                bool pastWantedResults = (buildFieldFiltersFromAllData && i >= topNResults);

                Lucene29.Net.Documents.Document document  = this.luceneReader.Document(i);
                System.Collections.IList        fieldList = document.GetFields();
                Dictionary <string, string>     values    = new Dictionary <string, string>();
                int totalValues = 0;
                int totalFields = fieldList.Count;
                for (int j = 0; j < totalFields; j++)
                {
                    if (fieldList[j] == null)
                    {
                        continue;
                    }
                    Lucene29.Net.Documents.Field field = fieldList[j] as Lucene29.Net.Documents.Field;
                    string name  = field.Name();
                    string value = field.StringValue();

                    if (filterAll || filterFieldNames.Contains(name))
                    {
                        SearchResultFilter filter = null;
                        if (!dataSet.ContainsFilter(name))
                        {
                            filter = new SearchResultFilter(name);
                            dataSet.AddFilter(filter);
                        }
                        else
                        {
                            filter = dataSet.GetFilter(name);
                        }

                        if (!filter.ContainsKey(value))
                        {
                            filter.AddValue(new KeyValuePair <string, bool>(value, true));
                        }
                    }

                    if (values.ContainsKey(name))
                    {
                        int revision = 1;
                        while (values.ContainsKey(name + "(" + revision.ToString() + ")"))
                        {
                            revision++;
                        }
                        name += "(" + revision.ToString() + ")";
                    }
                    values.Add(name, value);
                    if (OnReadResultFound(new ReaderEventArgs(this.index.IndexDirectory.FullName, topNResults, buildFieldFiltersFromAllData, filterFieldNames)))
                    {
                        OnEndRead(new ReaderEventArgs(this.index.IndexDirectory.FullName, topNResults, buildFieldFiltersFromAllData, filterFieldNames));
                        LibraryAnalysis.Fire(new ReadInfo(this.index.IndexDirectory.FullName, resultsToCollect, this.TotalDocuments, buildFieldFiltersFromAllData, this.IsOptimized));
                        return(dataSet);
                    }
                    ++totalValues;
                }
                if (totalValues > 0 && !pastWantedResults)
                {
                    dataSet.AddSearchResult(new SearchResult(values, this.index.IndexDirectory.FullName, 1f));
                }
            }

            OnEndRead(new ReaderEventArgs(this.index.IndexDirectory.FullName, topNResults, buildFieldFiltersFromAllData, filterFieldNames));

            return(dataSet);
        }
Esempio n. 3
0
        /// <summary>
        /// Performs a search against a set of indexes.
        /// </summary>
        /// <param name="builder">The query to run against the indexes.</param>
        /// <param name="totalResultsRequested">The total number of results to return.</param>
        /// <returns>a list of <see cref="IndexLibrary.SearchResult"/>, one for each result found.</returns>
        /// <remarks>
        /// Designed to be used for the majority of searches. The functionality contained in this
        /// method is used for a normal search, i.e. enter a term, search, get results.
        /// </remarks>
        public virtual IEnumerable <SearchResult> Search(QueryBuilder builder, int totalResultsRequested)
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder", "builder cannot be null");
            }
            List <SearchResult> results = new List <SearchResult>();

            if (OnBeginSearch(new MultiSearcherEventArgs(this.IndexNames, SearchMethodType.Quick, SearchMethodLocation.Beginning, null)) || totalResultsRequested < -1 || totalResultsRequested == 0)
            {
                OnEndSearch(new MultiSearcherEventArgs(this.IndexNames, SearchMethodType.Quick, SearchMethodLocation.Ending, null));
                LibraryAnalysis.Fire(new SearchInfo(this.IndexNamesConcatenated, builder.ToString(), SearchMethodType.Normal, 0, true));
                return(results);
            }

            Lucene29.Net.Store.Directory             directory   = null;
            Lucene29.Net.Search.MultiSearcher        searcher    = null;
            List <Lucene29.Net.Search.IndexSearcher> searchables = null;
            int  hitsLength = 0;
            bool canceled   = false;

            try {
                searchables = new List <Lucene29.Net.Search.IndexSearcher>();
                for (int i = 0; i < this.indexes.Count; i++)
                {
                    DirectoryInfo searchInfo = null;
                    if (!GetIndexReadDirectory(this.indexes[i], out searchInfo))
                    {
                        continue;
                    }
                    searchables.Add(new Lucene29.Net.Search.IndexSearcher(Lucene29.Net.Store.FSDirectory.Open(searchInfo), true));
                }
                if (searchables.Count == 0)
                {
                    OnEndSearch(new MultiSearcherEventArgs(this.IndexNames, SearchMethodType.Quick, SearchMethodLocation.Ending, null));
                    return(results);
                }
                searcher = new Lucene29.Net.Search.MultiSearcher(searchables.ToArray());
                Lucene29.Net.Search.TopDocs topDocs = searcher.Search(builder.GetLuceneQuery, (totalResultsRequested == -1) ? StaticValues.DefaultDocsToReturn : totalResultsRequested);

                hitsLength = (totalResultsRequested == -1) ? topDocs.totalHits : Math.Min(topDocs.totalHits, totalResultsRequested);
                if (hitsLength > 5000)
                {
                    hitsLength = 5000;
                }
                int resultsFound = 0;
                for (int i = 0; i < hitsLength; i++)
                {
                    int      docID    = topDocs.scoreDocs[i].doc;
                    Document document = searcher.Doc(docID);
                    System.Collections.IList    fieldList = document.GetFields();
                    Dictionary <string, string> values    = new Dictionary <string, string>();
                    int totalValues = 0;
                    int totalFields = fieldList.Count;
                    for (int j = 0; j < totalFields; j++)
                    {
                        if (fieldList[j] == null)
                        {
                            continue;
                        }
                        Field field = fieldList[j] as Field;
                        values.Add(field.Name(), field.StringValue());
                        ++totalValues;
                    }
                    if (totalValues > 0)
                    {
                        SearchResult result = new SearchResult(values, string.Join(", ", this.IndexNames), topDocs.scoreDocs[i].score);
                        results.Add(result);
                        resultsFound++;
                        if (OnSearchResultFound(new MultiSearcherEventArgs(this.IndexNames, SearchMethodType.Normal, SearchMethodLocation.ResultFound, result)))
                        {
                            canceled = true;
                            break;
                        }
                    }
                }
            }
            finally {
                if (searcher != null)
                {
                    searcher.Close();
                }
                if (searchables != null)
                {
                    searchables.ForEach(x => x.Close());
                }
                if (directory != null)
                {
                    directory.Close();
                }

                OnEndSearch(new MultiSearcherEventArgs(this.IndexNames, SearchMethodType.Quick, SearchMethodLocation.Ending, null));
                LibraryAnalysis.Fire(new SearchInfo(this.IndexNamesConcatenated, builder.ToString(), SearchMethodType.Normal, hitsLength, canceled));
            }

            return(results);
        }
Esempio n. 4
0
        /// <summary>
        /// Performs a full search against a set of indexes.
        /// </summary>
        /// <param name="builder">The query to run against the indexes.</param>
        /// <param name="totalResultsRequested">The total number of results to return.</param>
        /// <param name="fieldFilterNames">An exclusive list of fields to retrieve from the indexes.</param>
        /// <returns>A <see cref="IndexLibrary.SearchResultDataSet"/> that contains distinct values for each specified field and all search results</returns>
        /// <remarks>
        /// Used when you want to create filter type results such as http://www.kayak.com when you perform
        /// a search for an airline. A list of distinct values for all fields is displayed so you can filter down
        /// your results. This method performs the same functionality.
        /// </remarks>
        public virtual SearchResultDataSet FullSearch(QueryBuilder builder, int totalResultsRequested, string[] fieldFilterNames)
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder", "builder cannot be null");
            }
            SearchResultDataSet dataSet = new SearchResultDataSet();
            bool getAllFilters          = (fieldFilterNames == null || fieldFilterNames.Length == 0);

            if (OnBeginSearch(new MultiSearcherEventArgs(this.IndexNames, SearchMethodType.Quick, SearchMethodLocation.Beginning, null)) || totalResultsRequested < -1 || totalResultsRequested == 0)
            {
                OnEndSearch(new MultiSearcherEventArgs(this.IndexNames, SearchMethodType.Quick, SearchMethodLocation.Ending, null));
                LibraryAnalysis.Fire(new SearchInfo(this.IndexNamesConcatenated, builder.ToString(), SearchMethodType.Full, 0, true));
                return(dataSet);
            }

            Lucene29.Net.Store.Directory             directory   = null;
            Lucene29.Net.Search.MultiSearcher        searcher    = null;
            List <Lucene29.Net.Search.IndexSearcher> searchables = null;
            int  hitsLength = 0;
            bool canceled   = false;

            try {
                searchables = new List <Lucene29.Net.Search.IndexSearcher>();
                for (int i = 0; i < this.indexes.Count; i++)
                {
                    DirectoryInfo searchInfo = null;
                    if (!GetIndexReadDirectory(this.indexes[i], out searchInfo))
                    {
                        continue;
                    }
                    searchables.Add(new Lucene29.Net.Search.IndexSearcher(Lucene29.Net.Store.FSDirectory.Open(searchInfo), true));
                }

                if (searchables.Count == 0)
                {
                    OnEndSearch(new MultiSearcherEventArgs(this.IndexNames, SearchMethodType.Quick, SearchMethodLocation.Ending, null));
                    return(dataSet);
                }
                searcher = new Lucene29.Net.Search.MultiSearcher(searchables.ToArray());
                Lucene29.Net.Search.TopDocs topDocs = searcher.Search(builder.GetLuceneQuery, (totalResultsRequested == -1) ? StaticValues.DefaultDocsToReturn : totalResultsRequested);

                hitsLength = (totalResultsRequested == -1) ? topDocs.totalHits : Math.Min(topDocs.totalHits, totalResultsRequested);
                if (hitsLength > 5000)
                {
                    hitsLength = 5000;
                }
                int resultsFound = 0;
                for (int i = 0; i < hitsLength; i++)
                {
                    int      docID    = topDocs.scoreDocs[i].doc;
                    Document document = searcher.Doc(docID);
                    System.Collections.IList    fieldList = document.GetFields();
                    Dictionary <string, string> values    = new Dictionary <string, string>();
                    int totalValues = 0;
                    int totalFields = fieldList.Count;
                    for (int j = 0; j < totalFields; j++)
                    {
                        if (fieldList[j] == null)
                        {
                            continue;
                        }
                        Field  field = fieldList[j] as Field;
                        string name  = field.Name();
                        string value = field.StringValue();
                        field = null;

                        if (getAllFilters || fieldFilterNames.Contains(name))
                        {
                            SearchResultFilter filter = null;
                            if (!dataSet.ContainsFilter(name))
                            {
                                filter = new SearchResultFilter(name);
                                dataSet.AddFilter(filter);
                            }
                            else
                            {
                                filter = dataSet.GetFilter(name);
                            }

                            if (!filter.ContainsKey(value))
                            {
                                filter.AddValue(new KeyValuePair <string, bool>(value, true));
                            }
                        }

                        if (values.ContainsKey(name))
                        {
                            int revision = 1;
                            while (values.ContainsKey(name + "(" + revision.ToString() + ")"))
                            {
                                revision++;
                            }
                            name += "(" + revision.ToString() + ")";
                        }
                        values.Add(name, value);
                        ++totalValues;
                    }
                    if (totalValues > 0)
                    {
                        SearchResult result = new SearchResult(values, string.Join(", ", this.IndexNames), topDocs.scoreDocs[i].score);
                        dataSet.AddSearchResult(result);
                        resultsFound++;
                        if (OnSearchResultFound(new MultiSearcherEventArgs(this.IndexNames, SearchMethodType.Full, SearchMethodLocation.ResultFound, result)))
                        {
                            canceled = true;
                            break;
                        }
                    }
                }
            }
            finally {
                if (searcher != null)
                {
                    searcher.Close();
                }
                if (searchables != null)
                {
                    searchables.ForEach(x => x.Close());
                }
                if (directory != null)
                {
                    directory.Close();
                }

                OnEndSearch(new MultiSearcherEventArgs(this.IndexNames, SearchMethodType.Quick, SearchMethodLocation.Ending, null));
                LibraryAnalysis.Fire(new SearchInfo(this.IndexNamesConcatenated, builder.ToString(), SearchMethodType.Full, hitsLength, canceled));
            }

            return(dataSet);
        }
Esempio n. 5
0
        /// <summary>
        /// Performs a search against an index.
        /// </summary>
        /// <param name="builder">The query to run against the index.</param>
        /// <param name="totalResultsRequested">The total number of results to return.</param>
        /// <returns>a list of <see cref="IndexLibrary.SearchResult"/>, one for each result found.</returns>
        /// <remarks>
        /// Designed to be used for the majority of searches. The functionality contained in this
        /// method is used for a normal search, i.e. enter a term, search, get results.
        /// </remarks>
        public virtual IEnumerable <SearchResult> Search(QueryBuilder builder, int totalResultsRequested)
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder", "builder cannot be null");
            }
            List <SearchResult> results = new List <SearchResult>();

            if (OnBeginSearch(new SearcherEventArgs(this.index.IndexDirectory.Name, this.index.IndexStructure, SearchMethodType.Normal, SearchMethodLocation.Beginning, null)))
            {
                OnEndSearch(new SearcherEventArgs(this.index.IndexDirectory.Name, this.index.IndexStructure, SearchMethodType.Normal, SearchMethodLocation.Ending, null));
                LibraryAnalysis.Fire(new SearchInfo(this.index.IndexDirectory.Name, builder.ToString(), SearchMethodType.Normal, 0, true));
                return(results);
            }

            this.index.Refresh();
            DirectoryInfo searchDirectory = null;
            bool          hasIndexFiles   = GetIndexReadDirectory(out searchDirectory);

            if ((totalResultsRequested < -1 || totalResultsRequested == 0) || (!hasIndexFiles))
            {
                OnEndSearch(new SearcherEventArgs(this.index.IndexDirectory.Name, this.index.IndexStructure, SearchMethodType.Normal, SearchMethodLocation.Ending, null));
                LibraryAnalysis.Fire(new SearchInfo(this.index.IndexDirectory.Name, builder.ToString(), SearchMethodType.Normal, 0, true));
                return(results);
            }

            Lucene29.Net.Store.Directory      directory = null;
            Lucene29.Net.Search.IndexSearcher searcher  = null;
            int  hitsLength = 0;
            bool canceled   = false;

            try {
                directory = Lucene29.Net.Store.FSDirectory.Open(searchDirectory);
                searcher  = new Lucene29.Net.Search.IndexSearcher(directory, true);
                Lucene29.Net.Search.TopDocs topDocs = searcher.Search(builder.GetLuceneQuery, (totalResultsRequested == -1) ? StaticValues.DefaultDocsToReturn : totalResultsRequested);

                hitsLength = (totalResultsRequested == -1) ? topDocs.totalHits : Math.Min(topDocs.totalHits, totalResultsRequested);
                if (hitsLength > 5000)
                {
                    hitsLength = 5000;
                }
                int resultsFound = 0;
                for (int i = 0; i < hitsLength; i++)
                {
                    int      docID    = topDocs.scoreDocs[i].doc;
                    Document document = searcher.Doc(docID);
                    System.Collections.IList    fieldList = document.GetFields();
                    Dictionary <string, string> values    = new Dictionary <string, string>();
                    int totalValues = 0;
                    int totalFields = fieldList.Count;
                    for (int j = 0; j < totalFields; j++)
                    {
                        if (fieldList[j] == null)
                        {
                            continue;
                        }
                        Field  field       = fieldList[j] as Field;
                        string name        = field.Name();
                        int    renameCount = 1;
                        while (values.ContainsKey(name))
                        {
                            name = field.Name() + "(" + renameCount.ToString() + ")";
                            renameCount++;
                        }
                        values.Add(name, field.StringValue());
                        ++totalValues;
                    }
                    if (totalValues > 0)
                    {
                        SearchResult result = new SearchResult(values, this.index.IndexDirectory.Name, topDocs.scoreDocs[i].score);
                        results.Add(result);
                        resultsFound++;
                        if (OnSearchResultFound(new SearcherEventArgs(this.index.IndexDirectory.Name, this.index.IndexStructure, SearchMethodType.Normal, SearchMethodLocation.ResultFound, result)))
                        {
                            canceled = true;
                            break;
                        }
                    }
                }
            }
            finally {
                if (searcher != null)
                {
                    searcher.Close();
                }
                if (directory != null)
                {
                    directory.Close();
                }

                OnEndSearch(new SearcherEventArgs(this.index.IndexDirectory.Name, this.index.IndexStructure, SearchMethodType.Normal, SearchMethodLocation.Ending, null));
                LibraryAnalysis.Fire(new SearchInfo(this.index.IndexDirectory.Name, builder.ToString(), SearchMethodType.Normal, hitsLength, canceled));
            }

            return(results);
        }
Esempio n. 6
0
        /// <summary>
        /// Performs a quick search against an index.
        /// </summary>
        /// <param name="builder">The query to run against the index.</param>
        /// <param name="fieldName">Name of the field to return from the index.</param>
        /// <param name="totalResultsRequested">The total number of results to return.</param>
        /// <returns>A list of strings, one for each result found</returns>
        /// <remarks>
        /// Designed to be used for 'quick' type searches such as those used for type-ahead features or
        /// searches where only a single column needs to be returned.
        /// </remarks>
        public IEnumerable <string> QuickSearch(QueryBuilder builder, string fieldName, int totalResultsRequested)
        {
            if (builder == null)
            {
                throw new ArgumentNullException("builder", "builder cannot be null");
            }
            List <string> results = new List <string>();

            if (OnBeginSearch(new SearcherEventArgs(this.index.IndexDirectory.Name, this.index.IndexStructure, SearchMethodType.Quick, SearchMethodLocation.Beginning, null)))
            {
                OnEndSearch(new SearcherEventArgs(this.index.IndexDirectory.Name, this.index.IndexStructure, SearchMethodType.Quick, SearchMethodLocation.Ending, null));
                LibraryAnalysis.Fire(new SearchInfo(this.index.IndexDirectory.Name, builder.ToString(), SearchMethodType.Quick, 0, true));
                return(results);
            }
            this.index.Refresh();

            DirectoryInfo searchDirectory = null;
            bool          hasIndexFiles   = GetIndexReadDirectory(out searchDirectory);

            if ((totalResultsRequested < -1 || totalResultsRequested == 0) || (!hasIndexFiles))
            {
                OnEndSearch(new SearcherEventArgs(this.index.IndexDirectory.Name, this.index.IndexStructure, SearchMethodType.Quick, SearchMethodLocation.Ending, null));
                LibraryAnalysis.Fire(new SearchInfo(this.index.IndexDirectory.Name, builder.ToString(), SearchMethodType.Quick, 0, true));
                return(results);
            }

            Lucene29.Net.Store.Directory      directory = null;
            Lucene29.Net.Search.IndexSearcher searcher  = null;
            int  hitsLength = 0;
            bool canceled   = false;

            try {
                directory = Lucene29.Net.Store.FSDirectory.Open(searchDirectory);
                searcher  = new Lucene29.Net.Search.IndexSearcher(directory, true);
                Lucene29.Net.Search.TopDocs topDocs = searcher.Search(builder.GetLuceneQuery, (totalResultsRequested == -1) ? StaticValues.DefaultDocsToReturn : totalResultsRequested);

                hitsLength = (totalResultsRequested == -1) ? topDocs.totalHits : Math.Min(topDocs.totalHits, totalResultsRequested);
                if (hitsLength > 5000)
                {
                    hitsLength = 5000;
                }
                int resultsFound = 0;
                for (int i = 0; i < hitsLength; i++)
                {
                    int      docID    = topDocs.scoreDocs[i].doc;
                    Document document = searcher.Doc(docID);
                    System.Collections.IList fieldList = document.GetFields();
                    //Dictionary<string, string> values = new Dictionary<string, string>();
                    int   totalFields    = fieldList.Count;
                    Field collectedField = null;
                    for (int j = 0; j < totalFields; j++)
                    {
                        if (fieldList[j] == null)
                        {
                            continue;
                        }
                        collectedField = fieldList[j] as Field;
                        if (collectedField.Name().Equals(fieldName, StringComparison.CurrentCultureIgnoreCase))
                        {
                            break;
                        }
                        collectedField = null;
                    }
                    if (collectedField != null)
                    {
                        results.Add(collectedField.StringValue());
                        resultsFound++;
                        if (OnSearchResultFound(new SearcherEventArgs(this.index.IndexDirectory.Name, this.index.IndexStructure, SearchMethodType.Quick, SearchMethodLocation.ResultFound, collectedField.Name(), collectedField.StringValue(), topDocs.scoreDocs[i].score)))
                        {
                            canceled = true;
                            break;
                        }
                    }
                }
            }
            finally {
                if (searcher != null)
                {
                    searcher.Close();
                }
                if (directory != null)
                {
                    directory.Close();
                }

                OnEndSearch(new SearcherEventArgs(this.index.IndexDirectory.Name, this.index.IndexStructure, SearchMethodType.Quick, SearchMethodLocation.Ending, null));
                LibraryAnalysis.Fire(new SearchInfo(this.index.IndexDirectory.Name, builder.ToString(), SearchMethodType.Quick, hitsLength, canceled));
            }

            return(results);
        }