private void RegisterActor(XMLQuarkSubscription sub, bool isRoot)
        {
            HashSet <string> activeQuarks  = SyncQuark.DecodeSyncQuarks(sub.activeQuarks);
            HashSet <string> passiveQuarks = SyncQuark.DecodeSyncQuarks(sub.passiveQuarks);
            QuarkPublisher   qp;

            // Save SyncID to XMLQuarkSubscription, if we need the info later
            if (m_actor.ContainsKey(sub.actorID))
            {
                UnRegisterActor(sub.actorID);
            }
            if (isRoot)
            {
                RootInfo root = new RootInfo();
                root.quarkAddress = sub.rootAddress;
                root.syncAddress  = sub.syncListenerAddress;
                root.Roots.Add(root);
                m_actor[sub.actorID] = root;
                m_rootActors.Add((RootInfo)m_actor[sub.actorID]);
            }
            else
            {
                if (sub.syncListenerAddress.Length > 0)
                {
                    RelayActor relActor = new RelayActor();
                    relActor.syncAddress = sub.syncListenerAddress;
                    m_actor[sub.actorID] = relActor;
                }
                else
                {
                    Actor actor = new Actor();
                    m_actor[sub.actorID] = actor;
                }
                // Note: Adding all the roots as this actor's root for now.
                foreach (RootInfo root in m_rootActors)
                {
                    m_actor[sub.actorID].Roots.Add(root);
                }
            }
            m_actor[sub.actorID].ActiveQuarks  = activeQuarks;
            m_actor[sub.actorID].PassiveQuarks = passiveQuarks;

            m_actor[sub.actorID].XmlSubscription = sub;

            foreach (string quark in activeQuarks)
            {
                if (!QuarkSubscriptions.TryGetValue(quark, out qp))
                {
                    qp = new QuarkPublisher(new SyncQuark(quark));
                    QuarkSubscriptions.Add(quark, qp);
                }
                qp.AddActiveSubscriber(sub.actorID);
                if (isRoot)
                {
                    qp.SetRootActor(sub.actorID);
                }
            }

            foreach (string quark in passiveQuarks)
            {
                if (!QuarkSubscriptions.TryGetValue(quark, out qp))
                {
                    qp = new QuarkPublisher(new SyncQuark(quark));
                    QuarkSubscriptions.Add(quark, qp);
                }
                qp.AddPassiveSubscriber(sub.actorID);
            }
        }
        /// <summary>
        /// Handles a quark crossing request. Checks to see if the request is possible, and returns true or false based on
        /// the validity of the crossing to the actor who requested. This is performed in 3 steps:
        /// Step 1: Tell root to be ready to receive crossing requests for the object
        /// Root will also do sanity checks (e.g. object was deleted before crossing), so checking actorStatus code
        /// is important.
        /// Step 2: Root provides URL for uploading updated properties and for downloading said object.
        /// Step 3: Tell actor about the URL where it may contact the root directly.
        /// TODO: This can be optimized if we are allowed to remember or calculate the URL. We could respond immediately with the URL
        /// and the actor would keep trying it until root accepts it. For now, we avoid concurrency.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="actorRequest"></param>
        private void HandleCrossing(HttpListenerContext context, HttpListenerRequest actorRequest)
        {
            StreamReader    actorReader = new StreamReader(actorRequest.InputStream);
            XmlSerializer   deserializer = new XmlSerializer(typeof(CrossingRequest));
            CrossingRequest cross = (CrossingRequest)deserializer.Deserialize(actorReader);
            QuarkPublisher  curQp = null, prevQp = null;
            string          url = "";
            HttpStatusCode  status;

            m_crossLock.EnterReadLock();
            try
            {
                m_log.InfoFormat("{0}: Handling Crossing. Time: {1}", LogHeader, DateTime.Now.Ticks);
                if (m_quarkSubscriptions.TryGetValue(cross.curQuark, out curQp) && m_quarkSubscriptions.TryGetValue(cross.prevQuark, out prevQp))
                {
                    if (curQp.RootActorID != prevQp.RootActorID)
                    {
                        // TODO: Inter-root communication
                    }
                    else
                    {
                        // Actor's response variables
                        HttpListenerResponse actorResponse = context.Response;
                        Stream actorOutput = actorResponse.OutputStream;

                        // Root's request variables
                        RootInfo       root        = (RootInfo)m_actor[curQp.RootActorID];
                        HttpWebRequest rootRequest = (HttpWebRequest)WebRequest.Create("http://" + root.quarkAddress + "/cross/");
                        rootRequest.Credentials = CredentialCache.DefaultCredentials;
                        rootRequest.Method      = "POST";
                        rootRequest.ContentType = "text/json";
                        Stream rootOutput = rootRequest.GetRequestStream();

                        status = ValidateCrossing(cross);
                        if (status != HttpStatusCode.Created)
                        {
                            actorResponse.StatusCode = (int)status;
                            actorOutput.Close();
                            actorResponse.Close();
                            return;
                        }
                        // From here on, I might have to write, make sure we only do one of these at a time.
                        // Can't go in UpgradeableLock with a ReadLock, so let go first.
                        m_crossLock.ExitReadLock();
                        m_crossLock.EnterUpgradeableReadLock();
                        try
                        {
                            // First we double check nothing changed while we were waiting for the lock, and we are still valid to cross.
                            status = ValidateCrossing(cross);
                            if (status != HttpStatusCode.Created)
                            {
                                actorResponse.StatusCode = (int)status;
                                actorOutput.Close();
                                actorResponse.Close();
                                return;
                            }

                            // Step 1: Tell root to be ready to receive crossing requests for the object
                            // Root will also do sanity checks (e.g. object was deleted before crossing), so checking actorStatus code
                            // is important.
                            OSDMap DataMap = new OSDMap();
                            DataMap["uuid"] = OSD.FromUUID(cross.uuid);
                            DataMap["pq"]   = OSD.FromString(cross.prevQuark);
                            DataMap["cq"]   = OSD.FromString(cross.curQuark);
                            DataMap["ts"]   = OSD.FromLong(cross.timestamp);

                            string encodedMap     = OSDParser.SerializeJsonString(DataMap, true);
                            byte[] rootData       = System.Text.Encoding.ASCII.GetBytes(encodedMap);
                            int    rootDataLength = rootData.Length;
                            rootOutput.Write(rootData, 0, rootDataLength);
                            rootOutput.Close();

                            // Step 2: Root provides URL for uploading updated properties and for downloading said object.
                            HttpWebResponse response = (HttpWebResponse)rootRequest.GetResponse();
                            if (HttpStatusCode.OK == response.StatusCode)
                            {
                                m_crossLock.EnterWriteLock();
                                try
                                {
                                    m_crossings[cross.uuid]       = new CurrentCrossings();
                                    m_crossings[cross.uuid].cross = cross;
                                    m_crossings[cross.uuid].actors.UnionWith(m_quarkSubscriptions[cross.prevQuark].GetAllQuarkSubscribers());
                                    m_crossings[cross.uuid].actors.UnionWith(m_quarkSubscriptions[cross.curQuark].GetAllQuarkSubscribers());
                                    // Remove the starting actor from the list of actors to ACK.
                                    m_crossings[cross.uuid].actors.Remove(cross.actorID);
                                    m_crossings[cross.uuid].rootHandler = root;
                                }
                                finally
                                {
                                    m_crossLock.ExitWriteLock();
                                }
                                Stream       respData   = response.GetResponseStream();
                                StreamReader rootReader = new StreamReader(respData);
                                url = rootReader.ReadToEnd();
                                m_log.WarnFormat("{0}: Got URL for object request from server: {1}", LogHeader, url);
                                if (url.Length > 0)
                                {
                                    // Step 3: Tell actor about the URL where it may contact the root directly.
                                    // TODO: This can be optimized if we are allowed to remember or calculate the URL. We could respond immediately with the URL
                                    // and the actor would keep trying it until root accepts it. For now, we avoid concurrency.
                                    actorResponse.StatusCode = (int)HttpStatusCode.Created;
                                    byte[] actorUrlData       = System.Text.Encoding.ASCII.GetBytes(url);
                                    int    actorUrlDataLength = actorUrlData.Length;
                                    actorOutput.Write(actorUrlData, 0, actorUrlDataLength);
                                    actorOutput.Close();
                                    actorResponse.Close();
                                }
                                else
                                {
                                    m_log.ErrorFormat("{0}: Received empty URL from Root", LogHeader);
                                }
                            }
                            else
                            {
                                m_log.ErrorFormat("{0}: Failed to request crossing from root. Error Code: {1}", LogHeader, response.StatusCode);
                            }
                        }
                        finally
                        {
                            m_crossLock.ExitUpgradeableReadLock();
                        }
                    }
                }
            }
            catch (Exception e)
            {
                m_log.ErrorFormat("{0}: Failed to request crossing from root and forward to actor. Exception: {1}\n{2}", LogHeader, e, e.StackTrace);
            }
            finally
            {
                if (m_crossLock.IsReadLockHeld)
                {
                    m_crossLock.ExitReadLock();
                }
            }
        }