partially working new chronochat
diff --git a/src/chat-policy-rule.cpp b/src/chat-policy-rule.cpp
index 1aa8b24..201cf70 100644
--- a/src/chat-policy-rule.cpp
+++ b/src/chat-policy-rule.cpp
@@ -8,33 +8,37 @@
  * Author: Yingdi Yu <yingdi@cs.ucla.edu>
  */
 
-#include "chat-policy-rule.cpp"
+#include "chat-policy-rule.h"
+#include <ndn.cxx/fields/signature-sha256-with-rsa.h>
 
 using namespace ndn;
 using namespace std;
 using namespace ndn::security;
 
 
-ChatPolicyRule::ChatPolicyRule(Ptr<Regex> dataRegex, const Name& dataRef,
-			       Ptr<Regex> signerRegex, const Name& signerRef,
-			       bool isPositive)
-  : PolicyRule(PolicyRule::IDENTITY_POLICY, isPositive)
+ChatPolicyRule::ChatPolicyRule(Ptr<Regex> dataRegex,
+			       Ptr<Regex> signerRegex)
+  : PolicyRule(PolicyRule::IDENTITY_POLICY, true)
   , m_dataRegex(dataRegex)
   , m_signerRegex(signerRegex)
-  , m_dataRef(dataRef)
-  , m_signerRef(signerRef)
+{}
+
+ChatPolicyRule::ChatPolicyRule(const ChatPolicyRule& rule)
+  : PolicyRule(PolicyRule::IDENTITY_POLICY, true)
+  , m_dataRegex(rule.m_dataRegex)
+  , m_signerRegex(rule.m_signerRegex)
 {}
 
 bool 
 ChatPolicyRule::matchDataName(const Data & data)
-{ return (m_dataRegex.match(data.getName()) && m_dataRegex.expand() == m_dataRef) ? true : false; }
+{ return m_dataRegex->match(data.getName()); }
 
 bool 
 ChatPolicyRule::matchSignerName(const Data & data)
 { 
   Ptr<const signature::Sha256WithRsa> sigPtr = DynamicCast<const signature::Sha256WithRsa> (data.getSignature());
   Name signerName = sigPtr->getKeyLocator ().getKeyName ();
-  return (m_signerRegex.match(signerName) && m_signerRegex.expand() == m_signerRef) ? true : false; 
+  return m_signerRegex->match(signerName); 
 }
 
 bool
@@ -43,20 +47,4 @@
 
 bool
 ChatPolicyRule::satisfy(const Name & dataName, const Name & signerName)
-{
-  if (m_dataRegex.match(data.getName()) 
-      && m_dataRegex.expand() == m_dataRef
-      && m_signerRegex.match(signerName) 
-      && m_signerRegex.expand() == m_signerRef)
-    return true;
-  else
-    return false;
-}
-  
-TiXmlElement *
-ChatPolicyRule::toXmlElement()
-{
-  //TODO:
-  return NULL;
-}
-};
+{ return (m_dataRegex->match(dataName) && m_signerRegex->match(signerName)); }
diff --git a/src/chat-policy-rule.h b/src/chat-policy-rule.h
index dfb434d..4534bab 100644
--- a/src/chat-policy-rule.h
+++ b/src/chat-policy-rule.h
@@ -12,36 +12,35 @@
 #define CHAT_POLICY_RULE_H
 
 #include <ndn.cxx/security/policy/policy-rule.h>
+#include <ndn.cxx/regex/regex.h>
 
 class ChatPolicyRule : public ndn::security::PolicyRule
 {
   
 public:
-  ChatPolicyRule();
+  ChatPolicyRule(ndn::Ptr<ndn::Regex> dataRegex,
+                 ndn::Ptr<ndn::Regex> signerRegex);
+
+  ChatPolicyRule(const ChatPolicyRule& rule);
 
   virtual
-  ~ChatPolicyRyle() {};
+  ~ChatPolicyRule() {};
 
   bool 
-  matchDataName(const Data & data);
+  matchDataName(const ndn::Data & data);
 
   bool 
-  matchSignerName(const Data & data);
+  matchSignerName(const ndn::Data & data);
 
   bool
-  satisfy(const Data & data);
+  satisfy(const ndn::Data & data);
 
   bool
-  satisfy(const Name & dataName, const Name & signerName);
+  satisfy(const ndn::Name & dataName, const ndn::Name & signerName);
   
-  TiXmlElement *
-  toXmlElement();
-
 private:
   ndn::Ptr<ndn::Regex> m_dataRegex;
   ndn::Ptr<ndn::Regex> m_signerRegex;
-  ndn::Name m_dataRef;
-  ndn::Name m_signerRef;
 };
 
 #endif //CHAT_POLICY_RULE_H
diff --git a/src/chatdialog.cpp b/src/chatdialog.cpp
index 5f1d3eb..fe7d7b5 100644
--- a/src/chatdialog.cpp
+++ b/src/chatdialog.cpp
@@ -5,67 +5,247 @@
  *
  * BSD license, See the LICENSE file for more information
  *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *         Yingdi Yu <yingdi@cs.ucla.edu>
  */
 
 #include "chatdialog.h"
 #include "ui_chatdialog.h"
 
+#include <QScrollBar>
+
 #ifndef Q_MOC_RUN
 #include <ndn.cxx/security/identity/identity-manager.h>
-#include <ndn.cxx/security/identity/basic-identity-storage.h>
-#include <ndn.cxx/security/identity/osx-privatekey-storage.h>
 #include <ndn.cxx/security/encryption/basic-encryption-manager.h>
+#include <sync-intro-certificate.h>
+#include <boost/random/random_device.hpp>
+#include <boost/random/uniform_int_distribution.hpp>
 #include "logging.h"
 #endif
 
 using namespace std;
-using namespace ndn;
 
 INIT_LOGGER("ChatDialog");
 
-ChatDialog::ChatDialog(const Name& chatroomPrefix,
-		       const Name& localPrefix,
-                       const Name& defaultIdentity,
+static const int HELLO_INTERVAL = FRESHNESS * 3 / 4;
+
+Q_DECLARE_METATYPE(std::vector<Sync::MissingDataInfo> )
+Q_DECLARE_METATYPE(size_t)
+
+ChatDialog::ChatDialog(ndn::Ptr<ContactManager> contactManager,
+                       const ndn::Name& chatroomPrefix,
+		       const ndn::Name& localPrefix,
+                       const ndn::Name& defaultIdentity,
 		       QWidget *parent) 
-    : QDialog(parent)
-    , m_chatroomPrefix(chatroomPrefix)
-    , m_localPrefix(localPrefix)
-    , m_defaultIdentity(defaultIdentity)
-    , m_policyManager(Ptr<ChatroomPolicyManager>(new ChatroomPolicyManager))
-    , ui(new Ui::ChatDialog)
+: QDialog(parent)
+  , ui(new Ui::ChatDialog)
+  , m_contactManager(contactManager)
+  , m_chatroomPrefix(chatroomPrefix)
+  , m_localPrefix(localPrefix)
+  , m_defaultIdentity(defaultIdentity)
+  , m_invitationPolicyManager(ndn::Ptr<InvitationPolicyManager>(new InvitationPolicyManager(m_chatroomPrefix.get(-1).toUri())))
+  , m_sock(NULL)
+  , m_lastMsgTime(0)
+  // , m_historyInitialized(false)
+  , m_joined(false)
+  , m_inviteListDialog(new InviteListDialog(m_contactManager))
 {
+  qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
+  qRegisterMetaType<size_t>("size_t");
+
   ui->setupUi(this);
 
+  m_localChatPrefix = m_localPrefix;
+  m_localChatPrefix.append("FH").append(m_defaultIdentity);
+  m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1));
+
+  m_session = time(NULL);
+  m_scene = new DigestTreeScene(this);
+
+  initializeSetting();
+  updateLabels();
+
+  ui->treeViewer->setScene(m_scene);
+  ui->treeViewer->hide();
+  m_scene->plot("Empty");
+  QRectF rect = m_scene->itemsBoundingRect();
+  m_scene->setSceneRect(rect);
+
+  m_rosterModel = new QStringListModel(this);
+  ui->listView->setModel(m_rosterModel);
+
+  m_timer = new QTimer(this);
+
   setWrapper();
+
+  connect(ui->inviteButton, SIGNAL(clicked()),
+          this, SLOT(openInviteListDialog()));
+  connect(m_inviteListDialog, SIGNAL(invitionDetermined(QString, bool)),
+          this, SLOT(sendInvitationWrapper(QString, bool)));
+  connect(ui->lineEdit, SIGNAL(returnPressed()), 
+          this, SLOT(returnPressed()));
+  connect(ui->treeButton, SIGNAL(pressed()), 
+          this, SLOT(treeButtonPressed()));
+  connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool, bool)), 
+          this, SLOT(processData(QString, const char *, size_t, bool, bool)));
+  connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), 
+          this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
+  connect(m_timer, SIGNAL(timeout()), 
+          this, SLOT(replot()));
+  connect(m_scene, SIGNAL(replot()), 
+          this, SLOT(replot()));
+  // TODO: TrayIcon
+  // connect(trayIcon, SIGNAL(messageClicked()), 
+  //         this, SLOT(showNormal()));
+  // connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), 
+  //         this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
+  connect(m_scene, SIGNAL(rosterChanged(QStringList)), 
+          this, SLOT(updateRosterList(QStringList)));
+
+  // m_identityManager = ndn::Ptr<ndn::security::IdentityManager>::Create();
+  // // ndn::Ptr<ndn::security::EncryptionManager> encryptionManager = ndn::Ptr<ndn::security::EncryptionManager>(new ndn::security::BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
+
+  // ndn::Name certificateName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
+  // m_syncPolicyManager = ndn::Ptr<SyncPolicyManager>(new SyncPolicyManager(m_defaultIdentity, certificateName, m_chatroomPrefix));
+
+  initializeSync();
 }
 
+// ChatDialog::ChatDialog(const ndn::Name& chatroomPrefix,
+// 		       const ndn::Name& localPrefix,
+//                        const ndn::Name& defaultIdentity,
+//                        const ndn::security::IdentityCertificate& identityCertificate,
+// 		       QWidget *parent) 
+//     : QDialog(parent)
+//     , ui(new Ui::ChatDialog)
+//     , m_chatroomPrefix(chatroomPrefix)
+//     , m_localPrefix(localPrefix)
+//     , m_defaultIdentity(defaultIdentity)
+//     , m_invitationPolicyManager(ndn::Ptr<InvitationPolicyManager>(new InvitationPolicyManager(m_chatroomPrefix.get(-1).toUri())))
+
+//     , m_sock(NULL)
+//     , m_lastMsgTime(0)
+//     // , m_historyInitialized(false)
+//     , m_joined(false)
+// {
+//   qRegisterMetaType<std::vector<Sync::MissingDataInfo> >("std::vector<Sync::MissingDataInfo>");
+//   qRegisterMetaType<size_t>("size_t");
+
+//   ui->setupUi(this);
+
+//   m_localChatPrefix = m_localPrefix;
+//   m_localChatPrefix.append("FH").append(m_defaultIdentity);
+//   m_localChatPrefix.append("chronos").append(m_chatroomPrefix.get(-1));
+
+//   m_session = time(NULL);
+//   m_scene = new DigestTreeScene(this);
+
+//   initializeSetting();
+//   updateLabels();
+
+//   ui->treeViewer->setScene(m_scene);
+//   ui->treeViewer->hide();
+//   m_scene->plot("Empty");
+//   QRectF rect = m_scene->itemsBoundingRect();
+//   m_scene->setSceneRect(rect);
+
+//   m_rosterModel = new QStringListModel(this);
+//   ui->listView->setModel(m_rosterModel);
+
+//   m_timer = new QTimer(this);
+
+//   setWrapper();
+
+//   connect(ui->lineEdit, SIGNAL(returnPressed()), 
+//           this, SLOT(returnPressed()));
+//   connect(ui->treeButton, SIGNAL(pressed()), 
+//           this, SLOT(treeButtonPressed()));
+//   connect(this, SIGNAL(dataReceived(QString, const char *, size_t, bool, bool)), 
+//           this, SLOT(processData(QString, const char *, size_t, bool, bool)));
+//   connect(this, SIGNAL(treeUpdated(const std::vector<Sync::MissingDataInfo>)), 
+//           this, SLOT(processTreeUpdate(const std::vector<Sync::MissingDataInfo>)));
+//   connect(m_timer, SIGNAL(timeout()), 
+//           this, SLOT(replot()));
+//   connect(m_scene, SIGNAL(replot()), 
+//           this, SLOT(replot()));
+//   // TODO: TrayIcon
+//   // connect(trayIcon, SIGNAL(messageClicked()), 
+//   //         this, SLOT(showNormal()));
+//   // connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), 
+//   //         this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
+//   connect(m_scene, SIGNAL(rosterChanged(QStringList)), 
+//           this, SLOT(updateRosterList(QStringList)));
+
+//   // m_identityManager = ndn::Ptr<ndn::security::IdentityManager>::Create();
+//   // // ndn::Ptr<ndn::security::EncryptionManager> encryptionManager = ndn::Ptr<ndn::security::EncryptionManager>(new ndn::security::BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
+
+//   // ndn::Name certificateName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
+//   // m_syncPolicyManager = ndn::Ptr<SyncPolicyManager>(new SyncPolicyManager(m_defaultIdentity, certificateName, m_chatroomPrefix));
+
+//   initializeSync();
+// }
+
 ChatDialog::~ChatDialog()
 {
   delete ui;
+  sendLeave();
   m_handler->shutdown();
 }
 
 void
 ChatDialog::setWrapper()
 {
-  Ptr<security::OSXPrivatekeyStorage> privateStorage = Ptr<security::OSXPrivatekeyStorage>::Create();
-  m_identityManager = Ptr<security::IdentityManager>(new security::IdentityManager(Ptr<security::BasicIdentityStorage>::Create(), privateStorage));
-  Ptr<security::EncryptionManager> encryptionManager = Ptr<security::EncryptionManager>(new security::BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
+  m_identityManager = ndn::Ptr<ndn::security::IdentityManager>::Create();
+  // ndn::Ptr<ndn::security::EncryptionManager> encryptionManager = ndn::Ptr<ndn::security::EncryptionManager>(new ndn::security::BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
 
-  m_keychain = Ptr<security::Keychain>(new security::Keychain(m_identityManager, m_policyManager, encryptionManager));
+  ndn::Name certificateName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
+  m_syncPolicyManager = ndn::Ptr<SyncPolicyManager>(new SyncPolicyManager(m_defaultIdentity, certificateName, m_chatroomPrefix));
 
-  m_handler = Ptr<Wrapper>(new Wrapper(m_keychain));
+  m_keychain = ndn::Ptr<ndn::security::Keychain>(new ndn::security::Keychain(m_identityManager, m_invitationPolicyManager, NULL));
+
+  m_handler = ndn::Ptr<ndn::Wrapper>(new ndn::Wrapper(m_keychain));
 }
 
 void
-ChatDialog::sendInvitation(Ptr<ContactItem> contact)
+ChatDialog::initializeSetting()
 {
-  m_policyManager->addTrustAnchor(contact->getSelfEndorseCertificate());
+  // TODO: nick name may be changed.
+  m_user.setNick(QString::fromStdString(m_defaultIdentity.get(-1).toUri()));
+  m_user.setChatroom(QString::fromStdString(m_chatroomPrefix.get(-1).toUri()));
+  m_user.setOriginPrefix(QString::fromStdString(m_localPrefix.toUri()));
+  m_user.setPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
+  m_scene->setCurrentPrefix(QString::fromStdString(m_localChatPrefix.toUri()));
+}
 
-  Name certificateName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
+void
+ChatDialog::updateLabels()
+{
+  QString settingDisp = QString("Chatroom: %1").arg(m_user.getChatroom());
+  ui->infoLabel->setStyleSheet("QLabel {color: #630; font-size: 16px; font: bold \"Verdana\";}");
+  ui->infoLabel->setText(settingDisp);
+  QString prefixDisp;
+  if (m_user.getPrefix().startsWith("/private/local"))
+  {
+    prefixDisp = QString("<Warning: no connection to hub or hub does not support prefix autoconfig.>\n <Prefix = %1>").arg(m_user.getPrefix());
+    ui->prefixLabel->setStyleSheet("QLabel {color: red; font-size: 12px; font: bold \"Verdana\";}");
+  }
+  else
+  {
+    prefixDisp = QString("<Prefix = %1>").arg(m_user.getPrefix());
+    ui->prefixLabel->setStyleSheet("QLabel {color: Green; font-size: 12px; font: bold \"Verdana\";}");
+  }
+  ui->prefixLabel->setText(prefixDisp);
+}
 
-  Name interestName("/ndn/broadcast/chronos/invitation");
+void
+ChatDialog::sendInvitation(ndn::Ptr<ContactItem> contact, bool isIntroducer)
+{
+  m_invitationPolicyManager->addTrustAnchor(contact->getSelfEndorseCertificate());
+
+  ndn::Name certificateName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
+
+  ndn::Name interestName("/ndn/broadcast/chronos/invitation");
   interestName.append(contact->getNameSpace());
   interestName.append("chatroom");
   interestName.append(m_chatroomPrefix.get(-1));
@@ -75,68 +255,100 @@
   interestName.append(certificateName);
 
   string signedUri = interestName.toUri();
-  Blob signedBlob(signedUri.c_str(), signedUri.size());
+  ndn::Blob signedBlob(signedUri.c_str(), signedUri.size());
 
-  Ptr<const signature::Sha256WithRsa> sha256sig = DynamicCast<const signature::Sha256WithRsa>(m_identityManager->signByCertificate(signedBlob, certificateName));
-  const Blob& sigBits = sha256sig->getSignatureBits();
+  ndn::Ptr<const ndn::signature::Sha256WithRsa> sha256sig = ndn::DynamicCast<const ndn::signature::Sha256WithRsa>(m_identityManager->signByCertificate(signedBlob, certificateName));
+  const ndn::Blob& sigBits = sha256sig->getSignatureBits();
 
   interestName.append(sigBits.buf(), sigBits.size());
 
-  Ptr<Interest> interest = Ptr<Interest>(new Interest(interestName));
-  Ptr<Closure> closure = Ptr<Closure>(new Closure(boost::bind(&ChatDialog::onInviteReplyVerified,
-                                                              this,
-                                                              _1,
-                                                              contact->getNameSpace()),
-                                                  boost::bind(&ChatDialog::onInviteTimeout,
-                                                              this,
-                                                              _1,
-                                                              _2,
-                                                              contact->getNameSpace(),
-                                                              7),
-                                                  boost::bind(&ChatDialog::onUnverified,
-                                                              this,
-                                                              _1)));
+  ndn::Ptr<ndn::Interest> interest = ndn::Ptr<ndn::Interest>(new ndn::Interest(interestName));
+  ndn::Ptr<ndn::Closure> closure = ndn::Ptr<ndn::Closure>(new ndn::Closure(boost::bind(&ChatDialog::onInviteReplyVerified,
+                                                                                       this,
+                                                                                       _1,
+                                                                                       contact->getNameSpace(),
+                                                                                       isIntroducer),
+                                                                           boost::bind(&ChatDialog::onInviteTimeout,
+                                                                                       this,
+                                                                                       _1,
+                                                                                       _2,
+                                                                                       contact->getNameSpace(),
+                                                                                       7),
+                                                                           boost::bind(&ChatDialog::onUnverified,
+                                                                                       this,
+                                                                                       _1)));
 
   m_handler->sendInterest(interest, closure);
 }
 
 void
-ChatDialog::invitationRejected(const Name& identity)
+ChatDialog::addTrustAnchor(const EndorseCertificate& selfEndorseCertificate)
+{ m_invitationPolicyManager->addTrustAnchor(selfEndorseCertificate); }
+
+void
+ChatDialog::addChatDataRule(const ndn::Name& prefix, 
+                            const ndn::security::IdentityCertificate& identityCertificate,
+                            bool isIntroducer)
+{ m_syncPolicyManager->addChatDataRule(prefix, identityCertificate, isIntroducer); }
+
+void
+ChatDialog::publishIntroCert(ndn::Ptr<ndn::security::IdentityCertificate> dskCertificate, bool isIntroducer)
 {
-  _LOG_DEBUG(" " << identity.toUri() << " rejected your invitation!");
+  SyncIntroCertificate syncIntroCertificate(m_chatroomPrefix,
+                                            dskCertificate->getPublicKeyName(),
+                                            m_identityManager->getDefaultKeyNameForIdentity(m_defaultIdentity),
+                                            dskCertificate->getNotBefore(),
+                                            dskCertificate->getNotAfter(),
+                                            dskCertificate->getPublicKeyInfo(),
+                                            (isIntroducer ? SyncIntroCertificate::INTRODUCER : SyncIntroCertificate::PRODUCER));
+  ndn::Name certName = m_identityManager->getDefaultCertificateNameByIdentity(m_defaultIdentity);
+  m_identityManager->signByCertificate(syncIntroCertificate, certName);
+  m_handler->putToNdnd(*syncIntroCertificate.encodeToWire());
 }
 
 void
-ChatDialog::invitationAccepted(const Name& identity)
+ChatDialog::invitationRejected(const ndn::Name& identity)
+{
+  _LOG_DEBUG(" " << identity.toUri() << " rejected your invitation!");
+  //TODO:
+}
+
+void
+ChatDialog::invitationAccepted(const ndn::Name& identity, ndn::Ptr<ndn::Data> data, const string& inviteePrefix, bool isIntroducer)
 {
   _LOG_DEBUG(" " << identity.toUri() << " accepted your invitation!");
+  ndn::Ptr<const ndn::signature::Sha256WithRsa> sha256sig = boost::dynamic_pointer_cast<const ndn::signature::Sha256WithRsa> (data->getSignature());
+  const ndn::Name & keyLocatorName = sha256sig->getKeyLocator().getKeyName();
+  ndn::Ptr<ndn::security::IdentityCertificate> dskCertificate = m_invitationPolicyManager->getValidatedDskCertificate(keyLocatorName);
+  m_syncPolicyManager->addChatDataRule(inviteePrefix, *dskCertificate, isIntroducer);
+  publishIntroCert(dskCertificate, isIntroducer);
 }
 
 void 
-ChatDialog::onInviteReplyVerified(Ptr<Data> data, const Name& identity)
+ChatDialog::onInviteReplyVerified(ndn::Ptr<ndn::Data> data, const ndn::Name& identity, bool isIntroducer)
 {
   string content(data->content().buf(), data->content().size());
   if(content.empty())
     invitationRejected(identity);
   else
-    invitationAccepted(identity);
+    invitationAccepted(identity, data, content, isIntroducer);
 }
 
 void 
-ChatDialog::onInviteTimeout(Ptr<Closure> closure, Ptr<Interest> interest, const Name& identity, int retry)
+ChatDialog::onInviteTimeout(ndn::Ptr<ndn::Closure> closure, ndn::Ptr<ndn::Interest> interest, const ndn::Name& identity, int retry)
 {
   if(retry > 0)
     {
-      Ptr<Closure> newClosure = Ptr<Closure>(new Closure(closure->m_dataCallback,
-                                                         boost::bind(&ChatDialog::onInviteTimeout, 
-                                                                     this, 
-                                                                     _1, 
-                                                                     _2, 
-                                                                     identity,
-                                                                     retry - 1),
-                                                         closure->m_unverifiedCallback,
-                                                         closure->m_stepCount)
-                                             );
+      ndn::Ptr<ndn::Closure> newClosure = ndn::Ptr<ndn::Closure>(new ndn::Closure(closure->m_dataCallback,
+                                                                                  boost::bind(&ChatDialog::onInviteTimeout, 
+                                                                                              this, 
+                                                                                              _1, 
+                                                                                              _2, 
+                                                                                              identity,
+                                                                                              retry - 1),
+                                                                                  closure->m_unverifiedCallback,
+                                                                                  closure->m_stepCount)
+                                                                 );
       m_handler->sendInterest(interest, newClosure);
     }
   else
@@ -144,9 +356,620 @@
 }
  
 void
-ChatDialog::onUnverified(Ptr<Data> data)
+ChatDialog::onUnverified(ndn::Ptr<ndn::Data> data)
 {}
 
+void
+ChatDialog::initializeSync()
+{
+  
+  m_sock = new Sync::SyncSocket(m_chatroomPrefix.toUri(),
+                                m_syncPolicyManager,
+                                bind(&ChatDialog::processTreeUpdateWrapper, this, _1, _2),
+                                bind(&ChatDialog::processRemoveWrapper, this, _1));
+  
+  usleep(100000);
+
+  QTimer::singleShot(600, this, SLOT(sendJoin()));
+  m_timer->start(FRESHNESS * 1000);
+  disableTreeDisplay();
+  QTimer::singleShot(2200, this, SLOT(enableTreeDisplay()));
+  // Sync::CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
+  // handle->setInterestFilter(m_user.getPrefix().toStdString(), bind(&ChatDialog::respondHistoryRequest, this, _1));
+  // _LOG_DEBUG("initializeSync is done!");
+}
+
+void
+ChatDialog::returnPressed()
+{
+  QString text = ui->lineEdit->text();
+  if (text.isEmpty())
+    return;
+
+  ui->lineEdit->clear();
+
+  if (text.startsWith("boruoboluomi"))
+  {
+    summonReaper ();
+    // reapButton->show();
+    fitView();
+    return;
+  }
+
+  if (text.startsWith("minimanihong"))
+  {
+    // reapButton->hide();
+    fitView();
+    return;
+  }
+
+  SyncDemo::ChatMessage msg;
+  formChatMessage(text, msg);
+
+  appendMessage(msg);
+
+  sendMsg(msg);
+
+  fitView();
+}
+
+void 
+ChatDialog::treeButtonPressed()
+{
+  if (ui->treeViewer->isVisible())
+  {
+    ui->treeViewer->hide();
+    ui->treeButton->setText("Show ChronoSync Tree");
+  }
+  else
+  {
+    ui->treeViewer->show();
+    ui->treeButton->setText("Hide ChronoSync Tree");
+  }
+
+  fitView();
+}
+
+void ChatDialog::disableTreeDisplay()
+{
+  ui->treeButton->setEnabled(false);
+  ui->treeViewer->hide();
+  fitView();
+}
+
+void ChatDialog::enableTreeDisplay()
+{
+  ui->treeButton->setEnabled(true);
+  // treeViewer->show();
+  // fitView();
+}
+
+void
+ChatDialog::processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo> v, Sync::SyncSocket *sock)
+{
+  emit treeUpdated(v);
+  _LOG_DEBUG("<<< Tree update signal emitted");
+}
+
+void
+ChatDialog::processRemoveWrapper(std::string prefix)
+{
+  _LOG_DEBUG("Sync REMOVE signal received for prefix: " << prefix);
+}
+
+void
+ChatDialog::processTreeUpdate(const std::vector<Sync::MissingDataInfo> v)
+{
+  _LOG_DEBUG("<<< processing Tree Update");
+
+  if (v.empty())
+  {
+    return;
+  }
+
+  // reflect the changes on digest tree
+  {
+    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+    m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
+  }
+
+  int n = v.size();
+  int totalMissingPackets = 0;
+  for (int i = 0; i < n; i++)
+  {
+    totalMissingPackets += v[i].high.getSeq() - v[i].low.getSeq() + 1;
+  }
+
+  for (int i = 0; i < n; i++)
+  {
+    if (totalMissingPackets < 4)
+    {
+      for (Sync::SeqNo seq = v[i].low; seq <= v[i].high; ++seq)
+      {
+        m_sock->fetchData(v[i].prefix, seq, bind(&ChatDialog::processDataWrapper, this, _1), 2);
+        _LOG_DEBUG("<<< Fetching " << v[i].prefix << "/" <<seq.getSession() <<"/" << seq.getSeq());
+      }
+    }
+    else
+    {
+        m_sock->fetchData(v[i].prefix, v[i].high, bind(&ChatDialog::processDataNoShowWrapper, this, _1), 2);
+    }
+  }
+
+  // adjust the view
+  fitView();
+
+}
+
+void
+ChatDialog::processDataWrapper(ndn::Ptr<ndn::Data> data)
+{
+  string name = data->getName().toUri();
+  const char* buf = data->content().buf();
+  size_t len = data->content().size();
+
+  char *tempBuf = new char[len];
+  memcpy(tempBuf, buf, len);
+  emit dataReceived(name.c_str(), tempBuf, len, true, false);
+  _LOG_DEBUG("<<< " << name << " fetched");
+}
+
+void
+ChatDialog::processDataNoShowWrapper(ndn::Ptr<ndn::Data> data)
+{
+  string name = data->getName().toUri();
+  const char* buf = data->content().buf();
+  size_t len = data->content().size();
+
+  char *tempBuf = new char[len];
+  memcpy(tempBuf, buf, len);
+  emit dataReceived(name.c_str(), tempBuf, len, false, false);
+
+  // if (!m_historyInitialized)
+  // {
+  //   fetchHistory(name);
+  //   m_historyInitialized = true;
+  // }
+}
+
+// void
+// ChatDialog::fetchHistory(std::string name)
+// {
+
+//   /****************************/
+//   /* TODO: fix following part */
+//   /****************************/
+//   string nameWithoutSeq = name.substr(0, name.find_last_of('/'));
+//   string prefix = nameWithoutSeq.substr(0, nameWithoutSeq.find_last_of('/'));
+//   prefix += "/history";
+//   // Ptr<Wrapper>CcnxWrapperPtr handle = boost::make_shared<Sync::CcnxWrapper> ();
+//   // QString randomString = getRandomString();
+//   // for (int i = 0; i < MAX_HISTORY_ENTRY; i++)
+//   // {
+//   //   QString interest = QString("%1/%2/%3").arg(prefix.c_str()).arg(randomString).arg(i);
+//   //   handle->sendInterest(interest.toStdString(), bind(&ChatDialog::processDataHistoryWrapper, this, _1, _2, _3));
+//   // }
+// }
+
+void
+ChatDialog::processData(QString name, const char *buf, size_t len, bool show, bool isHistory)
+{
+  SyncDemo::ChatMessage msg;
+  bool corrupted = false;
+  if (!msg.ParseFromArray(buf, len))
+  {
+    _LOG_DEBUG("Errrrr.. Can not parse msg with name: " << name.toStdString() << ". what is happening?");
+    // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
+    msg.set_from("inconnu");
+    msg.set_type(SyncDemo::ChatMessage::OTHER);
+    corrupted = true;
+  }
+
+  delete [] buf;
+  buf = NULL;
+
+  // display msg received from network
+  // we have to do so; this function is called by ccnd thread
+  // so if we call appendMsg directly
+  // Qt crash as "QObject: Cannot create children for a parent that is in a different thread"
+  // the "cannonical" way to is use signal-slot
+  if (show && !corrupted)
+  {
+    appendMessage(msg, isHistory);
+  }
+
+  if (!isHistory)
+  {
+    // update the tree view
+    std::string stdStrName = name.toStdString();
+    std::string stdStrNameWithoutSeq = stdStrName.substr(0, stdStrName.find_last_of('/'));
+    std::string prefix = stdStrNameWithoutSeq.substr(0, stdStrNameWithoutSeq.find_last_of('/'));
+    _LOG_DEBUG("<<< updating scene for" << prefix << ": " << msg.from());
+    if (msg.type() == SyncDemo::ChatMessage::LEAVE)
+    {
+      processRemove(prefix.c_str());
+    }
+    else
+    {
+      boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+      m_scene->msgReceived(prefix.c_str(), msg.from().c_str());
+    }
+  }
+  fitView();
+}
+
+void
+ChatDialog::processRemove(QString prefix)
+{
+  _LOG_DEBUG("<<< remove node for prefix" << prefix.toStdString());
+
+  bool removed = m_scene->removeNode(prefix);
+  if (removed)
+  {
+    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+    m_scene->plot(m_sock->getRootDigest().c_str());
+  }
+}
+
+void
+ChatDialog::sendJoin()
+{
+  m_joined = true;
+  SyncDemo::ChatMessage msg;
+  formControlMessage(msg, SyncDemo::ChatMessage::JOIN);
+  sendMsg(msg);
+  boost::random::random_device rng;
+  boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
+  m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
+  QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
+}
+
+void
+ChatDialog::sendHello()
+{
+  time_t now = time(NULL);
+  int elapsed = now - m_lastMsgTime;
+  if (elapsed >= m_randomizedInterval / 1000)
+  {
+    SyncDemo::ChatMessage msg;
+    formControlMessage(msg, SyncDemo::ChatMessage::HELLO);
+    sendMsg(msg);
+    boost::random::random_device rng;
+    boost::random::uniform_int_distribution<> uniform(1, FRESHNESS / 5 * 1000);
+    m_randomizedInterval = HELLO_INTERVAL * 1000 + uniform(rng);
+    QTimer::singleShot(m_randomizedInterval, this, SLOT(sendHello()));
+  }
+  else
+  {
+    QTimer::singleShot((m_randomizedInterval - elapsed * 1000), this, SLOT(sendHello()));
+  }
+}
+
+void
+ChatDialog::sendLeave()
+{
+  SyncDemo::ChatMessage msg;
+  formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
+  sendMsg(msg);
+  usleep(500000);
+  m_sock->remove(m_user.getPrefix().toStdString());
+  usleep(5000);
+  m_joined = false;
+  _LOG_DEBUG("Sync REMOVE signal sent");
+}
+
+void
+ChatDialog::replot()
+{
+  boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+  m_scene->plot(m_sock->getRootDigest().c_str());
+  fitView();
+}
+
+void
+ChatDialog::summonReaper()
+{
+  Sync::SyncLogic &logic = m_sock->getLogic ();
+  map<string, bool> branches = logic.getBranchPrefixes();
+  QMap<QString, DisplayUserPtr> roster = m_scene->getRosterFull();
+
+  m_zombieList.clear();
+
+  QMapIterator<QString, DisplayUserPtr> it(roster);
+  map<string, bool>::iterator mapIt;
+  while(it.hasNext())
+  {
+    it.next();
+    DisplayUserPtr p = it.value();
+    if (p != DisplayUserNullPtr)
+    {
+      mapIt = branches.find(p->getPrefix().toStdString());
+      if (mapIt != branches.end())
+      {
+        mapIt->second = true;
+      }
+    }
+  }
+
+  for (mapIt = branches.begin(); mapIt != branches.end(); ++mapIt)
+  {
+    // this is zombie. all active users should have been marked true
+    if (! mapIt->second)
+    {
+      m_zombieList.append(mapIt->first.c_str());
+    }
+  }
+
+  m_zombieIndex = 0;
+
+  // start reaping
+  reap();
+}
+
+void
+ChatDialog::reap()
+{
+  if (m_zombieIndex < m_zombieList.size())
+  {
+    string prefix = m_zombieList.at(m_zombieIndex).toStdString();
+    m_sock->remove(prefix);
+    _LOG_DEBUG("Reaped: prefix = " << prefix);
+    m_zombieIndex++;
+    // reap again in 10 seconds
+    QTimer::singleShot(10000, this, SLOT(reap()));
+  }
+}
+
+void
+ChatDialog::updateRosterList(QStringList staleUserList)
+{
+  boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+  QStringList rosterList = m_scene->getRosterList();
+  m_rosterModel->setStringList(rosterList);
+  QString user;
+  QStringListIterator it(staleUserList);
+  while(it.hasNext())
+  {
+    std::string nick = it.next().toStdString();
+    if (nick.empty())
+      continue;
+
+    SyncDemo::ChatMessage msg;
+    formControlMessage(msg, SyncDemo::ChatMessage::LEAVE);
+    msg.set_from(nick);
+    appendMessage(msg);
+  }
+}
+
+void
+ChatDialog::resizeEvent(QResizeEvent *e)
+{
+  fitView();
+}
+
+void
+ChatDialog::showEvent(QShowEvent *e)
+{
+  fitView();
+}
+
+void
+ChatDialog::fitView()
+{
+  boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+  QRectF rect = m_scene->itemsBoundingRect();
+  m_scene->setSceneRect(rect);
+  ui->treeViewer->fitInView(m_scene->itemsBoundingRect(), Qt::KeepAspectRatio);
+}
+
+void
+ChatDialog::formChatMessage(const QString &text, SyncDemo::ChatMessage &msg) {
+  msg.set_from(m_user.getNick().toStdString());
+  msg.set_to(m_user.getChatroom().toStdString());
+  msg.set_data(text.toUtf8().constData());
+  time_t seconds = time(NULL);
+  msg.set_timestamp(seconds);
+  msg.set_type(SyncDemo::ChatMessage::CHAT);
+}
+
+void
+ChatDialog::formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type)
+{
+  msg.set_from(m_user.getNick().toStdString());
+  msg.set_to(m_user.getChatroom().toStdString());
+  time_t seconds = time(NULL);
+  msg.set_timestamp(seconds);
+  msg.set_type(type);
+}
+
+void
+ChatDialog::appendMessage(const SyncDemo::ChatMessage msg, bool isHistory)
+{
+  boost::recursive_mutex::scoped_lock lock(m_msgMutex);
+
+  if (msg.type() == SyncDemo::ChatMessage::CHAT)
+  {
+
+    if (!msg.has_data())
+    {
+      return;
+    }
+
+    if (msg.from().empty() || msg.data().empty())
+    {
+      return;
+    }
+
+    if (!msg.has_timestamp())
+    {
+      return;
+    }
+
+    // if (m_history.size() == MAX_HISTORY_ENTRY)
+    // {
+    //   m_history.dequeue();
+    // }
+
+    // m_history.enqueue(msg);
+
+    QTextCharFormat nickFormat;
+    nickFormat.setForeground(Qt::darkGreen);
+    nickFormat.setFontWeight(QFont::Bold);
+    nickFormat.setFontUnderline(true);
+    nickFormat.setUnderlineColor(Qt::gray);
+
+    QTextCursor cursor(ui->textEdit->textCursor());
+    cursor.movePosition(QTextCursor::End);
+    QTextTableFormat tableFormat;
+    tableFormat.setBorder(0);
+    QTextTable *table = cursor.insertTable(1, 2, tableFormat);
+    QString from = QString("%1 ").arg(msg.from().c_str());
+    QTextTableCell fromCell = table->cellAt(0, 0);
+    fromCell.setFormat(nickFormat);
+    fromCell.firstCursorPosition().insertText(from);
+
+    time_t timestamp = msg.timestamp();
+    printTimeInCell(table, timestamp);
+
+    QTextCursor nextCursor(ui->textEdit->textCursor());
+    nextCursor.movePosition(QTextCursor::End);
+    table = nextCursor.insertTable(1, 1, tableFormat);
+    table->cellAt(0, 0).firstCursorPosition().insertText(QString::fromUtf8(msg.data().c_str()));
+    if (!isHistory)
+    {
+      showMessage(from, QString::fromUtf8(msg.data().c_str()));
+    }
+  }
+
+  if (msg.type() == SyncDemo::ChatMessage::JOIN || msg.type() == SyncDemo::ChatMessage::LEAVE)
+  {
+    QTextCharFormat nickFormat;
+    nickFormat.setForeground(Qt::gray);
+    nickFormat.setFontWeight(QFont::Bold);
+    nickFormat.setFontUnderline(true);
+    nickFormat.setUnderlineColor(Qt::gray);
+
+    QTextCursor cursor(ui->textEdit->textCursor());
+    cursor.movePosition(QTextCursor::End);
+    QTextTableFormat tableFormat;
+    tableFormat.setBorder(0);
+    QTextTable *table = cursor.insertTable(1, 2, tableFormat);
+    QString action;
+    if (msg.type() == SyncDemo::ChatMessage::JOIN)
+    {
+      action = "enters room";
+    }
+    else
+    {
+      action = "leaves room";
+    }
+
+    QString from = QString("%1 %2  ").arg(msg.from().c_str()).arg(action);
+    QTextTableCell fromCell = table->cellAt(0, 0);
+    fromCell.setFormat(nickFormat);
+    fromCell.firstCursorPosition().insertText(from);
+
+    time_t timestamp = msg.timestamp();
+    printTimeInCell(table, timestamp);
+  }
+
+  QScrollBar *bar = ui->textEdit->verticalScrollBar();
+  bar->setValue(bar->maximum());
+}
+
+QString
+ChatDialog::formatTime(time_t timestamp)
+{
+  struct tm *tm_time = localtime(&timestamp);
+  int hour = tm_time->tm_hour;
+  QString amOrPM;
+  if (hour > 12)
+  {
+    hour -= 12;
+    amOrPM = "PM";
+  }
+  else
+  {
+    amOrPM = "AM";
+    if (hour == 0)
+    {
+      hour = 12;
+    }
+  }
+
+  char textTime[12];
+  sprintf(textTime, "%d:%02d:%02d %s", hour, tm_time->tm_min, tm_time->tm_sec, amOrPM.toStdString().c_str());
+  return QString(textTime);
+}
+
+void
+ChatDialog::printTimeInCell(QTextTable *table, time_t timestamp)
+{
+  QTextCharFormat timeFormat;
+  timeFormat.setForeground(Qt::gray);
+  timeFormat.setFontUnderline(true);
+  timeFormat.setUnderlineColor(Qt::gray);
+  QTextTableCell timeCell = table->cellAt(0, 1);
+  timeCell.setFormat(timeFormat);
+  timeCell.firstCursorPosition().insertText(formatTime(timestamp));
+}
+
+void
+ChatDialog::showMessage(QString from, QString data)
+{
+  if (!isActiveWindow())
+  {
+    //TODO: Notification to be done
+    // trayIcon->showMessage(QString("Chatroom %1 has a new message").arg(m_user.getChatroom()), QString("<%1>: %2").arg(from).arg(data), QSystemTrayIcon::Information, 20000);
+    // trayIcon->setIcon(QIcon(":/images/note.png"));
+  }
+}
+
+void
+ChatDialog::sendMsg(SyncDemo::ChatMessage &msg)
+{
+  // send msg
+  size_t size = msg.ByteSize();
+  char *buf = new char[size];
+  msg.SerializeToArray(buf, size);
+  if (!msg.IsInitialized())
+  {
+    _LOG_DEBUG("Errrrr.. msg was not probally initialized "<<__FILE__ <<":"<<__LINE__<<". what is happening?");
+    abort();
+  }
+  m_sock->publishData(m_user.getPrefix().toStdString(), m_session, buf, size, FRESHNESS);
+
+  delete buf;
+
+  m_lastMsgTime = time(NULL);
+
+  int nextSequence = m_sock->getNextSeq(m_user.getPrefix().toStdString(), m_session);
+  Sync::MissingDataInfo mdi = {m_user.getPrefix().toStdString(), Sync::SeqNo(0), Sync::SeqNo(nextSequence - 1)};
+  std::vector<Sync::MissingDataInfo> v;
+  v.push_back(mdi);
+  {
+    boost::recursive_mutex::scoped_lock lock(m_sceneMutex);
+    m_scene->processUpdate(v, m_sock->getRootDigest().c_str());
+    m_scene->msgReceived(m_user.getPrefix(), m_user.getNick());
+  }
+}
+
+void
+ChatDialog::openInviteListDialog()
+{
+  m_inviteListDialog->setInviteLabel(m_chatroomPrefix.toUri());
+  m_inviteListDialog->show();
+}
+
+void
+ChatDialog::sendInvitationWrapper(QString invitee, bool isIntroducer)
+{
+  ndn::Name inviteeNamespace(invitee.toUtf8().constData());
+  ndn::Ptr<ContactItem> inviteeItem = m_contactManager->getContact(inviteeNamespace);
+  sendInvitation(inviteeItem, isIntroducer);
+}
+
+
 #if WAF
 #include "chatdialog.moc"
 #include "chatdialog.cpp.moc"
diff --git a/src/chatdialog.h b/src/chatdialog.h
index e482169..a4792bc 100644
--- a/src/chatdialog.h
+++ b/src/chatdialog.h
@@ -5,22 +5,36 @@
  *
  * BSD license, See the LICENSE file for more information
  *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ *         Yingdi Yu <yingdi@cs.ucla.edu>
  */
 
 #ifndef CHATDIALOG_H
 #define CHATDIALOG_H
 
 #include <QDialog>
+#include <QTextTable>
+#include <QStringListModel>
+#include <QTimer>
+
+#include "invitelistdialog.h"
 
 #ifndef Q_MOC_RUN
 #include <ndn.cxx/data.h>
 #include <ndn.cxx/security/keychain.h>
 #include <ndn.cxx/wrapper/wrapper.h>
-#include "chatroom-policy-manager.h"
+#include "invitation-policy-manager.h"
 #include "contact-item.h"
+
+#include <ccnx/sync-socket.h>
+#include <sync-seq-no.h>
+#include "chatbuf.pb.h"
+#include "digesttreescene.h"
 #endif
 
+#define MAX_HISTORY_ENTRY   20
+
 namespace Ui {
 class ChatDialog;
 }
@@ -30,10 +44,18 @@
   Q_OBJECT
 
 public:
-  explicit ChatDialog(const ndn::Name& chatroomPrefix,
+  explicit ChatDialog(ndn::Ptr<ContactManager> contactManager,
+                      const ndn::Name& chatroomPrefix,
                       const ndn::Name& localPrefix,
                       const ndn::Name& defaultIdentity,
                       QWidget *parent = 0);
+
+  // explicit ChatDialog(const ndn::Name& chatroomPrefix,
+  //                     const ndn::Name& localPrefix,
+  //                     const ndn::Name& defaultIdentity,
+  //                     const ndn::security::IdentityCertificate& identityCertificate,
+  //                     QWidget *parent = 0);
+
   ~ChatDialog();
 
   const ndn::Name&
@@ -45,14 +67,50 @@
   { return m_localPrefix; }
 
   void
-  sendInvitation(ndn::Ptr<ContactItem> contact);
+  sendInvitation(ndn::Ptr<ContactItem> contact, bool isIntroducer);
+
+  void
+  addTrustAnchor(const EndorseCertificate& selfEndorseCertificate);
+
+  void
+  addChatDataRule(const ndn::Name& prefix, 
+                  const ndn::security::IdentityCertificate& identityCertificate,
+                  bool isIntroducer);
+
+  void 
+  appendMessage(const SyncDemo::ChatMessage msg, bool isHistory = false);
+
+  void 
+  processTreeUpdateWrapper(const std::vector<Sync::MissingDataInfo>, Sync::SyncSocket *);
+
+  void 
+  processDataWrapper(ndn::Ptr<ndn::Data> data);
+
+  void 
+  processDataNoShowWrapper(ndn::Ptr<ndn::Data> data);
+
+  void 
+  processRemoveWrapper(std::string);
 
 private:
+
+  void
+  initializeSetting();
+
+  void 
+  updateLabels();
+
   void
   setWrapper();
+
+  void
+  initializeSync();
+
+  void
+  publishIntroCert(ndn::Ptr<ndn::security::IdentityCertificate> dskCertificate, bool isIntroducer);
   
   void 
-  onInviteReplyVerified(ndn::Ptr<ndn::Data> data, const ndn::Name& identity);
+  onInviteReplyVerified(ndn::Ptr<ndn::Data> data, const ndn::Name& identity, bool isIntroducer);
 
   void 
   onInviteTimeout(ndn::Ptr<ndn::Closure> closure, 
@@ -64,20 +122,139 @@
   invitationRejected(const ndn::Name& identity);
   
   void 
-  invitationAccepted(const ndn::Name& identity);
+  invitationAccepted(const ndn::Name& identity,
+                     ndn::Ptr<ndn::Data> data, 
+                     const std::string& inviteePrefix,
+                     bool isIntroducer);
 
   void
   onUnverified(ndn::Ptr<ndn::Data> data);
+
+
+
+  // void 
+  // fetchHistory(std::string name);
+
+  void 
+  formChatMessage(const QString &text, SyncDemo::ChatMessage &msg);
+
+  void 
+  formControlMessage(SyncDemo::ChatMessage &msg, SyncDemo::ChatMessage::ChatMessageType type);
+
+  void 
+  sendMsg(SyncDemo::ChatMessage &msg);
+
+  void 
+  resizeEvent(QResizeEvent *);
+  
+  void 
+  showEvent(QShowEvent *);
+
+  void 
+  fitView();
+
+  QString 
+  formatTime(time_t);
+
+  void 
+  printTimeInCell(QTextTable *, time_t);
+
+  void 
+  disableTreeDisplay();
+
+signals:
+  void 
+  dataReceived(QString name, const char *buf, size_t len, bool show, bool isHistory);
+  
+  void 
+  treeUpdated(const std::vector<Sync::MissingDataInfo>);
+  
+  void 
+  removeReceived(QString prefix);
+
+public slots:
+  void 
+  processTreeUpdate(const std::vector<Sync::MissingDataInfo>);
+
+  void 
+  processData(QString name, const char *buf, size_t len, bool show, bool isHistory);
+
+  void 
+  processRemove(QString prefix);
+
+private slots:
+  void
+  returnPressed();
+
+  void 
+  treeButtonPressed();
+
+  void 
+  sendJoin();
+
+  void
+  sendHello();
+
+  void
+  sendLeave();
+
+  void 
+  replot();
+
+  void 
+  updateRosterList(QStringList);
+
+  void 
+  enableTreeDisplay();
+
+  void 
+  summonReaper();
+
+  void
+  reap();
+
+  void 
+  showMessage(QString, QString);
+  
+  void
+  openInviteListDialog();
+  
+  void
+  sendInvitationWrapper(QString, bool);
     
 private:
   Ui::ChatDialog *ui;
+  ndn::Ptr<ContactManager> m_contactManager;
   ndn::Name m_chatroomPrefix;
   ndn::Name m_localPrefix;
+  ndn::Name m_localChatPrefix;
   ndn::Name m_defaultIdentity;
-  ndn::Ptr<ChatroomPolicyManager> m_policyManager;
+  ndn::Ptr<InvitationPolicyManager> m_invitationPolicyManager;
+  ndn::Ptr<SyncPolicyManager> m_syncPolicyManager; 
   ndn::Ptr<ndn::security::IdentityManager> m_identityManager;
   ndn::Ptr<ndn::security::Keychain> m_keychain;
   ndn::Ptr<ndn::Wrapper> m_handler;
+
+  User m_user; 
+  Sync::SyncSocket *m_sock;
+  uint32_t m_session;
+  DigestTreeScene *m_scene;
+  boost::recursive_mutex m_msgMutex;
+  boost::recursive_mutex m_sceneMutex;
+  time_t m_lastMsgTime;
+  int m_randomizedInterval;
+  QTimer *m_timer;
+  QStringListModel *m_rosterModel;
+  
+
+  // QQueue<SyncDemo::ChatMessage> m_history;
+  // bool m_historyInitialized;
+  bool m_joined;
+
+  QList<QString> m_zombieList;
+  int m_zombieIndex;
+
+  InviteListDialog* m_inviteListDialog;
 };
 
 #endif // ChatDIALOG_H
diff --git a/src/chatdialog.ui b/src/chatdialog.ui
index 2380f3d..256aadf 100644
--- a/src/chatdialog.ui
+++ b/src/chatdialog.ui
@@ -63,6 +63,16 @@
         <enum>QLayout::SetFixedSize</enum>
        </property>
        <item>
+        <widget class="QPushButton" name="inviteButton">
+         <property name="text">
+          <string>Invite</string>
+         </property>
+         <property name="autoDefault">
+          <bool>false</bool>
+         </property>
+        </widget>
+       </item>
+       <item>
         <widget class="QPushButton" name="treeButton">
          <property name="enabled">
           <bool>false</bool>
diff --git a/src/chatroom-policy-manager.cpp b/src/chatroom-policy-manager.cpp
deleted file mode 100644
index 394f8ee..0000000
--- a/src/chatroom-policy-manager.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#include "chatroom-policy-manager.h"
-
-#include <ndn.cxx/security/cache/ttl-certificate-cache.h>
-
-#include "logging.h"
-
-using namespace std;
-using namespace ndn;
-using namespace ndn::security;
-
-INIT_LOGGER("ChatroomPolicyManager");
-
-ChatroomPolicyManager::ChatroomPolicyManager(int stepLimit,
-					     Ptr<CertificateCache> certificateCache)
-  : m_stepLimit(stepLimit)
-  , m_certificateCache(certificateCache)
-{
-  if(m_certificateCache == NULL)
-    m_certificateCache = Ptr<TTLCertificateCache>(new TTLCertificateCache());
-
-  m_invitationPolicyRule = Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^<ndn><broadcast><chronos><invitation>([^<chatroom>]*)<chatroom>", 
-									  "^([^<KEY>]*)<KEY><DSK-.*><ID-CERT><>$", 
-									  "==", "\\1", "\\1", true));
-
-  m_dskRule = Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<KEY>]*)<KEY><DSK-.*><ID-CERT><>$", 
-							     "^([^<KEY>]*)<KEY>(<>*)<KSK-.*><ID-CERT><>$", 
-							     "==", "\\1", "\\1\\2", true));
-
-  m_keyNameRegex = Ptr<Regex>(new Regex("^([^<KEY>]*)<KEY>(<>*<KSK-.*>)<ID-CERT><>$", "\\1\\2"));
-} 
-
-ChatroomPolicyManager::~ChatroomPolicyManager()
-{}
-
-bool 
-ChatroomPolicyManager::skipVerifyAndTrust (const Data& data)
-{ return false; }
-
-bool
-ChatroomPolicyManager::requireVerify (const Data& data)
-{ return true; }
-
-Ptr<ValidationRequest>
-ChatroomPolicyManager::checkVerificationPolicy(Ptr<Data> data, 
-					       const int& stepCount, 
-					       const DataCallback& verifiedCallback,
-					       const UnverifiedCallback& unverifiedCallback)
-{
-  if(m_stepLimit == stepCount)
-    {
-      _LOG_DEBUG("reach the maximum steps of verification");
-      unverifiedCallback(data);
-      return NULL;
-    }
-
-  Ptr<const signature::Sha256WithRsa> sha256sig = boost::dynamic_pointer_cast<const signature::Sha256WithRsa> (data->getSignature());    
-
-  if(KeyLocator::KEYNAME != sha256sig->getKeyLocator().getType())
-    {
-      unverifiedCallback(data);
-      return NULL;
-    }
-
-  const Name & keyLocatorName = sha256sig->getKeyLocator().getKeyName();
-
-  if(m_invitationPolicyRule->satisfy(*data))
-    {
-      Ptr<const IdentityCertificate> trustedCert = m_certificateCache->getCertificate(keyLocatorName);
-      
-      if(NULL != trustedCert){
-	if(verifySignature(*data, trustedCert->getPublicKeyInfo()))
-	  verifiedCallback(data);
-	else
-	  unverifiedCallback(data);
-
-	return NULL;
-      }
-      else{
-	_LOG_DEBUG("KeyLocator has not been cached and validated!");
-
-	DataCallback recursiveVerifiedCallback = boost::bind(&ChatroomPolicyManager::onCertificateVerified, 
-							     this, 
-							     _1, 
-							     data, 
-							     verifiedCallback, 
-							     unverifiedCallback);
-
-	UnverifiedCallback recursiveUnverifiedCallback = boost::bind(&ChatroomPolicyManager::onCertificateUnverified, 
-								     this, 
-								     _1, 
-								     data, 
-								     unverifiedCallback);
-
-
-	Ptr<Interest> interest = Ptr<Interest>(new Interest(keyLocatorName));
-	
-	Ptr<ValidationRequest> nextStep = Ptr<ValidationRequest>(new ValidationRequest(interest, 
-										       recursiveVerifiedCallback,
-										       recursiveUnverifiedCallback,
-										       0,
-										       stepCount + 1)
-								 );
-	return nextStep;
-      }
-    }
-
-  if(m_dskRule->satisfy(*data))
-    {
-      m_keyNameRegex->match(keyLocatorName);
-      Name keyName = m_keyNameRegex->expand();
-
-      if(m_trustAnchors.end() != m_trustAnchors.find(keyName))
-        if(verifySignature(*data, m_trustAnchors[keyName]))
-          verifiedCallback(data);
-        else
-          unverifiedCallback(data);
-      else
-        unverifiedCallback(data);
-
-      return NULL;	
-    }
-
-  unverifiedCallback(data);
-  return NULL;
-}
-
-bool 
-ChatroomPolicyManager::checkSigningPolicy(const Name& dataName, 
-					  const Name& certificateName)
-{
-  //TODO:
-}
-    
-Name 
-ChatroomPolicyManager::inferSigningIdentity(const Name& dataName)
-{
-  //TODO:
-}
-
-void
-ChatroomPolicyManager::addTrustAnchor(const EndorseCertificate& selfEndorseCertificate)
-{ m_trustAnchors.insert(pair <Name, Publickey > (selfEndorseCertificate.getPublicKeyName(), selfEndorseCertificate.getPublicKeyInfo())); }
-
-void 
-ChatroomPolicyManager::onCertificateVerified(Ptr<Data> certData, 
-					     Ptr<Data> originalData,
-					     const DataCallback& verifiedCallback, 
-					     const UnverifiedCallback& unverifiedCallback)
-{
-  Ptr<IdentityCertificate> certificate = Ptr<IdentityCertificate>(new IdentityCertificate(*certData));
-  m_certificateCache->insertCertificate(certificate);
-
-  if(verifySignature(*originalData, certificate->getPublicKeyInfo()))
-    verifiedCallback(originalData);
-  else
-    unverifiedCallback(originalData);
-}
-
-void
-ChatroomPolicyManager::onCertificateUnverified(Ptr<Data> certData, 
-					       Ptr<Data> originalData,
-					       const UnverifiedCallback& unverifiedCallback)
-{ unverifiedCallback(originalData); }
-
diff --git a/src/chatroom-policy-manager.h b/src/chatroom-policy-manager.h
deleted file mode 100644
index 04227b8..0000000
--- a/src/chatroom-policy-manager.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
-/*
- * Copyright (c) 2013, Regents of the University of California
- *                     Yingdi Yu
- *
- * BSD license, See the LICENSE file for more information
- *
- * Author: Yingdi Yu <yingdi@cs.ucla.edu>
- */
-
-#ifndef CHATROOM_POLICY_MANAGER_H
-#define CHATROOM_POLICY_MANAGER_H
-
-#include <ndn.cxx/security/policy/policy-manager.h>
-#include <ndn.cxx/security/policy/identity-policy-rule.h>
-#include <ndn.cxx/security/cache/certificate-cache.h>
-#include <ndn.cxx/regex/regex.h>
-#include <map>
-
-#include "endorse-certificate.h"
-
-class ChatroomPolicyManager : public ndn::security::PolicyManager
-{
-public:
-  ChatroomPolicyManager(int stepLimit = 10,
-                        ndn::Ptr<ndn::security::CertificateCache> certificateCache = NULL);
-  
-  virtual
-  ~ChatroomPolicyManager();
-
-  bool 
-  skipVerifyAndTrust (const ndn::Data& data);
-
-  bool
-  requireVerify (const ndn::Data& data);
-
-  ndn::Ptr<ndn::security::ValidationRequest>
-  checkVerificationPolicy(ndn::Ptr<ndn::Data> data, 
-                          const int& stepCount, 
-                          const ndn::DataCallback& verifiedCallback,
-                          const ndn::UnverifiedCallback& unverifiedCallback);
-
-  bool 
-  checkSigningPolicy(const ndn::Name& dataName, 
-                     const ndn::Name& certificateName);
-    
-  ndn::Name 
-  inferSigningIdentity(const ndn::Name& dataName);
-
-  void
-  addTrustAnchor(const EndorseCertificate& selfEndorseCertificate);
-
-private:
-  void 
-  onCertificateVerified(ndn::Ptr<ndn::Data> certData, 
-                        ndn::Ptr<ndn::Data> originalData,
-                        const ndn::DataCallback& verifiedCallback, 
-                        const ndn::UnverifiedCallback& unverifiedCallback);
-
-  void
-  onCertificateUnverified(ndn::Ptr<ndn::Data> certData, 
-                          ndn::Ptr<ndn::Data> originalData,
-                          const ndn::UnverifiedCallback& unverifiedCallback);
-
-private:
-  int m_stepLimit;
-  ndn::Ptr<ndn::security::CertificateCache> m_certificateCache;
-
-  ndn::Ptr<ndn::security::IdentityPolicyRule> m_invitationPolicyRule;
-  ndn::Ptr<ndn::security::IdentityPolicyRule> m_dskRule;
-
-  ndn::Ptr<ndn::Regex> m_keyNameRegex;
-
-  std::map<ndn::Name, ndn::security::Publickey> m_trustAnchors;
-
-};
-
-#endif //CHATROOM_POLICY_MANAGER_H
diff --git a/src/chronos-invitation.cpp b/src/chronos-invitation.cpp
new file mode 100644
index 0000000..7ec0243
--- /dev/null
+++ b/src/chronos-invitation.cpp
@@ -0,0 +1,98 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "chronos-invitation.h"
+#include "exception.h"
+#include "logging.h"
+
+using namespace std;
+using namespace ndn;
+
+INIT_LOGGER("ChronosInvitation");
+
+ChronosInvitation::ChronosInvitation(const ndn::Name& interestName)
+  : m_interestName(interestName)
+{
+  if(interestName.get(0).toUri() != string("ndn")
+     || interestName.get(1).toUri() != string("broadcast")
+     || interestName.get(2).toUri() != string("chronos")
+     || interestName.get(3).toUri() != string("invitation"))
+    throw LnException("Wrong ChronosInvitation Name");
+    
+  int i = 4;
+  int size = interestName.size();
+
+  string chatroomStr("chatroom");
+  int inviteeBegin = 4;
+  for(; i < size; i++)
+    if(interestName.get(i).toUri() == chatroomStr)
+      break;
+
+  if(i >= size)
+    throw LnException("Wrong ChronosInvitation Name, No chatroom tag");
+  m_inviteeNameSpace = interestName.getSubName(inviteeBegin, i - inviteeBegin);
+
+  _LOG_DEBUG(m_inviteeNameSpace.toUri());
+
+  string inviterPrefixStr("inviter-prefix");
+  int chatroomBegin = (++i);
+  for(; i < size;  i++)
+    if(interestName.get(i).toUri() == inviterPrefixStr)
+      break;
+
+  if(i > size)
+    throw LnException("Wrong ChronosInvitation Name, No inviter-prefix tag");
+  m_chatroom = interestName.getSubName(chatroomBegin, i - chatroomBegin);
+
+  _LOG_DEBUG(m_chatroom.toUri());
+
+  string inviterStr("inviter");
+  int inviterPrefixBegin = (++i);
+  for(; i < size; i++)
+    if(interestName.get(i).toUri() == inviterStr)
+      break;
+  
+  if(i > size)
+    throw LnException("Wrong ChronosInvitation Name, No inviter tag");
+  m_inviterPrefix = interestName.getSubName(inviterPrefixBegin, i - inviterPrefixBegin);
+
+  _LOG_DEBUG(m_inviterPrefix.toUri());
+
+  int inviterCertBegin = (++i);
+  m_inviterCertificateName = interestName.getSubName(inviterCertBegin, size - 1 - inviterCertBegin);
+
+  _LOG_DEBUG(m_inviterCertificateName.toUri());
+  
+  string signature = interestName.get(-1).toBlob();
+  m_signatureBits.insert(m_signatureBits.end(), signature.begin(), signature.end());
+
+  string keyStr("KEY");
+  int keyId = 0;
+  for(; keyId < m_inviterCertificateName.size(); keyId++)
+    if(m_inviterCertificateName.get(keyId).toUri() == keyStr)
+      break;
+  if(keyId >= m_inviterCertificateName.size())
+    throw LnException("Wrong ChronosInvitation Name, no KEY tag in inviter Certificate Name");
+  m_inviterNameSpace = m_inviterCertificateName.getSubName(0, keyId);
+
+  string signedName = interestName.getSubName(0, size - 1).toUri();
+  m_signedBlob.insert(m_signedBlob.end(), signedName.begin(), signedName.end());
+}
+
+ChronosInvitation::ChronosInvitation(const ChronosInvitation& invitation)
+  : m_interestName(invitation.m_interestName)
+  , m_inviteeNameSpace(invitation.m_inviteeNameSpace)
+  , m_chatroom(invitation.m_chatroom)
+  , m_inviterPrefix(invitation.m_inviterPrefix)
+  , m_inviterCertificateName(invitation.m_inviterCertificateName)
+  , m_signatureBits(invitation.m_signatureBits)
+  , m_inviterNameSpace(invitation.m_inviterNameSpace)
+  , m_signedBlob(invitation.m_signedBlob)
+{}
diff --git a/src/chronos-invitation.h b/src/chronos-invitation.h
new file mode 100644
index 0000000..7f660db
--- /dev/null
+++ b/src/chronos-invitation.h
@@ -0,0 +1,74 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef CHRONOS_INVITATION_H
+#define CHRONOS_INVITATION_H
+
+
+#include <ndn.cxx/fields/name.h>
+
+class ChronosInvitation
+{
+public:
+  ChronosInvitation() {}
+
+  ChronosInvitation(const ndn::Name& interestName);
+
+  ChronosInvitation(const ChronosInvitation& invitation);
+
+  virtual
+  ~ChronosInvitation() {};
+
+  inline const ndn::Name&
+  getInviteeNameSpace() const
+  { return m_inviteeNameSpace; }
+
+  inline const ndn::Name&
+  getChatroom() const
+  { return m_chatroom; }
+
+  inline const ndn::Name&
+  getInviterPrefix() const
+  { return m_inviterPrefix; }
+
+  inline const ndn::Name&
+  getInviterCertificateName() const
+  { return m_inviterCertificateName; }
+
+  inline const ndn::Blob&
+  getSignatureBits() const
+  { return m_signatureBits; }
+
+  inline const ndn::Name&
+  getInviterNameSpace() const
+  { return m_inviterNameSpace; }
+
+  inline const ndn::Blob&
+  getSignedBlob() const
+  { return m_signedBlob; }
+  
+  inline const ndn::Name&
+  getInterestName() const
+  { return m_interestName; }
+
+private:
+  ndn::Name m_interestName;
+
+  ndn::Name m_inviteeNameSpace;
+  ndn::Name m_chatroom;
+  ndn::Name m_inviterPrefix;
+  ndn::Name m_inviterCertificateName;
+  ndn::Blob m_signatureBits;
+  ndn::Name m_inviterNameSpace;
+
+  ndn::Blob m_signedBlob;
+};
+
+#endif
diff --git a/src/contact-manager.cpp b/src/contact-manager.cpp
index bc324b7..2f7536b 100644
--- a/src/contact-manager.cpp
+++ b/src/contact-manager.cpp
@@ -58,13 +58,13 @@
                                                                                           "^([^<KEY>]*)<KEY>(<>*)<><ID-CERT>",
                                                                                           "==", "\\1", "\\1\\2", true)));
   policyManager->addVerificationPolicyRule(Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<PROFILE-CERT>]*)<PROFILE-CERT>",
-											  "^([^<KEY>]*)<KEY>(<>*<KSK-.*>)<ID-CERT>", 
+											  "^([^<KEY>]*)<KEY>(<>*<ksk-.*>)<ID-CERT>", 
 											  "==", "\\1", "\\1\\2", true)));
-  policyManager->addVerificationPolicyRule(Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<KEY>]*)<KEY>(<>*)<KSK-.*><ID-CERT>",
-											  "^([^<KEY>]*)<KEY><DSK-.*><ID-CERT>",
+  policyManager->addVerificationPolicyRule(Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>",
+											  "^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>",
 											  ">", "\\1\\2", "\\1", true)));
-  policyManager->addVerificationPolicyRule(Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<KEY>]*)<KEY><DSK-.*><ID-CERT>",
-											  "^([^<KEY>]*)<KEY>(<>*)<KSK-.*><ID-CERT>",
+  policyManager->addVerificationPolicyRule(Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>",
+											  "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>",
 											  "==", "\\1", "\\1\\2", true)));
 
   policyManager->addSigningPolicyRule(Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<DNS>]*)<DNS><PROFILE>",
@@ -97,6 +97,7 @@
   interestName.append("DNS").append("PROFILE");
   
   Ptr<Interest> interestPtr = Ptr<Interest>(new Interest(interestName));
+  interestPtr->setChildSelector(Interest::CHILD_RIGHT);
   Ptr<Closure> closure = Ptr<Closure> (new Closure(boost::bind(&ContactManager::onDnsSelfEndorseCertificateVerified, 
                                                                this,
                                                                _1,
@@ -200,7 +201,12 @@
   Ptr<security::IdentityCertificate> dskCert = identityManager->getCertificate(certificateName);
   Ptr<const signature::Sha256WithRsa> dskCertSig = DynamicCast<const signature::Sha256WithRsa>(dskCert->getSignature());
   // HACK! KSK certificate should be retrieved from network.
-  Ptr<security::IdentityCertificate> kskCert = identityManager->getCertificate(dskCertSig->getKeyLocator().getKeyName());
+  _LOG_DEBUG("keyLocator: " << dskCertSig->getKeyLocator().getKeyName());
+  Name keyName = security::IdentityCertificate::certificateNameToPublicKeyName(dskCertSig->getKeyLocator().getKeyName());
+  _LOG_DEBUG("keyName: " << keyName.toUri());
+  Name kskCertName = identityManager->getPublicStorage()->getDefaultCertificateNameForKey(keyName);
+  _LOG_DEBUG("ksk cert name: " << kskCertName);
+  Ptr<security::IdentityCertificate> kskCert = identityManager->getCertificate(kskCertName);
 
   vector<string> endorseList;
   Profile::const_iterator it = profile.begin();
@@ -277,12 +283,9 @@
   Name keyName = selfEndorseCertificate->getPublicKeyName();
   Name identity = keyName.getSubName(0, keyName.size()-1);
 
-  TimeInterval ti = time::NowUnixTimestamp();
-  ostringstream oss;
-  oss << ti.total_seconds();
 
   Name dnsName = identity;
-  dnsName.append("DNS").append("PROFILE").append(oss.str());
+  dnsName.append("DNS").append("PROFILE").appendVersion();
   
   data->setName(dnsName);
   Ptr<Blob> blob = selfEndorseCertificate->encodeToWire();
diff --git a/src/contactpanel.cpp b/src/contactpanel.cpp
index 5c4cfc3..0ce0694 100644
--- a/src/contactpanel.cpp
+++ b/src/contactpanel.cpp
@@ -28,7 +28,7 @@
 #include <boost/filesystem.hpp>
 #include <boost/random/random_device.hpp>
 #include <boost/random/uniform_int_distribution.hpp>
-#include "invitation-policy-manager.h"
+#include "panel-policy-manager.h"
 #include "logging.h"
 #include "exception.h"
 #endif
@@ -41,15 +41,12 @@
 INIT_LOGGER("ContactPanel");
 
 Q_DECLARE_METATYPE(ndn::security::IdentityCertificate)
+Q_DECLARE_METATYPE(ChronosInvitation)
 
 ContactPanel::ContactPanel(Ptr<ContactManager> contactManager, QWidget *parent) 
     : QDialog(parent)
     , ui(new Ui::ContactPanel)
-    , m_contactManager(contactManager)
     , m_contactListModel(new QStringListModel)
-    , m_profileEditor(new ProfileEditor(m_contactManager))
-    , m_addContactPanel(new AddContactPanel(contactManager))
-    , m_setAliasDialog(new SetAliasDialog(contactManager))
     , m_startChatDialog(new StartChatDialog)
     , m_invitationDialog(new InvitationDialog)
     , m_settingDialog(new SettingDialog)
@@ -57,12 +54,18 @@
     , m_menuAlias(new QAction("&Set Alias", this))
 {
   qRegisterMetaType<ndn::security::IdentityCertificate>("IdentityCertificate");
+  qRegisterMetaType<ChronosInvitation>("ChronosInvitation");
   
+  openDB();    
+
+  m_contactManager = contactManager;
+  m_profileEditor = new ProfileEditor(m_contactManager);
+  m_addContactPanel = new AddContactPanel(contactManager);
+  m_setAliasDialog = new SetAliasDialog(contactManager);
+ 
   ui->setupUi(this);
   refreshContactList();
 
-  openDB();    
-
   setKeychain();
   m_handler = Ptr<Wrapper>(new Wrapper(m_keychain));
    
@@ -101,10 +104,10 @@
   connect(m_startChatDialog, SIGNAL(chatroomConfirmed(const QString&, const QString&, bool)),
           this, SLOT(startChatroom(const QString&, const QString&, bool)));
 
-  connect(m_invitationDialog, SIGNAL(invitationAccepted(const ndn::Name&, const ndn::security::IdentityCertificate&, QString, QString)),
-          this, SLOT(acceptInvitation(const ndn::Name&, const ndn::security::IdentityCertificate&, QString, QString)));
-  connect(m_invitationDialog, SIGNAL(invitationRejected(const ndn::Name&)),
-          this, SLOT(rejectInvitation(const ndn::Name&)));
+  connect(m_invitationDialog, SIGNAL(invitationAccepted(const ChronosInvitation&, const ndn::security::IdentityCertificate&)),
+          this, SLOT(acceptInvitation(const ChronosInvitation&, const ndn::security::IdentityCertificate&)));
+  connect(m_invitationDialog, SIGNAL(invitationRejected(const ChronosInvitation&)),
+          this, SLOT(rejectInvitation(const ChronosInvitation&)));
 
   connect(m_settingDialog, SIGNAL(identitySet(const QString&)),
           this, SLOT(updateDefaultIdentity(const QString&)));
@@ -138,22 +141,22 @@
   path.append(QDir::separator()).append(".chronos").append(QDir::separator()).append("chronos.db");
   db.setDatabaseName(path);
   bool ok = db.open();
+  _LOG_DEBUG("db opened: " << std::boolalpha << ok );
 }
 
 void 
 ContactPanel::setKeychain()
 {
-  Ptr<security::OSXPrivatekeyStorage> privateStorage = Ptr<security::OSXPrivatekeyStorage>::Create();
-  Ptr<security::IdentityManager> identityManager = Ptr<security::IdentityManager>(new security::IdentityManager(Ptr<security::BasicIdentityStorage>::Create(), privateStorage));
+  Ptr<security::IdentityManager> identityManager = Ptr<security::IdentityManager>::Create();
   Ptr<security::CertificateCache> certificateCache = Ptr<security::CertificateCache>(new security::TTLCertificateCache());
-  Ptr<InvitationPolicyManager> policyManager = Ptr<InvitationPolicyManager>(new InvitationPolicyManager(10, certificateCache));
-  Ptr<security::EncryptionManager> encryptionManager = Ptr<security::EncryptionManager>(new security::BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
+  Ptr<PanelPolicyManager> policyManager = Ptr<PanelPolicyManager>(new PanelPolicyManager(10, certificateCache));
+  // Ptr<security::EncryptionManager> encryptionManager = Ptr<security::EncryptionManager>(new security::BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
 
   vector<Ptr<ContactItem> >::const_iterator it = m_contactList.begin();
   for(; it != m_contactList.end(); it++)
       policyManager->addTrustAnchor((*it)->getSelfEndorseCertificate());
 
-  m_keychain = Ptr<security::Keychain>(new security::Keychain(identityManager, policyManager, encryptionManager));
+  m_keychain = Ptr<security::Keychain>(new security::Keychain(identityManager, policyManager, NULL));
 }
 
 void
@@ -188,7 +191,11 @@
 
 void
 ContactPanel::onLocalPrefixTimeout(Ptr<Closure> closure, Ptr<Interest> interest)
-{ throw LnException("No local prefix is found!"); }
+{ 
+  string randomSuffix = getRandomString();
+  m_localPrefix = Name("/private/local"); 
+  m_localPrefix.append(randomSuffix);
+}
 
 void
 ContactPanel::onUnverified(Ptr<Data> data)
@@ -204,41 +211,35 @@
                                        int inviterIndex)
 {
   Ptr<security::IdentityCertificate> certificate = Ptr<security::IdentityCertificate>(new security::IdentityCertificate(*data));
-
-  const int end = interestName.size();
-
-  string signature = interestName.get(end-1).toBlob();
-  Blob signatureBlob(signature.c_str(), signature.size());
-  string signedName = interestName.getSubName(0, end - 1).toUri();
-  Blob signedBlob(signedName.c_str(), signedName.size());
-
-  if(security::PolicyManager::verifySignature(signedBlob, signatureBlob, certificate->getPublicKeyInfo()))
+  Ptr<ChronosInvitation> invitation = Ptr<ChronosInvitation>(new ChronosInvitation(interestName));
+  
+  if(security::PolicyManager::verifySignature(invitation->getSignedBlob(), invitation->getSignatureBits(), certificate->getPublicKeyInfo()))
     {
       Name keyName = certificate->getPublicKeyName();
       Name inviterNameSpace = keyName.getSubName(0, keyName.size() - 1);
-      popChatInvitation(interestName, inviterIndex, inviterNameSpace, certificate);
+      popChatInvitation(invitation, inviterIndex, inviterNameSpace, certificate);
     }
 }
 
 void
-ContactPanel::popChatInvitation(const Name& interestName,
+ContactPanel::popChatInvitation(Ptr<ChronosInvitation> invitation,
                                 int inviterIndex,
                                 const Name& inviterNameSpace,
                                 Ptr<security::IdentityCertificate> certificate)
 {
-  string chatroomTag("chatroom");
-  int i = 0;
-  for(; i < inviterIndex; i++)
-    if(interestName.get(i).toUri() == chatroomTag)
-      break;
-  if(i+1 >= inviterIndex)
+  string chatroom = invitation->getChatroom().get(0).toUri();
+  string inviter = inviterNameSpace.toUri();
+
+  string alias;
+  vector<Ptr<ContactItem> >::iterator it = m_contactList.begin();
+  for(; it != m_contactList.end(); it++)
+    if((*it)->getNameSpace() == inviterNameSpace)
+      alias = (*it)->getAlias();
+
+  if(it != m_contactList.end())
     return;
 
-  string chatroom = interestName.get(i+1).toUri();
-  string inviter = inviterNameSpace.toUri();
-  m_invitationDialog->setMsg(inviter, chatroom);
-  m_invitationDialog->setIdentityCertificate(certificate);
-  m_invitationDialog->setInterestName(interestName);
+  m_invitationDialog->setInvitation(alias, invitation, certificate);
   emit newInvitationReady();
 }
 
@@ -427,17 +428,18 @@
 void
 ContactPanel::openStartChatDialog()
 {
-  TimeInterval ti = time::NowUnixTimestamp();
-  ostringstream oss;
-  oss << ti.total_seconds();
+  // TimeInterval ti = time::NowUnixTimestamp();
+  // ostringstream oss;
+  // oss << ti.total_seconds();
 
   Name chatroom("/ndn/broadcast/chronos");
-  chatroom.append(string("chatroom-") + oss.str());
+  chatroom.append(string("chatroom-") + getRandomString());
 
   m_startChatDialog->setInvitee(m_currentSelectedContactNamespace, chatroom.toUri());
   m_startChatDialog->show();
 }
 
+// For inviter
 void
 ContactPanel::startChatroom(const QString& chatroom, const QString& invitee, bool isIntroducer)
 {
@@ -445,48 +447,59 @@
   _LOG_DEBUG("invitee: " << invitee.toUtf8().constData());
   _LOG_DEBUG("introducer: " << std::boolalpha << isIntroducer);
 
-  Name chatroomName("/ndn/broadcast/chronos");
-  chatroomName.append(chatroom.toUtf8().constData());
+  Name chatroomName(chatroom.toUtf8().constData());
   
-  ChatDialog* chatDialog = new ChatDialog(chatroomName, m_localPrefix, m_defaultIdentity);
+  ChatDialog* chatDialog = new ChatDialog(m_contactManager, chatroomName, m_localPrefix, m_defaultIdentity);
   m_chatDialogs.insert(pair <Name, ChatDialog*> (chatroomName, chatDialog));
   
   //TODO: send invitation
   Name inviteeNamespace(invitee.toUtf8().constData());
   Ptr<ContactItem> inviteeItem = m_contactManager->getContact(inviteeNamespace);
 
-  chatDialog->sendInvitation(inviteeItem); 
+  chatDialog->sendInvitation(inviteeItem, isIntroducer); 
   
   chatDialog->show();
 }
 
+// For Invitee
 void
-ContactPanel::startChatroom2(const QString& chatroom, const QString& inviter)
+ContactPanel::startChatroom2(const ChronosInvitation& invitation, 
+                             const security::IdentityCertificate& identityCertificate)
 {
-  _LOG_DEBUG("room: " << chatroom.toUtf8().constData());
-  _LOG_DEBUG("inviter: " << inviter.toUtf8().constData());
+  _LOG_DEBUG("room: " << invitation.getChatroom().toUri());
+  _LOG_DEBUG("inviter: " << invitation.getInviterNameSpace().toUri());
+
+  Name chatroomName("/ndn/broadcast/chronos");
+  chatroomName.append(invitation.getChatroom());
+
+  ChatDialog* chatDialog = new ChatDialog(m_contactManager, chatroomName, m_localPrefix, m_defaultIdentity);
+  chatDialog->addChatDataRule(invitation.getInviterPrefix(), identityCertificate, true);
+
+  Ptr<ContactItem> inviterItem = m_contactManager->getContact(invitation.getInviterNameSpace());
+  chatDialog->addTrustAnchor(inviterItem->getSelfEndorseCertificate());
+  
+  m_chatDialogs.insert(pair <Name, ChatDialog*> (chatroomName, chatDialog));
+
+  chatDialog->show();
 }
 
 void
-ContactPanel::acceptInvitation(const Name& interestName, 
-                               const security::IdentityCertificate& identityCertificate, 
-                               QString inviter, 
-                               QString chatroom)
+ContactPanel::acceptInvitation(const ChronosInvitation& invitation, 
+                               const security::IdentityCertificate& identityCertificate)
 {
   string prefix = m_localPrefix.toUri();
-  _LOG_DEBUG("interestName " << interestName);
-  _LOG_DEBUG("prefix " << prefix);
-  m_handler->publishDataByIdentity (interestName, prefix);
+
+  m_handler->publishDataByIdentity (invitation.getInterestName(), prefix);
   //TODO:: open chat dialog
-  _LOG_DEBUG("ok");
-  startChatroom2(chatroom, inviter);
+  _LOG_DEBUG("TO open chat dialog");
+  startChatroom2(invitation, identityCertificate);
 }
 
 void
-ContactPanel::rejectInvitation(const ndn::Name& interestName)
+ContactPanel::rejectInvitation(const ChronosInvitation& invitation)
 {
   string empty;
-  m_handler->publishDataByIdentity (interestName, empty);
+  m_handler->publishDataByIdentity (invitation.getInterestName(), empty);
 }
 
 
diff --git a/src/contactpanel.h b/src/contactpanel.h
index 2f33b49..5f595b0 100644
--- a/src/contactpanel.h
+++ b/src/contactpanel.h
@@ -26,6 +26,7 @@
 
 #ifndef Q_MOC_RUN
 #include "contact-manager.h"
+#include "chronos-invitation.h"
 #endif
 
 
@@ -79,7 +80,7 @@
   getRandomString();
 
   void
-  popChatInvitation(const ndn::Name& interestName,
+  popChatInvitation(ndn::Ptr<ChronosInvitation> invitation,
                     int inviterIndex,
                     const ndn::Name& inviterNameSpace,
                     ndn::Ptr<ndn::security::IdentityCertificate> certificate);
@@ -124,16 +125,15 @@
   startChatroom(const QString& chatroom, const QString& invitee, bool isIntroducer);
 
   void 
-  startChatroom2(const QString& chatroom, const QString& inviter);
+  startChatroom2(const ChronosInvitation& invitation, 
+                 const ndn::security::IdentityCertificate& identityCertificate);
 
   void
-  acceptInvitation(const ndn::Name& interestName, 
-                   const ndn::security::IdentityCertificate& identityCertificate, 
-                   QString inviter, 
-                   QString chatroom);
+  acceptInvitation(const ChronosInvitation& invitation, 
+                   const ndn::security::IdentityCertificate& identityCertificate);
 
   void
-  rejectInvitation(const ndn::Name& interestName);
+  rejectInvitation(const ChronosInvitation& invitation);
 
 private:
   Ui::ContactPanel *ui;
diff --git a/src/digesttreescene.cpp b/src/digesttreescene.cpp
new file mode 100644
index 0000000..5c785e6
--- /dev/null
+++ b/src/digesttreescene.cpp
@@ -0,0 +1,330 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "digesttreescene.h"
+
+#include <QtGui>
+
+#ifndef Q_MOC_RUN
+#include <vector>
+#include <iostream>
+#include <assert.h>
+#include <boost/lexical_cast.hpp>
+#include <memory>
+#endif
+
+static const double Pi = 3.14159265358979323846264338327950288419717;
+
+//DisplayUserPtr DisplayUserNullPtr;
+
+DigestTreeScene::DigestTreeScene(QWidget *parent)
+  : QGraphicsScene(parent)
+{
+  previouslyUpdatedUser = DisplayUserNullPtr;
+}
+
+void
+DigestTreeScene::processUpdate(const std::vector<Sync::MissingDataInfo> &v, QString digest)
+{
+  int n = v.size();
+  bool rePlot = false; 
+  for (int i = 0; i < n; i++) 
+  {
+    Roster_iterator it = m_roster.find(v[i].prefix.c_str());
+    if (it == m_roster.end()) 
+    {
+      rePlot = true; 
+      DisplayUserPtr p(new DisplayUser());
+      time_t tempTime = time(NULL) - FRESHNESS + 1;
+      p->setReceived(tempTime);
+      p->setPrefix(v[i].prefix.c_str());
+      p->setSeq(v[i].high);
+      m_roster.insert(p->getPrefix(), p);
+    }
+    else 
+    {
+      it.value()->setSeq(v[i].high);
+    }
+  }
+
+  if (rePlot) 
+  {
+    plot(digest);
+    QTimer::singleShot(2100, this, SLOT(emitReplot()));
+  }
+  else 
+  {
+    for (int i = 0; i < n; i++) 
+    {
+      Roster_iterator it = m_roster.find(v[i].prefix.c_str());
+      if (it != m_roster.end()) {
+        DisplayUserPtr p = it.value();
+        QGraphicsTextItem *item = p->getSeqTextItem();
+        QGraphicsRectItem *rectItem = p->getInnerRectItem();
+        std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
+        item->setPlainText(s.c_str());
+        QRectF textBR = item->boundingRect();
+        QRectF rectBR = rectItem->boundingRect();
+        item->setPos(rectBR.x() + (rectBR.width() - textBR.width())/2, rectBR.y() + (rectBR.height() - textBR.height())/2);
+      }
+    }
+    m_rootDigest->setPlainText(digest);
+  }
+}
+
+void
+DigestTreeScene::emitReplot()
+{
+  emit replot();
+}
+
+QStringList
+DigestTreeScene::getRosterList()
+{
+  QStringList rosterList;
+  RosterIterator it(m_roster);
+  while(it.hasNext())
+  {
+    it.next();
+    DisplayUserPtr p = it.value();
+    if (p != DisplayUserNullPtr)
+    {
+      rosterList << "- " + p->getNick();
+    }
+  }
+  return rosterList;
+}
+
+void
+DigestTreeScene::msgReceived(QString prefix, QString nick)
+{
+  Roster_iterator it = m_roster.find(prefix);
+  if (it != m_roster.end()) 
+  {
+    std::cout << "Updating for prefix = " << prefix.toStdString() << " nick = " << nick.toStdString() << std::endl;
+    DisplayUserPtr p = it.value();
+    p->setReceived(time(NULL));
+    if (nick != p->getNick()) {
+    std::cout << "old nick = " << p->getNick().toStdString() << std::endl;
+      p->setNick(nick);
+      QGraphicsTextItem *nickItem = p->getNickTextItem();
+      QGraphicsRectItem *nickRectItem = p->getNickRectItem();
+      nickItem->setPlainText(p->getNick());
+      QRectF rectBR = nickRectItem->boundingRect();
+      QRectF nickBR = nickItem->boundingRect();
+      nickItem->setPos(rectBR.x() + (rectBR.width() - nickBR.width())/2, rectBR.y() + 5);
+      emit rosterChanged(QStringList());
+    }
+
+    reDrawNode(p, Qt::red);
+
+    if (previouslyUpdatedUser != DisplayUserNullPtr && previouslyUpdatedUser != p) 
+    {
+      reDrawNode(previouslyUpdatedUser, Qt::darkBlue);
+    }
+
+    previouslyUpdatedUser = p;
+  }
+}
+
+void
+DigestTreeScene::clearAll()
+{
+  clear();
+  m_roster.clear();
+}
+
+bool
+DigestTreeScene::removeNode(const QString prefix)
+{
+  int removedCount = m_roster.remove(prefix);
+  return (removedCount > 0);
+}
+
+void
+DigestTreeScene::plot(QString digest)
+{
+#ifdef __DEBUG
+  std::cout << "Plotting at time: " << time(NULL) << std::endl;
+#endif
+  clear();
+
+  int nodeSize = 40;
+
+  int siblingDistance = 100, levelDistance = 100;
+  std::auto_ptr<TreeLayout> layout(new OneLevelTreeLayout());
+  layout->setSiblingDistance(siblingDistance);
+  layout->setLevelDistance(levelDistance);
+
+  // do some cleaning, get rid of stale member info
+  Roster_iterator it = m_roster.begin();
+  QStringList staleUserList;
+  while (it != m_roster.end())
+  {
+    DisplayUserPtr p = it.value();
+    if (p != DisplayUserNullPtr)
+    {
+      time_t now = time(NULL);
+      if (now - p->getReceived() >= FRESHNESS)
+      {
+#ifdef __DEBUG
+        std::cout << "Removing user: " << p->getNick().toStdString() << std::endl;
+        std::cout << "now - last = " << now - p->getReceived() << std::endl;
+#endif
+        staleUserList << p->getNick();
+        p = DisplayUserNullPtr;
+        it = m_roster.erase(it);
+      }
+      else
+      {
+        if (!m_currentPrefix.startsWith("/private/local") && p->getPrefix().startsWith("/private/local"))
+        {
+#ifdef __DEBUG
+          std::cout << "erasing: " << p->getPrefix().toStdString() << std::endl;
+#endif
+          staleUserList << p->getNick();
+          p = DisplayUserNullPtr;
+          it = m_roster.erase(it);
+          continue;
+        }
+        ++it;
+      }
+    }
+    else
+    {
+      it = m_roster.erase(it);
+    }
+  }
+
+  // for simpicity here, whenever we replot, we also redo the roster list
+  emit rosterChanged(staleUserList);
+
+  int n = m_roster.size();
+
+  std::vector<TreeLayout::Coordinate> childNodesCo(n);
+
+  layout->setOneLevelLayout(childNodesCo);
+
+  plotEdge(childNodesCo, nodeSize);
+  plotNode(childNodesCo, digest, nodeSize);
+
+  previouslyUpdatedUser = DisplayUserNullPtr;
+
+}
+
+void
+DigestTreeScene::plotEdge(const std::vector<TreeLayout::Coordinate> &childNodesCo, int nodeSize)
+{
+  int n = childNodesCo.size();
+  for (int i = 0; i < n; i++) {
+    double x1 = 0.0, y1 = 0.0;
+    double x2 = childNodesCo[i].x, y2 = childNodesCo[i].y;
+    QPointF src(x1 + nodeSize/2, y1 + nodeSize/2);
+    QPointF dest(x2 + nodeSize/2, y2 + nodeSize/2);
+    QLineF line(src, dest);
+    double angle = ::acos(line.dx() / line.length());
+
+    double arrowSize = 10;
+    QPointF sourceArrowP0 = src + QPointF((nodeSize/2 + 10) * line.dx() / line.length(),  (nodeSize/2 +10) * line.dy() / line.length());
+    QPointF sourceArrowP1 = sourceArrowP0 + QPointF(cos(angle + Pi / 3 - Pi/2) * arrowSize,
+                                                    sin(angle + Pi / 3 - Pi/2) * arrowSize);
+    QPointF sourceArrowP2 = sourceArrowP0 + QPointF(cos(angle + Pi - Pi / 3 - Pi/2) * arrowSize,
+                                                         sin(angle + Pi - Pi / 3 - Pi/2) * arrowSize);
+
+    addLine(QLineF(sourceArrowP0, dest), QPen(Qt::black));
+    addPolygon(QPolygonF() << sourceArrowP0<< sourceArrowP1 << sourceArrowP2, QPen(Qt::black), QBrush(Qt::black));
+  }
+}
+
+void
+DigestTreeScene::plotNode(const std::vector<TreeLayout::Coordinate> &childNodesCo, QString digest, int nodeSize)
+{
+  RosterIterator it(m_roster);
+  int n = childNodesCo.size();
+  int rim = 3;
+
+  // plot root node
+  QRectF rootBoundingRect(0, 0, nodeSize, nodeSize);
+  QRectF rootInnerBoundingRect(rim, rim, nodeSize - rim * 2, nodeSize - rim * 2);
+  addRect(rootBoundingRect, QPen(Qt::black), QBrush(Qt::darkRed));
+  addRect(rootInnerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
+  QRectF digestRect(- 5.5 * nodeSize , - nodeSize, 12 * nodeSize, 30);
+  addRect(digestRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
+
+  QGraphicsTextItem *digestItem = addText(digest);
+  QRectF digestBoundingRect = digestItem->boundingRect();
+  digestItem->setDefaultTextColor(Qt::black);
+  digestItem->setFont(QFont("Cursive", 12, QFont::Bold));
+  digestItem->setPos(- 4.5 * nodeSize + (12 * nodeSize - digestBoundingRect.width()) / 2, - nodeSize + 5);
+  m_rootDigest = digestItem;
+
+  // plot child nodes
+  for (int i = 0; i < n; i++)
+  {
+    if (it.hasNext()) 
+    {
+      it.next();
+    }
+    else 
+    {
+      abort();
+    }
+
+    double x = childNodesCo[i].x;
+    double y = childNodesCo[i].y;
+    QRectF boundingRect(x, y, nodeSize, nodeSize);
+    QRectF innerBoundingRect(x + rim, y + rim, nodeSize - rim * 2, nodeSize - rim * 2);
+    DisplayUserPtr p = it.value();
+    QGraphicsRectItem *rectItem = addRect(boundingRect, QPen(Qt::black), QBrush(Qt::darkBlue));
+    p->setRimRectItem(rectItem);
+
+    QGraphicsRectItem *innerRectItem = addRect(innerBoundingRect, QPen(Qt::black), QBrush(Qt::lightGray));
+    p->setInnerRectItem(innerRectItem);
+
+    std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
+    QGraphicsTextItem *seqItem = addText(s.c_str());
+    seqItem->setFont(QFont("Cursive", 12, QFont::Bold));
+    QRectF seqBoundingRect = seqItem->boundingRect(); 
+    seqItem->setPos(x + nodeSize / 2 - seqBoundingRect.width() / 2, y + nodeSize / 2 - seqBoundingRect.height() / 2);
+    p->setSeqTextItem(seqItem);
+
+    QRectF textRect(x - nodeSize / 2, y + nodeSize, 2 * nodeSize, 30);
+    QGraphicsRectItem *nickRectItem = addRect(textRect, QPen(Qt::darkCyan), QBrush(Qt::darkCyan));
+    p->setNickRectItem(nickRectItem);
+    QGraphicsTextItem *nickItem = addText(p->getNick());
+    QRectF textBoundingRect = nickItem->boundingRect();
+    nickItem->setDefaultTextColor(Qt::white);
+    nickItem->setFont(QFont("Cursive", 12, QFont::Bold));
+    nickItem->setPos(x + nodeSize / 2 - textBoundingRect.width() / 2, y + nodeSize + 5);
+    p->setNickTextItem(nickItem);
+  }
+
+}
+
+void
+DigestTreeScene::reDrawNode(DisplayUserPtr p, QColor rimColor)
+{
+    QGraphicsRectItem *rimItem = p->getRimRectItem();
+    rimItem->setBrush(QBrush(rimColor));
+    QGraphicsRectItem *innerItem = p->getInnerRectItem();
+    innerItem->setBrush(QBrush(Qt::lightGray));
+    QGraphicsTextItem *seqTextItem = p->getSeqTextItem();
+    std::string s = boost::lexical_cast<std::string>(p->getSeqNo().getSeq());
+    seqTextItem->setPlainText(s.c_str());
+    QRectF textBR = seqTextItem->boundingRect();
+    QRectF innerBR = innerItem->boundingRect();
+    seqTextItem->setPos(innerBR.x() + (innerBR.width() - textBR.width())/2, innerBR.y() + (innerBR.height() - textBR.height())/2);
+}
+
+#if WAF
+#include "digesttreescene.moc"
+#include "digesttreescene.cpp.moc"
+#endif
diff --git a/src/digesttreescene.h b/src/digesttreescene.h
new file mode 100644
index 0000000..7266ecb
--- /dev/null
+++ b/src/digesttreescene.h
@@ -0,0 +1,125 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef DIGESTTREESCENE_H
+#define DIGESTTREESCENE_H
+
+#include "treelayout.h"
+
+#include <QtGui/QGraphicsScene>
+#include <QColor>
+#include <QMap>
+
+#ifndef Q_MOC_RUN
+#include <sync-seq-no.h>
+#include <sync-logic.h>
+#include <ctime>
+#include <vector>
+#include <tr1/memory>
+#endif
+
+const int FRESHNESS = 60;
+
+class QGraphicsTextItem;
+
+class User;
+class DisplayUser;
+typedef std::tr1::shared_ptr<DisplayUser> DisplayUserPtr;
+static DisplayUserPtr DisplayUserNullPtr;
+
+class DigestTreeScene : public QGraphicsScene
+{
+  Q_OBJECT
+
+typedef QMap<QString, DisplayUserPtr> Roster;
+typedef QMap<QString, DisplayUserPtr>::iterator Roster_iterator;
+typedef QMapIterator<QString, DisplayUserPtr> RosterIterator;
+
+public:
+  DigestTreeScene(QWidget *parent = 0);
+  void processUpdate(const std::vector<Sync::MissingDataInfo> &v, QString digest);
+  void msgReceived(QString prefix, QString nick);
+  void clearAll();
+  bool removeNode(const QString prefix);
+  void plot(QString digest);
+  QStringList getRosterList();
+  void setCurrentPrefix(QString prefix) {m_currentPrefix = prefix;}
+  QMap<QString, DisplayUserPtr> getRosterFull() { return m_roster;}
+
+signals:
+  void replot();
+  void rosterChanged(QStringList);
+
+private slots:
+  void emitReplot();
+
+private:
+  void plotEdge(const std::vector<TreeLayout::Coordinate> &v, int nodeSize);
+  void plotNode(const std::vector<TreeLayout::Coordinate> &v, QString digest, int nodeSize);
+  void reDrawNode(DisplayUserPtr p, QColor rimColor);
+private:
+  Roster m_roster;
+  QGraphicsTextItem *m_rootDigest; 
+  DisplayUserPtr previouslyUpdatedUser;
+  QString m_currentPrefix;
+
+};
+
+class User 
+{
+public:
+  User():m_received(time(NULL)) {}
+  User(QString n, QString p, QString c): m_nick(n), m_prefix(p), m_chatroom(c), m_received(time(NULL)) {}
+  void setNick(QString nick) {m_nick = nick;}
+  void setPrefix(QString prefix) {m_prefix = prefix;}
+  void setChatroom(QString chatroom) {m_chatroom = chatroom;}
+  void setSeq(Sync::SeqNo seq) {m_seq = seq;}
+  void setReceived(time_t t) {m_received = t;}
+  void setOriginPrefix(QString originPrefix) { m_originPrefix = originPrefix;}
+  QString getNick() { return m_nick;}
+  QString getPrefix() { return m_prefix;}
+  QString getChatroom() { return m_chatroom;}
+  QString getOriginPrefix() { return m_originPrefix;}
+  Sync::SeqNo getSeqNo() { return m_seq;}
+  time_t getReceived() { return m_received;}
+private:
+  QString m_nick;
+  QString m_prefix;
+  QString m_chatroom;
+  QString m_originPrefix;
+  Sync::SeqNo m_seq;
+  time_t m_received;
+};
+
+class DisplayUser : public User 
+{
+public:
+  DisplayUser():m_seqTextItem(NULL), m_nickTextItem(NULL), m_rimRectItem(NULL) {}
+  DisplayUser(QString n, QString p , QString c): User(n, p, c), m_seqTextItem(NULL), m_nickTextItem(NULL), m_rimRectItem(NULL) {}
+  QGraphicsTextItem *getSeqTextItem() {return m_seqTextItem;}
+  QGraphicsTextItem *getNickTextItem() {return m_nickTextItem;}
+  QGraphicsRectItem *getRimRectItem() {return m_rimRectItem;}
+  QGraphicsRectItem *getInnerRectItem() {return m_innerRectItem;}
+  QGraphicsRectItem *getNickRectItem() {return m_nickRectItem;}
+  void setSeqTextItem(QGraphicsTextItem *item) { m_seqTextItem = item;}
+  void setNickTextItem(QGraphicsTextItem *item) { m_nickTextItem = item;}
+  void setRimRectItem(QGraphicsRectItem *item) {m_rimRectItem = item;}
+  void setInnerRectItem(QGraphicsRectItem *item) {m_innerRectItem = item;}
+  void setNickRectItem(QGraphicsRectItem *item) {m_nickRectItem = item;}
+private:
+  QGraphicsTextItem *m_seqTextItem;
+  QGraphicsTextItem *m_nickTextItem;
+  QGraphicsRectItem *m_rimRectItem;
+  QGraphicsRectItem *m_innerRectItem;
+  QGraphicsRectItem *m_nickRectItem;
+};
+
+#endif
diff --git a/src/exception.h b/src/exception.h
index fbd1812..5cce5aa 100644
--- a/src/exception.h
+++ b/src/exception.h
@@ -22,9 +22,10 @@
   ~LnException() throw()
   {}
   
-  inline const std::string& 
-  msg() const 
-  {return m_errMsg;}
+  const char* what() const throw()
+  {
+    return m_errMsg.c_str();
+  }
   
 private:
   const std::string m_errMsg;
diff --git a/src/invitation-policy-manager.cpp b/src/invitation-policy-manager.cpp
index a8b75fb..10929e3 100644
--- a/src/invitation-policy-manager.cpp
+++ b/src/invitation-policy-manager.cpp
@@ -10,8 +10,7 @@
 
 #include "invitation-policy-manager.h"
 
-#include <ndn.cxx/security/certificate/identity-certificate.h>
-#include <boost/bind.hpp>
+#include <ndn.cxx/security/cache/ttl-certificate-cache.h>
 
 #include "logging.h"
 
@@ -21,51 +20,43 @@
 
 INIT_LOGGER("InvitationPolicyManager");
 
-InvitationPolicyManager::InvitationPolicyManager(const int & stepLimit,
-						 Ptr<CertificateCache> certificateCache)
-  : m_stepLimit(stepLimit)
+InvitationPolicyManager::InvitationPolicyManager(const string& chatroomName,
+                                             int stepLimit,
+					     Ptr<CertificateCache> certificateCache)
+  : m_chatroomName(chatroomName)
+  , m_stepLimit(stepLimit)
   , m_certificateCache(certificateCache)
-  , m_localPrefixRegex(Ptr<Regex>(new Regex("^<local><ndn><prefix><><>$")))
 {
-  m_invitationDataRule = Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^<ndn><broadcast><chronos><invitation>([^<chatroom>]*)<chatroom>", 
-        								"^([^<KEY>]*)<KEY><DSK-.*><ID-CERT><>$", 
-        								"==", "\\1", "\\1", true));
-  
-  m_dskRule = Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<KEY>]*)<KEY><DSK-.*><ID-CERT><>$", 
-							     "^([^<KEY>]*)<KEY>(<>*)<KSK-.*><ID-CERT><>$", 
+  if(m_certificateCache == NULL)
+    m_certificateCache = Ptr<TTLCertificateCache>(new TTLCertificateCache());
+
+  m_invitationPolicyRule = Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^<ndn><broadcast><chronos><invitation>([^<chatroom>]*)<chatroom>", 
+									  "^([^<KEY>]*)<KEY><dsk-.*><ID-CERT>$", 
+									  "==", "\\1", "\\1", true));
+
+  m_dskRule = Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<KEY>]*)<KEY><dsk-.*><ID-CERT><>$", 
+							     "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$", 
 							     "==", "\\1", "\\1\\2", true));
 
-  m_keyNameRegex = Ptr<Regex>(new Regex("^([^<KEY>]*)<KEY>(<>*<KSK-.*>)<ID-CERT><>$", "\\1\\2"));
+  m_keyNameRegex = Ptr<Regex>(new Regex("^([^<KEY>]*)<KEY>(<>*<ksk-.*>)<ID-CERT>$", "\\1\\2"));
+} 
 
-  m_signingCertificateRegex = Ptr<Regex>(new Regex("^<ndn><broadcast><chronos><invitation>([^<chatroom>]*)<chatroom>", "\\1"));
-}
+InvitationPolicyManager::~InvitationPolicyManager()
+{}
 
 bool 
-InvitationPolicyManager::skipVerifyAndTrust (const Data & data)
-{
-  if(m_localPrefixRegex->match(data.getName()))
-    return true;
-  
-  return false;
-}
+InvitationPolicyManager::skipVerifyAndTrust (const Data& data)
+{ return false; }
 
 bool
-InvitationPolicyManager::requireVerify (const Data & data)
-{
-  // if(m_invitationDataRule->matchDataName(data))
-  //   return true;
-
-  if(m_dskRule->matchDataName(data))
-    return true;
-
-  return false;
-}
+InvitationPolicyManager::requireVerify (const Data& data)
+{ return true; }
 
 Ptr<ValidationRequest>
 InvitationPolicyManager::checkVerificationPolicy(Ptr<Data> data, 
-						 const int & stepCount, 
-						 const DataCallback& verifiedCallback,
-						 const UnverifiedCallback& unverifiedCallback)
+					       const int& stepCount, 
+					       const DataCallback& verifiedCallback,
+					       const UnverifiedCallback& unverifiedCallback)
 {
   if(m_stepLimit == stepCount)
     {
@@ -84,46 +75,46 @@
 
   const Name & keyLocatorName = sha256sig->getKeyLocator().getKeyName();
 
-  // if(m_invitationDataRule->satisfy(*data))
-  //   {
-  //     Ptr<const IdentityCertificate> trustedCert = m_certificateCache->getCertificate(keyLocatorName);
+  if(m_invitationPolicyRule->satisfy(*data))
+    {
+      Ptr<const IdentityCertificate> trustedCert = m_certificateCache->getCertificate(keyLocatorName);
       
-  //     if(NULL != trustedCert){
-  //       if(verifySignature(*data, trustedCert->getPublicKeyInfo()))
-  //         verifiedCallback(data);
-  //       else
-  //         unverifiedCallback(data);
+      if(NULL != trustedCert){
+	if(verifySignature(*data, trustedCert->getPublicKeyInfo()))
+	  verifiedCallback(data);
+	else
+	  unverifiedCallback(data);
 
-  //       return NULL;
-  //     }
-  //     else{
-  //       _LOG_DEBUG("KeyLocator has not been cached and validated!");
+	return NULL;
+      }
+      else{
+	_LOG_DEBUG("KeyLocator has not been cached and validated!");
 
-  //       DataCallback recursiveVerifiedCallback = boost::bind(&InvitationPolicyManager::onCertificateVerified, 
-  //       						     this, 
-  //       						     _1, 
-  //       						     data, 
-  //       						     verifiedCallback, 
-  //       						     unverifiedCallback);
+	DataCallback recursiveVerifiedCallback = boost::bind(&InvitationPolicyManager::onDskCertificateVerified, 
+							     this, 
+							     _1, 
+							     data, 
+							     verifiedCallback, 
+							     unverifiedCallback);
 
-  //       UnverifiedCallback recursiveUnverifiedCallback = boost::bind(&InvitationPolicyManager::onCertificateUnverified, 
-  //       							     this, 
-  //       							     _1, 
-  //       							     data, 
-  //       							     unverifiedCallback);
+	UnverifiedCallback recursiveUnverifiedCallback = boost::bind(&InvitationPolicyManager::onDskCertificateUnverified, 
+								     this, 
+								     _1, 
+								     data, 
+								     unverifiedCallback);
 
 
-  //       Ptr<Interest> interest = Ptr<Interest>(new Interest(sha256sig->getKeyLocator().getKeyName()));
+	Ptr<Interest> interest = Ptr<Interest>(new Interest(keyLocatorName));
 	
-  //       Ptr<ValidationRequest> nextStep = Ptr<ValidationRequest>(new ValidationRequest(interest, 
-  //       									       recursiveVerifiedCallback,
-  //       									       recursiveUnverifiedCallback,
-  //       									       0,
-  //       									       stepCount + 1)
-  //       							 );
-  //       return nextStep;
-  //     }
-  //   }
+	Ptr<ValidationRequest> nextStep = Ptr<ValidationRequest>(new ValidationRequest(interest, 
+										       recursiveVerifiedCallback,
+										       recursiveUnverifiedCallback,
+										       0,
+										       stepCount + 1)
+								 );
+	return nextStep;
+      }
+    }
 
   if(m_dskRule->satisfy(*data))
     {
@@ -145,41 +136,86 @@
   return NULL;
 }
 
-// void 
-// InvitationPolicyManager::onCertificateVerified(Ptr<Data> certData, 
-// 					       Ptr<Data> originalData,
-// 					       const DataCallback& verifiedCallback, 
-// 					       const UnverifiedCallback& unverifiedCallback)
-// {
-//   IdentityCertificate certificate(*certData);
-
-//   if(verifySignature(*originalData, certificate.getPublicKeyInfo()))
-//     verifiedCallback(originalData);
-//   else
-//     unverifiedCallback(originalData);
-// }
-
-// void
-// InvitationPolicyManager::onCertificateUnverified(Ptr<Data> certData, 
-// 						 Ptr<Data> originalData,
-// 						 const UnverifiedCallback& unverifiedCallback)
-// { unverifiedCallback(originalData); }
-
 bool 
-InvitationPolicyManager::checkSigningPolicy(const Name & dataName, const Name & certificateName)
+InvitationPolicyManager::checkSigningPolicy(const Name& dataName, 
+					  const Name& certificateName)
 {
-  return m_invitationDataRule->satisfy(dataName, certificateName);
+  //TODO:
+  return true;
 }
-
+    
 Name 
-InvitationPolicyManager::inferSigningIdentity(const Name & dataName)
+InvitationPolicyManager::inferSigningIdentity(const Name& dataName)
 {
-  if(m_signingCertificateRegex->match(dataName))
-    return m_signingCertificateRegex->expand();
-  else
-    return Name();
+  //TODO:
+  return Name();
 }
 
 void
 InvitationPolicyManager::addTrustAnchor(const EndorseCertificate& selfEndorseCertificate)
 { m_trustAnchors.insert(pair <Name, Publickey > (selfEndorseCertificate.getPublicKeyName(), selfEndorseCertificate.getPublicKeyInfo())); }
+
+
+// void
+// InvitationPolicyManager::addChatDataRule(const Name& prefix, 
+//                                        const IdentityCertificate identityCertificate)
+// {
+//   Name dataPrefix = prefix;
+//   dataPrefix.append("chronos").append(m_chatroomName);
+//   Ptr<Regex> dataRegex = Regex::fromName(prefix);
+//   Name certName = identityCertificate.getName();
+//   Name signerName = certName.getPrefix(certName.size()-1);
+//   Ptr<Regex> signerRegex = Regex::fromName(signerName, true);
+  
+//   ChatPolicyRule rule(dataRegex, signerRegex);
+//   map<Name, ChatPolicyRule>::iterator it = m_chatDataRules.find(dataPrefix);
+//   if(it != m_chatDataRules.end())
+//     it->second = rule;
+//   else
+//     m_chatDataRules.insert(pair <Name, ChatPolicyRule > (dataPrefix, rule));
+// }
+
+
+void 
+InvitationPolicyManager::onDskCertificateVerified(Ptr<Data> certData, 
+					     Ptr<Data> originalData,
+					     const DataCallback& verifiedCallback, 
+					     const UnverifiedCallback& unverifiedCallback)
+{
+  Ptr<IdentityCertificate> certificate = Ptr<IdentityCertificate>(new IdentityCertificate(*certData));
+
+  if(!certificate->isTooLate() && !certificate->isTooEarly())
+    {
+      Name certName = certificate->getName().getPrefix(certificate->getName().size()-1);
+      map<Name, Ptr<IdentityCertificate> >::iterator it = m_dskCertificates.find(certName);
+      if(it == m_dskCertificates.end())
+        m_dskCertificates.insert(pair <Name, Ptr<IdentityCertificate> > (certName, certificate));
+
+      if(verifySignature(*originalData, certificate->getPublicKeyInfo()))
+        {
+          verifiedCallback(originalData);
+          return;
+        }
+    }
+  else
+    {
+      unverifiedCallback(originalData);
+      return;
+    }
+}
+
+void
+InvitationPolicyManager::onDskCertificateUnverified(Ptr<Data> certData, 
+                                                  Ptr<Data> originalData,
+                                                  const UnverifiedCallback& unverifiedCallback)
+{ unverifiedCallback(originalData); }
+
+Ptr<IdentityCertificate> 
+InvitationPolicyManager::getValidatedDskCertificate(const ndn::Name& certName)
+{
+  map<Name, Ptr<IdentityCertificate> >::iterator it = m_dskCertificates.find(certName);
+  if(m_dskCertificates.end() != it)
+    return it->second;
+  else
+    return NULL;
+}
diff --git a/src/invitation-policy-manager.h b/src/invitation-policy-manager.h
index c8316cd..85afa53 100644
--- a/src/invitation-policy-manager.h
+++ b/src/invitation-policy-manager.h
@@ -14,93 +14,80 @@
 #include <ndn.cxx/security/policy/policy-manager.h>
 #include <ndn.cxx/security/policy/identity-policy-rule.h>
 #include <ndn.cxx/security/cache/certificate-cache.h>
+#include <ndn.cxx/regex/regex.h>
 #include <map>
 
 #include "endorse-certificate.h"
+#include "chat-policy-rule.h"
 
 class InvitationPolicyManager : public ndn::security::PolicyManager
 {
 public:
-  InvitationPolicyManager(const int & stepLimit = 10,                        
-                          ndn::Ptr<ndn::security::CertificateCache> certificateCache = NULL);
+  InvitationPolicyManager(const std::string& chatroomName,
+                        int stepLimit = 10,
+                        ndn::Ptr<ndn::security::CertificateCache> certificateCache = NULL);
+  
+  virtual
+  ~InvitationPolicyManager();
 
-  ~InvitationPolicyManager()
-  {}
-
-  /**
-   * @brief check if the received data packet can escape from verification
-   * @param data the received data packet
-   * @return true if the data does not need to be verified, otherwise false
-   */
   bool 
-  skipVerifyAndTrust (const ndn::Data & data);
+  skipVerifyAndTrust (const ndn::Data& data);
 
-  /**
-   * @brief check if PolicyManager has the verification rule for the received data
-   * @param data the received data packet
-   * @return true if the data must be verified, otherwise false
-   */
   bool
-  requireVerify (const ndn::Data & data);
+  requireVerify (const ndn::Data& data);
 
-  /**
-   * @brief check whether received data packet complies with the verification policy, and get the indication of next verification step
-   * @param data the received data packet
-   * @param stepCount the number of verification steps that have been done, used to track the verification progress
-   * @param verifiedCallback the callback function that will be called if the received data packet has been validated
-   * @param unverifiedCallback the callback function that will be called if the received data packet cannot be validated
-   * @return the indication of next verification step, NULL if there is no further step
-   */
   ndn::Ptr<ndn::security::ValidationRequest>
   checkVerificationPolicy(ndn::Ptr<ndn::Data> data, 
-                          const int & stepCount, 
+                          const int& stepCount, 
                           const ndn::DataCallback& verifiedCallback,
                           const ndn::UnverifiedCallback& unverifiedCallback);
 
-    
-  /**
-   * @brief check if the signing certificate name and data name satify the signing policy 
-   * @param dataName the name of data to be signed
-   * @param certificateName the name of signing certificate
-   * @return true if the signing certificate can be used to sign the data, otherwise false
-   */
   bool 
-  checkSigningPolicy(const ndn::Name & dataName, const ndn::Name & certificateName);
-  
-  /**
-   * @brief Infer signing identity name according to policy, if the signing identity cannot be inferred, it should return empty name
-   * @param dataName, the name of data to be signed
-   * @return the signing identity. 
-   */
+  checkSigningPolicy(const ndn::Name& dataName, 
+                     const ndn::Name& certificateName);
+    
   ndn::Name 
-  inferSigningIdentity(const ndn::Name & dataName);
+  inferSigningIdentity(const ndn::Name& dataName);
 
-  
   void
   addTrustAnchor(const EndorseCertificate& selfEndorseCertificate);
+  
+  // void 
+  // addChatDataRule(const ndn::Name& prefix, 
+  //                 const ndn::security::IdentityCertificate identityCertificate);
 
-// private:
-//   void 
-//   onCertificateVerified(ndn::Ptr<ndn::Data> certData, 
-//                         ndn::Ptr<ndn::Data> originalData,
-//                         const ndn::DataCallback& verifiedCallback, 
-//                         const ndn::UnverifiedCallback& unverifiedCallback);
-
-//   void
-//   onCertificateUnverified(ndn::Ptr<ndn::Data> certData, 
-//                           ndn::Ptr<ndn::Data> originalData,
-//                           const ndn::UnverifiedCallback& unverifiedCallback);
+  ndn::Ptr<ndn::security::IdentityCertificate> 
+  getValidatedDskCertificate(const ndn::Name& certName);
 
 private:
+  void 
+  onDskCertificateVerified(ndn::Ptr<ndn::Data> certData, 
+                        ndn::Ptr<ndn::Data> originalData,
+                        const ndn::DataCallback& verifiedCallback, 
+                        const ndn::UnverifiedCallback& unverifiedCallback);
+
+  void
+  onDskCertificateUnverified(ndn::Ptr<ndn::Data> certData, 
+                          ndn::Ptr<ndn::Data> originalData,
+                          const ndn::UnverifiedCallback& unverifiedCallback);
+
+private:
+  std::string m_chatroomName;
+
   int m_stepLimit;
+
   ndn::Ptr<ndn::security::CertificateCache> m_certificateCache;
-  ndn::Ptr<ndn::Regex> m_localPrefixRegex;
-  ndn::Ptr<ndn::security::IdentityPolicyRule> m_invitationDataRule;
+
+  ndn::Ptr<ndn::security::IdentityPolicyRule> m_invitationPolicyRule;
   ndn::Ptr<ndn::security::IdentityPolicyRule> m_dskRule;
+  std::map<ndn::Name, ChatPolicyRule> m_chatDataRules;
+
   ndn::Ptr<ndn::Regex> m_keyNameRegex;
-  ndn::Ptr<ndn::Regex> m_signingCertificateRegex;
+
   std::map<ndn::Name, ndn::security::Publickey> m_trustAnchors;
-  
+
+  std::map<ndn::Name, ndn::Ptr<ndn::security::IdentityCertificate> > m_dskCertificates;
+
 };
 
-#endif
+#endif //CHATROOM_POLICY_MANAGER_H
diff --git a/src/invitationdialog.cpp b/src/invitationdialog.cpp
index c00727d..9194bcc 100644
--- a/src/invitationdialog.cpp
+++ b/src/invitationdialog.cpp
@@ -33,23 +33,25 @@
 }
 
 void
-InvitationDialog::setMsg(const string& inviter, const string& chatroom)
+InvitationDialog::setInvitation(const string& alias,
+                                Ptr<ChronosInvitation> invitation, 
+                                Ptr<security::IdentityCertificate> identityCertificate)
 {
-  m_inviter = inviter;
-  m_chatroom = chatroom;
-  string msg = inviter;
+  m_inviterAlias = alias;
+  string msg = alias;
   msg.append(" invites you to join the chat room: ");
-  
   ui->msgLabel->setText(QString::fromUtf8(msg.c_str()));
-  ui->chatroomLine->setText(QString::fromUtf8(chatroom.c_str()));
+
+  m_invitation = invitation;
+  ui->chatroomLine->setText(QString::fromUtf8(invitation->getChatroom().get(0).toUri().c_str()));
+
+  m_identityCertificate = identityCertificate;
 }
 
 void
 InvitationDialog::onOkClicked()
 { 
-  QString inviter = QString::fromUtf8(m_inviter.c_str());
-  QString chatroom = QString::fromUtf8(m_chatroom.c_str());
-  emit invitationAccepted(m_interestName, *m_identityCertificate, inviter, chatroom); 
+  emit invitationAccepted(*m_invitation, *m_identityCertificate); 
   this->close();
 }
   
@@ -58,10 +60,12 @@
 { 
   ui->msgLabel->clear();
   ui->chatroomLine->clear();
-  m_interestName = Name();
-  m_inviter.clear();
-  m_chatroom.clear();
-  emit invitationRejected(m_interestName); 
+
+  m_invitation = NULL;
+  m_identityCertificate = NULL;
+  m_inviterAlias.clear();
+
+  emit invitationRejected(*m_invitation); 
   this->close();
 }
 
diff --git a/src/invitationdialog.h b/src/invitationdialog.h
index 3826ad4..d90b80e 100644
--- a/src/invitationdialog.h
+++ b/src/invitationdialog.h
@@ -16,6 +16,7 @@
 #ifndef Q_MOC_RUN
 #include <ndn.cxx/data.h>
 #include <ndn.cxx/security/certificate/identity-certificate.h>
+#include "chronos-invitation.h"
 #endif
 
 namespace Ui {
@@ -31,25 +32,17 @@
   ~InvitationDialog();
 
   void
-  setMsg(const std::string& inviter, const std::string& chatroom);
-
-  inline void
-  setInterestName(const ndn::Name& interestName)
-  { m_interestName = interestName; }
-
-  inline void
-  setIdentityCertificate(const ndn::Ptr<ndn::security::IdentityCertificate> identityCertificate)
-  { m_identityCertificate = identityCertificate; }
+  setInvitation(const std::string& alias,
+                ndn::Ptr<ChronosInvitation> invitation, 
+                ndn::Ptr<ndn::security::IdentityCertificate> identityCertificate);
 
 signals:
   void
-  invitationAccepted(const ndn::Name& interestName, 
-                     const ndn::security::IdentityCertificate& identityCertificate, 
-                     QString inviter, 
-                     QString chatroom);
+  invitationAccepted(const ChronosInvitation& invitation, 
+                     const ndn::security::IdentityCertificate& identityCertificate);
   
   void
-  invitationRejected(const ndn::Name& interestName);
+  invitationRejected(const ChronosInvitation& invitation);
 
 private slots:
   void
@@ -61,9 +54,8 @@
 
 private:
   Ui::InvitationDialog *ui;
-  std::string m_inviter;
-  std::string m_chatroom;
-  ndn::Name m_interestName;
+  std::string m_inviterAlias;
+  ndn::Ptr<ChronosInvitation> m_invitation;
   ndn::Ptr<ndn::security::IdentityCertificate> m_identityCertificate;
 };
 
diff --git a/src/invitelistdialog.cpp b/src/invitelistdialog.cpp
new file mode 100644
index 0000000..797a312
--- /dev/null
+++ b/src/invitelistdialog.cpp
@@ -0,0 +1,93 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "invitelistdialog.h"
+#include "ui_invitelistdialog.h"
+
+using namespace std;
+
+InviteListDialog::InviteListDialog(ndn::Ptr<ContactManager> contactManager,
+				   QWidget *parent) 
+  :QDialog(parent)
+  , ui(new Ui::InviteListDialog)
+  , m_contactManager(contactManager)
+  , m_contactListModel(new QStringListModel)
+{
+  ui->setupUi(this);
+
+  refreshContactList();
+
+  ui->contactListView->setModel(m_contactListModel);
+
+  connect(ui->inviteButton, SIGNAL(clicked()),
+	  this, SLOT(inviteWrapper()));
+  connect(ui->cancelButton, SIGNAL(clicked()),
+	  this, SLOT(onCancelClicked()));
+}
+
+InviteListDialog::~InviteListDialog()
+{
+  delete ui;
+  delete m_contactListModel;
+}
+
+void
+InviteListDialog::setInviteLabel(string label)
+{ 
+  string msg("invite to chatroom:\n");
+  msg += label;
+  ui->inviteLabel->setText(QString::fromUtf8(msg.c_str())); 
+  refreshContactList();
+}
+
+void
+InviteListDialog::refreshContactList()
+{
+  m_contactList = m_contactManager->getContactItemList();
+  QStringList contactNameList;
+  for(int i = 0; i < m_contactList.size(); i++)
+    {
+      contactNameList << QString::fromUtf8(m_contactList[i]->getAlias().c_str());
+    }
+
+  m_contactListModel->setStringList(contactNameList);
+}
+
+void
+InviteListDialog::inviteWrapper()
+{
+  QModelIndexList selected = ui->contactListView->selectionModel()->selectedIndexes();
+  QString text = m_contactListModel->data(selected.first(), Qt::DisplayRole).toString();
+  string alias = text.toUtf8().constData();
+
+  int i = 0;
+  for(; i < m_contactList.size(); i++)
+    {
+      if(alias == m_contactList[i]->getAlias())
+        break;
+    }
+
+  QString invitedContactNamespace = QString::fromUtf8(m_contactList[i]->getNameSpace().toUri().c_str());
+
+  bool isIntroducer = true;
+
+  emit invitionDetermined(invitedContactNamespace, isIntroducer);
+
+  this->close();
+}
+
+void
+InviteListDialog::onCancelClicked()
+{ this->close(); }
+
+#if WAF
+#include "invitelistdialog.moc"
+#include "invitelistdialog.cpp.moc"
+#endif
diff --git a/src/invitelistdialog.h b/src/invitelistdialog.h
new file mode 100644
index 0000000..cda26e5
--- /dev/null
+++ b/src/invitelistdialog.h
@@ -0,0 +1,59 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef INVITELISTDIALOG_H
+#define INVITELISTDIALOG_H
+
+#include <QDialog>
+#include <QStringListModel>
+
+#ifndef Q_MOC_RUN
+#include "contact-manager.h"
+#endif
+
+namespace Ui {
+class InviteListDialog;
+}
+
+class InviteListDialog : public QDialog
+{
+  Q_OBJECT
+
+public:
+  explicit InviteListDialog(ndn::Ptr<ContactManager> contactManager,
+                            QWidget *parent = 0);
+  ~InviteListDialog();
+
+  void
+  setInviteLabel(std::string label);
+  
+signals:
+  void
+  invitionDetermined(QString, bool);
+
+private slots:
+  void
+  refreshContactList();
+
+  void 
+  inviteWrapper();
+
+  void
+  onCancelClicked();
+
+private:
+  Ui::InviteListDialog *ui;
+  ndn::Ptr<ContactManager> m_contactManager;
+  QStringListModel* m_contactListModel;
+  std::vector<ndn::Ptr<ContactItem> > m_contactList;
+  std::vector<std::string> m_invitedContacts;
+};
+
+#endif // INVITELISTDIALOG_H
diff --git a/src/invitelistdialog.ui b/src/invitelistdialog.ui
new file mode 100644
index 0000000..0143de6
--- /dev/null
+++ b/src/invitelistdialog.ui
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InviteListDialog</class>
+ <widget class="QDialog" name="InviteListDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>300</width>
+    <height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <widget class="QWidget" name="">
+   <property name="geometry">
+    <rect>
+     <x>10</x>
+     <y>10</y>
+     <width>281</width>
+     <height>381</height>
+    </rect>
+   </property>
+   <layout class="QVBoxLayout" name="verticalLayout" stretch="4,1,20,2">
+    <property name="spacing">
+     <number>10</number>
+    </property>
+    <item>
+     <widget class="QLabel" name="inviteLabel">
+      <property name="font">
+       <font>
+        <weight>75</weight>
+        <bold>true</bold>
+       </font>
+      </property>
+      <property name="text">
+       <string>TextLabel</string>
+      </property>
+      <property name="alignment">
+       <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QCheckBox" name="isIntroducer">
+      <property name="text">
+       <string>as introducer</string>
+      </property>
+      <property name="checkable">
+       <bool>false</bool>
+      </property>
+      <property name="checked">
+       <bool>false</bool>
+      </property>
+      <property name="tristate">
+       <bool>false</bool>
+      </property>
+     </widget>
+    </item>
+    <item>
+     <widget class="QListView" name="contactListView"/>
+    </item>
+    <item>
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <item>
+       <widget class="QPushButton" name="cancelButton">
+        <property name="text">
+         <string>Cancel</string>
+        </property>
+        <property name="autoDefault">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="inviteButton">
+        <property name="text">
+         <string>Invite</string>
+        </property>
+        <property name="autoDefault">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/main.cpp b/src/main.cpp
index 9464195..0ae3da1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -22,9 +22,31 @@
 
 using namespace ndn;
 
+class NewApp : public QApplication
+{
+public:
+  NewApp(int & argc, char ** argv)
+    : QApplication(argc, argv)
+  {}
+
+  bool notify(QObject * receiver, QEvent * event) 
+  {
+    try 
+      {
+        return QApplication::notify(receiver, event);
+      } 
+    catch(std::exception& e) 
+      {
+        std::cerr << "Exception thrown:" << e.what() << endl;
+        return false;
+      }
+    
+  }
+};
+
 int main(int argc, char *argv[])
 {
-  QApplication app(argc, argv);
+  NewApp app(argc, argv);
 
 
 //   app.setWindowIcon(QIcon("/Users/yuyingdi/Develop/QT/demo.icns"));
diff --git a/src/panel-policy-manager.cpp b/src/panel-policy-manager.cpp
new file mode 100644
index 0000000..d3c7260
--- /dev/null
+++ b/src/panel-policy-manager.cpp
@@ -0,0 +1,191 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#include "panel-policy-manager.h"
+
+#include <ndn.cxx/security/certificate/identity-certificate.h>
+#include <boost/bind.hpp>
+
+#include "logging.h"
+
+using namespace std;
+using namespace ndn;
+using namespace ndn::security;
+
+INIT_LOGGER("PanelPolicyManager");
+
+PanelPolicyManager::PanelPolicyManager(const int & stepLimit,
+						 Ptr<CertificateCache> certificateCache)
+  : m_stepLimit(stepLimit)
+  , m_certificateCache(certificateCache)
+  , m_localPrefixRegex(Ptr<Regex>(new Regex("^<local><ndn><prefix><><>$")))
+{
+  m_invitationDataSigningRule = Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^<ndn><broadcast><chronos><invitation>([^<chatroom>]*)<chatroom>", 
+        								"^([^<KEY>]*)<KEY><dsk-.*><ID-CERT><>$", 
+        								"==", "\\1", "\\1", true));
+  
+  m_dskRule = Ptr<IdentityPolicyRule>(new IdentityPolicyRule("^([^<KEY>]*)<KEY><dsk-.*><ID-CERT><>$", 
+							     "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$", 
+							     "==", "\\1", "\\1\\2", true));
+
+  m_keyNameRegex = Ptr<Regex>(new Regex("^([^<KEY>]*)<KEY>(<>*<ksk-.*>)<ID-CERT>$", "\\1\\2"));
+
+  m_signingCertificateRegex = Ptr<Regex>(new Regex("^<ndn><broadcast><chronos><invitation>([^<chatroom>]*)<chatroom>", "\\1"));
+}
+
+bool 
+PanelPolicyManager::skipVerifyAndTrust (const Data & data)
+{
+  if(m_localPrefixRegex->match(data.getName()))
+    return true;
+  
+  return false;
+}
+
+bool
+PanelPolicyManager::requireVerify (const Data & data)
+{
+  // if(m_invitationDataRule->matchDataName(data))
+  //   return true;
+
+  if(m_dskRule->matchDataName(data))
+    return true;
+
+  return false;
+}
+
+Ptr<ValidationRequest>
+PanelPolicyManager::checkVerificationPolicy(Ptr<Data> data, 
+						 const int & stepCount, 
+						 const DataCallback& verifiedCallback,
+						 const UnverifiedCallback& unverifiedCallback)
+{
+  _LOG_DEBUG("checkVerificationPolicy");
+  if(m_stepLimit == stepCount)
+    {
+      _LOG_DEBUG("reach the maximum steps of verification");
+      unverifiedCallback(data);
+      return NULL;
+    }
+
+  Ptr<const signature::Sha256WithRsa> sha256sig = boost::dynamic_pointer_cast<const signature::Sha256WithRsa> (data->getSignature());    
+
+  if(KeyLocator::KEYNAME != sha256sig->getKeyLocator().getType())
+    {
+      unverifiedCallback(data);
+      return NULL;
+    }
+
+  const Name & keyLocatorName = sha256sig->getKeyLocator().getKeyName();
+
+  // if(m_invitationDataRule->satisfy(*data))
+  //   {
+  //     Ptr<const IdentityCertificate> trustedCert = m_certificateCache->getCertificate(keyLocatorName);
+      
+  //     if(NULL != trustedCert){
+  //       if(verifySignature(*data, trustedCert->getPublicKeyInfo()))
+  //         verifiedCallback(data);
+  //       else
+  //         unverifiedCallback(data);
+
+  //       return NULL;
+  //     }
+  //     else{
+  //       _LOG_DEBUG("KeyLocator has not been cached and validated!");
+
+  //       DataCallback recursiveVerifiedCallback = boost::bind(&PanelPolicyManager::onCertificateVerified, 
+  //       						     this, 
+  //       						     _1, 
+  //       						     data, 
+  //       						     verifiedCallback, 
+  //       						     unverifiedCallback);
+
+  //       UnverifiedCallback recursiveUnverifiedCallback = boost::bind(&PanelPolicyManager::onCertificateUnverified, 
+  //       							     this, 
+  //       							     _1, 
+  //       							     data, 
+  //       							     unverifiedCallback);
+
+
+  //       Ptr<Interest> interest = Ptr<Interest>(new Interest(sha256sig->getKeyLocator().getKeyName()));
+	
+  //       Ptr<ValidationRequest> nextStep = Ptr<ValidationRequest>(new ValidationRequest(interest, 
+  //       									       recursiveVerifiedCallback,
+  //       									       recursiveUnverifiedCallback,
+  //       									       0,
+  //       									       stepCount + 1)
+  //       							 );
+  //       return nextStep;
+  //     }
+  //   }
+
+  if(m_dskRule->satisfy(*data))
+    {
+      m_keyNameRegex->match(keyLocatorName);
+      Name keyName = m_keyNameRegex->expand();
+      _LOG_DEBUG(keyName.toUri());
+
+      if(m_trustAnchors.end() != m_trustAnchors.find(keyName))
+        if(verifySignature(*data, m_trustAnchors[keyName]))
+          verifiedCallback(data);
+        else
+          unverifiedCallback(data);
+      else
+        unverifiedCallback(data);
+
+      return NULL;	
+    }
+  _LOG_DEBUG("Unverified!");
+
+  unverifiedCallback(data);
+  return NULL;
+}
+
+// void 
+// PanelPolicyManager::onCertificateVerified(Ptr<Data> certData, 
+// 					       Ptr<Data> originalData,
+// 					       const DataCallback& verifiedCallback, 
+// 					       const UnverifiedCallback& unverifiedCallback)
+// {
+//   IdentityCertificate certificate(*certData);
+
+//   if(verifySignature(*originalData, certificate.getPublicKeyInfo()))
+//     verifiedCallback(originalData);
+//   else
+//     unverifiedCallback(originalData);
+// }
+
+// void
+// PanelPolicyManager::onCertificateUnverified(Ptr<Data> certData, 
+// 						 Ptr<Data> originalData,
+// 						 const UnverifiedCallback& unverifiedCallback)
+// { unverifiedCallback(originalData); }
+
+bool 
+PanelPolicyManager::checkSigningPolicy(const Name & dataName, const Name & certificateName)
+{
+  return m_invitationDataSigningRule->satisfy(dataName, certificateName);
+}
+
+Name 
+PanelPolicyManager::inferSigningIdentity(const Name & dataName)
+{
+  if(m_signingCertificateRegex->match(dataName))
+    return m_signingCertificateRegex->expand();
+  else
+    return Name();
+}
+
+void
+PanelPolicyManager::addTrustAnchor(const EndorseCertificate& selfEndorseCertificate)
+{ 
+  _LOG_DEBUG(selfEndorseCertificate.getPublicKeyName().toUri());
+  m_trustAnchors.insert(pair <Name, Publickey > (selfEndorseCertificate.getPublicKeyName(), selfEndorseCertificate.getPublicKeyInfo())); 
+}
diff --git a/src/panel-policy-manager.h b/src/panel-policy-manager.h
new file mode 100644
index 0000000..85fd2d9
--- /dev/null
+++ b/src/panel-policy-manager.h
@@ -0,0 +1,106 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Yingdi Yu <yingdi@cs.ucla.edu>
+ */
+
+#ifndef PANEL_POLICY_MANAGER_H
+#define PANEL_POLICY_MANAGER_H
+
+#include <ndn.cxx/security/policy/policy-manager.h>
+#include <ndn.cxx/security/policy/identity-policy-rule.h>
+#include <ndn.cxx/security/cache/certificate-cache.h>
+#include <map>
+
+#include "endorse-certificate.h"
+
+class PanelPolicyManager : public ndn::security::PolicyManager
+{
+public:
+  PanelPolicyManager(const int & stepLimit = 10,                        
+                          ndn::Ptr<ndn::security::CertificateCache> certificateCache = NULL);
+
+  ~PanelPolicyManager()
+  {}
+
+  /**
+   * @brief check if the received data packet can escape from verification
+   * @param data the received data packet
+   * @return true if the data does not need to be verified, otherwise false
+   */
+  bool 
+  skipVerifyAndTrust (const ndn::Data & data);
+
+  /**
+   * @brief check if PolicyManager has the verification rule for the received data
+   * @param data the received data packet
+   * @return true if the data must be verified, otherwise false
+   */
+  bool
+  requireVerify (const ndn::Data & data);
+
+  /**
+   * @brief check whether received data packet complies with the verification policy, and get the indication of next verification step
+   * @param data the received data packet
+   * @param stepCount the number of verification steps that have been done, used to track the verification progress
+   * @param verifiedCallback the callback function that will be called if the received data packet has been validated
+   * @param unverifiedCallback the callback function that will be called if the received data packet cannot be validated
+   * @return the indication of next verification step, NULL if there is no further step
+   */
+  ndn::Ptr<ndn::security::ValidationRequest>
+  checkVerificationPolicy(ndn::Ptr<ndn::Data> data, 
+                          const int & stepCount, 
+                          const ndn::DataCallback& verifiedCallback,
+                          const ndn::UnverifiedCallback& unverifiedCallback);
+
+    
+  /**
+   * @brief check if the signing certificate name and data name satify the signing policy 
+   * @param dataName the name of data to be signed
+   * @param certificateName the name of signing certificate
+   * @return true if the signing certificate can be used to sign the data, otherwise false
+   */
+  bool 
+  checkSigningPolicy(const ndn::Name & dataName, const ndn::Name & certificateName);
+  
+  /**
+   * @brief Infer signing identity name according to policy, if the signing identity cannot be inferred, it should return empty name
+   * @param dataName, the name of data to be signed
+   * @return the signing identity. 
+   */
+  ndn::Name 
+  inferSigningIdentity(const ndn::Name & dataName);
+
+  
+  void
+  addTrustAnchor(const EndorseCertificate& selfEndorseCertificate);
+
+// private:
+//   void 
+//   onCertificateVerified(ndn::Ptr<ndn::Data> certData, 
+//                         ndn::Ptr<ndn::Data> originalData,
+//                         const ndn::DataCallback& verifiedCallback, 
+//                         const ndn::UnverifiedCallback& unverifiedCallback);
+
+//   void
+//   onCertificateUnverified(ndn::Ptr<ndn::Data> certData, 
+//                           ndn::Ptr<ndn::Data> originalData,
+//                           const ndn::UnverifiedCallback& unverifiedCallback);
+
+private:
+  int m_stepLimit;
+  ndn::Ptr<ndn::security::CertificateCache> m_certificateCache;
+  ndn::Ptr<ndn::Regex> m_localPrefixRegex;
+  ndn::Ptr<ndn::security::IdentityPolicyRule> m_invitationDataSigningRule;
+  ndn::Ptr<ndn::security::IdentityPolicyRule> m_dskRule;
+  ndn::Ptr<ndn::Regex> m_keyNameRegex;
+  ndn::Ptr<ndn::Regex> m_signingCertificateRegex;
+  std::map<ndn::Name, ndn::security::Publickey> m_trustAnchors;
+  
+};
+
+#endif
diff --git a/src/profile-data.cpp b/src/profile-data.cpp
index f057a6d..9a8087b 100644
--- a/src/profile-data.cpp
+++ b/src/profile-data.cpp
@@ -26,11 +26,8 @@
   , m_profile(profile)
 {
   Name dataName = identity;
-  TimeInterval ti = time::NowUnixTimestamp();
-  ostringstream oss;
-  oss << ti.total_seconds();
 
-  dataName.append("PROFILE").append(oss.str());
+  dataName.append("PROFILE").appendVersion();
   setName(dataName);
   Ptr<Blob> profileBlob = profile.toDerBlob();
   setContent(Content(profileBlob->buf(), profileBlob->size()));
diff --git a/src/profileeditor.cpp b/src/profileeditor.cpp
index dd037ca..db00a6f 100644
--- a/src/profileeditor.cpp
+++ b/src/profileeditor.cpp
@@ -94,6 +94,7 @@
   m_currentIdentity = Name(inputIdentity.toUtf8().constData());
   string filter("profile_identity = '");
   filter.append(m_currentIdentity.toUri()).append("'");
+  _LOG_DEBUG("filter: " << filter);
 
   m_tableModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
   m_tableModel->setTable("SelfProfile");
@@ -103,6 +104,8 @@
   m_tableModel->setHeaderData(1, Qt::Horizontal, QObject::tr("Type"));
   m_tableModel->setHeaderData(2, Qt::Horizontal, QObject::tr("Value"));
 
+  _LOG_DEBUG("row count: " << m_tableModel->rowCount());
+
   ui->profileTable->setModel(m_tableModel);
   ui->profileTable->setColumnHidden(0, true);
   ui->profileTable->show();
diff --git a/src/startchatdialog.cpp b/src/startchatdialog.cpp
index 561096a..02d88f0 100644
--- a/src/startchatdialog.cpp
+++ b/src/startchatdialog.cpp
@@ -41,7 +41,8 @@
 {
   QString chatroom = ui->chatroomInput->text();
   QString invitee = QString::fromUtf8(m_invitee.c_str());
-  bool isIntroducer = ui->introCheckBox->isChecked();
+  // bool isIntroducer = ui->introCheckBox->isChecked();
+  bool isIntroducer = true;
   emit chatroomConfirmed(chatroom, invitee, isIntroducer);
   this->close();
 }
diff --git a/src/startchatdialog.ui b/src/startchatdialog.ui
index bfe6217..9451b51 100644
--- a/src/startchatdialog.ui
+++ b/src/startchatdialog.ui
@@ -80,6 +80,9 @@
    <property name="text">
     <string>Set invitee as introducer</string>
    </property>
+   <property name="checkable">
+    <bool>false</bool>
+   </property>
   </widget>
  </widget>
  <resources/>
diff --git a/src/treelayout.cpp b/src/treelayout.cpp
new file mode 100644
index 0000000..c1fecf3
--- /dev/null
+++ b/src/treelayout.cpp
@@ -0,0 +1,31 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#include "treelayout.h"
+
+void
+OneLevelTreeLayout::setOneLevelLayout(std::vector<Coordinate> &childNodesCo)
+{
+  if (childNodesCo.empty())
+  {
+    return;
+  }
+  double y = getLevelDistance();
+  double sd = getSiblingDistance();
+  int n = childNodesCo.size();
+  double x = - (n - 1) * sd / 2;
+  for (int i = 0; i < n; i++)
+  {
+    childNodesCo[i].x = x;
+    childNodesCo[i].y = y;
+    x += sd;
+  }
+}
diff --git a/src/treelayout.h b/src/treelayout.h
new file mode 100644
index 0000000..4942f62
--- /dev/null
+++ b/src/treelayout.h
@@ -0,0 +1,43 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013, Regents of the University of California
+ *                     Yingdi Yu
+ *
+ * BSD license, See the LICENSE file for more information
+ *
+ * Author: Zhenkai Zhu <zhenkai@cs.ucla.edu>
+ *         Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef TREELAYOUT_H
+#define TREELAYOUT_H
+#include <vector>
+
+class TreeLayout 
+{
+public:
+  struct Coordinate
+  {
+    double x;
+    double y;
+  };
+  TreeLayout(){}
+  virtual void setOneLevelLayout(std::vector<Coordinate> &childNodesCo){};
+  void setSiblingDistance(int d) {m_siblingDistance = d;}
+  void setLevelDistance(int d) {m_levelDistance = d;}
+  int getSiblingDistance() {return m_siblingDistance;}
+  int getLevelDistance() {return m_levelDistance;}
+  virtual ~TreeLayout(){}
+private:
+  int m_siblingDistance;
+  int m_levelDistance;
+};
+
+class OneLevelTreeLayout: public TreeLayout
+{
+public:
+  OneLevelTreeLayout(){}
+  virtual void setOneLevelLayout(std::vector<Coordinate> &childNodesCo);
+  virtual ~OneLevelTreeLayout(){}
+};
+#endif
diff --git a/src/trusted-contact.cpp b/src/trusted-contact.cpp
index b3271d2..7db842a 100644
--- a/src/trusted-contact.cpp
+++ b/src/trusted-contact.cpp
@@ -9,7 +9,9 @@
  */
 
 #include "trusted-contact.h"
-#include <tinyxml.h>
+#include <boost/tokenizer.hpp>
+using boost::tokenizer;
+using boost::escaped_list_separator;
 
 using namespace std;
 using namespace ndn;
@@ -19,14 +21,15 @@
 			       const string& alias)
   : ContactItem(selfEndorseCertificate, alias)
 {
-  TiXmlDocument xmlDoc;
-  xmlDoc.Parse(trustScope.c_str());
-  
-  TiXmlNode * it = xmlDoc.FirstChild();    
-  while(it != NULL)
+  tokenizer<escaped_list_separator<char> > trustScopeItems(trustScope, escaped_list_separator<char> ("\\", " \t", "'\""));
+
+  tokenizer<escaped_list_separator<char> >::iterator it = trustScopeItems.begin();
+
+  while (it != trustScopeItems.end())
     {
-      m_trustScope.push_back(Regex::fromXmlElement(dynamic_cast<TiXmlElement *>(it)));
-      it = it->NextSibling();
+      m_trustScope.push_back(Regex::fromName(Name(*it)));
+      m_trustScopeName.push_back(Name(*it));
+      it++;
     }
 }
 
@@ -45,12 +48,12 @@
 TrustedContact::getTrustScopeBlob() const
 {
   ostringstream oss;
-  TiXmlDocument * xmlDoc = new TiXmlDocument();
 
-  vector<Ptr<Regex> >::const_iterator it = m_trustScope.begin();
-  for(; it != m_trustScope.end(); it++)
-      xmlDoc->LinkEndChild((*it)->toXmlElement());
+  vector<Name>::const_iterator it = m_trustScopeName.begin();
+  if(it != m_trustScopeName.end())
+    oss << it->toUri();
+  for(; it != m_trustScopeName.end(); it++)
+    oss << " " << it->toUri();
 
-  oss << *xmlDoc;
   return Ptr<Blob>(new Blob(oss.str().c_str(), oss.str().size()));
 }
diff --git a/src/trusted-contact.h b/src/trusted-contact.h
index 9f9121c..bd2e84a 100644
--- a/src/trusted-contact.h
+++ b/src/trusted-contact.h
@@ -35,6 +35,7 @@
 
 private:
   std::vector<ndn::Ptr<ndn::Regex> > m_trustScope;
+  std::vector<ndn::Name> m_trustScopeName;
 };
 
 #endif