public static CatalogItem CreateCatalogItem(Stream stream, DateTime?refreshed, string packageHash, string originName, DateTime?createdDate = null, DateTime?lastEditedDate = null, DateTime?publishedDate = null)
        {
            try
            {
                Tuple <XDocument, IEnumerable <PackageEntry>, long, string> metadata = GetNupkgMetadata(stream, packageHash);

                // additional sections
                var addons = new GraphAddon[] { GetPackedData(stream, originName) };

                return(new NuspecPackageCatalogItem(metadata.Item1, refreshed, metadata.Item2, metadata.Item3, metadata.Item4, addons, createdDate, lastEditedDate, publishedDate));
            }
            catch (InvalidDataException e)
            {
                Trace.TraceError("Exception: {0} {1} {2}", originName, e.GetType().Name, e.Message);
                return(null);
            }
            catch (Exception e)
            {
                throw new Exception(string.Format("Exception processsing {0}", originName), e);
            }
        }
        public override async Task RunCore(CancellationToken cancellationToken)
        {
            TimeSpan hold = TimeSpan.FromMinutes(90);

            var messages = Queue.GetMessages(32, hold).ToList();

            var qClient = Account.CreateCloudQueueClient();
            var queue = qClient.GetQueueReference(CantonConstants.CatalogPageQueue);

            while (messages.Count > 0)
            {
                foreach (var message in messages)
                {
                    JObject work = JObject.Parse(message.AsString);
                    Uri galleryPageUri = new Uri(work["uri"].ToString());
                    int cantonCommitId = work["cantonCommitId"].ToObject<int>();
                    Log("started cantonCommitId: " + cantonCommitId);

                    try
                    {
                        // read the gallery page
                        JObject galleryPage = await GetJson(galleryPageUri);

                        // graph modififactions
                        GraphAddon[] addons = new GraphAddon[0];
                        //GraphAddon[] addons = new GraphAddon[] { 
                        //        new OriginGraphAddon(galleryPageUri.AbsoluteUri, cantonCommitId),
                        //        new GalleryGraphAddon(galleryPage)
                        //    };

                        string id = galleryPage["id"].ToString();
                        string version = galleryPage["version"].ToString();

                        DateTime? published = null;
                        JToken publishedToken = null;
                        if (galleryPage.TryGetValue("published", out publishedToken))
                        {
                            published = publishedToken.ToObject<DateTime>();
                        }

                        // download the nupkg
                        FileInfo nupkg = await GetNupkg(id, version);

                        Action<Uri> handler = (resourceUri) => QueuePage(resourceUri, Schema.DataTypes.PackageDetails, cantonCommitId, queue);

                        // create the new catalog item
                        using (var stream = nupkg.OpenRead())
                        {
                            // Create the core catalog page graph and upload it
                            using (CatalogPageCreator writer = new CatalogPageCreator(Storage, handler, addons))
                            {
                                CatalogItem catalogItem = Utils.CreateCatalogItem(stream, published, null, nupkg.FullName);
                                writer.Add(catalogItem);
                                await writer.Commit(DateTime.UtcNow, null, cancellationToken);
                            }
                        }

                        // clean up
                        nupkg.Delete();
                    }
                    catch (Exception ex)
                    {
                        LogError("Unable to build catalog page for: " + galleryPageUri.AbsoluteUri + " Error: " + ex.ToString());
                    }
                    finally
                    {
                        _queueTasks.Enqueue(Queue.DeleteMessageAsync(message));

                        bool status = false;
                        if (!_workQueueStatus.TryRemove(cantonCommitId, out status) || status == false)
                        {
                            // we have to send something, the job on the other side should recognize https://failed/
                            QueuePage(new Uri("https://failed/"), Schema.DataTypes.PackageDetails, cantonCommitId, queue);

                            LogError("Unable to build catalog page for: " + galleryPageUri.AbsoluteUri);
                        }
                    }
                }

                // get the next work item
                if (_run)
                {
                    messages = Queue.GetMessages(32, hold).ToList();
                }
                else
                {
                    messages = new List<CloudQueueMessage>();
                }

                // let deletes catch up
                Task task = null;
                while (_queueTasks.TryDequeue(out task))
                {
                    task.Wait();
                }
            }

            // final wait
            Task curTask = null;
            while (_queueTasks.TryDequeue(out curTask))
            {
                curTask.Wait();
            }
        }