diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
index 0b1be3860..01875351b 100644
--- a/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
@@ -1,229 +1,279 @@
 <?php
 
 final class PhabricatorCalendarEventEditController
   extends PhabricatorCalendarController {
 
   private $id;
 
   public function willProcessRequest(array $data) {
     $this->id = idx($data, 'id');
   }
 
   public function isCreate() {
     return !$this->id;
   }
 
   public function processRequest() {
     $request = $this->getRequest();
     $user = $request->getUser();
     $user_phid = $user->getPHID();
     $error_name = true;
     $validation_exception = null;
-    $invitees = null;
 
     $start_time = id(new AphrontFormDateControl())
       ->setUser($user)
       ->setName('start')
       ->setLabel(pht('Start'))
       ->setInitialTime(AphrontFormDateControl::TIME_START_OF_DAY);
 
     $end_time = id(new AphrontFormDateControl())
       ->setUser($user)
       ->setName('end')
       ->setLabel(pht('End'))
       ->setInitialTime(AphrontFormDateControl::TIME_END_OF_DAY);
 
     if ($this->isCreate()) {
       $event = PhabricatorCalendarEvent::initializeNewCalendarEvent($user);
       $end_value = $end_time->readValueFromRequest($request);
       $start_value = $start_time->readValueFromRequest($request);
       $submit_label = pht('Create');
       $filter = 'event/create/';
       $page_title = pht('Create Event');
       $redirect = 'created';
       $subscribers = array();
-      $invitees = array(
-        $user_phid => PhabricatorCalendarEventInvitee::STATUS_ATTENDING,
-      );
+      $invitees = array($user_phid);
     } else {
       $event = id(new PhabricatorCalendarEventQuery())
         ->setViewer($user)
         ->withIDs(array($this->id))
         ->requireCapabilities(
           array(
             PhabricatorPolicyCapability::CAN_VIEW,
             PhabricatorPolicyCapability::CAN_EDIT,
           ))
         ->executeOne();
       if (!$event) {
         return new Aphront404Response();
       }
 
       $end_time->setValue($event->getDateTo());
       $start_time->setValue($event->getDateFrom());
       $submit_label = pht('Update');
       $filter       = 'event/edit/'.$event->getID().'/';
       $page_title   = pht('Update Event');
       $redirect     = 'updated';
 
       $subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID(
         $event->getPHID());
+      $invitees = array();
+      foreach ($event->getInvitees() as $invitee) {
+        if ($invitee->isUninvited()) {
+          continue;
+        } else {
+          $invitees[] = $invitee->getInviteePHID();
+        }
+      }
     }
 
     $errors = array();
     if ($request->isFormPost()) {
       $xactions = array();
       $name = $request->getStr('name');
       $type = $request->getInt('status');
       $start_value = $start_time->readValueFromRequest($request);
       $end_value = $end_time->readValueFromRequest($request);
       $description = $request->getStr('description');
       $subscribers = $request->getArr('subscribers');
+      $invitees = $request->getArr('invitees');
+      $new_invitees = $this->getNewInviteeList($invitees, $event);
+
+      if ($this->isCreate()) {
+        $status = idx($new_invitees, $user->getPHID());
+        $status_attending = PhabricatorCalendarEventInvitee::STATUS_ATTENDING;
+        if ($status) {
+          $new_invitees[$user->getPHID()] = $status_attending;
+        }
+      }
 
       if ($start_time->getError()) {
         $errors[] = pht('Invalid start time; reset to default.');
       }
       if ($end_time->getError()) {
         $errors[] = pht('Invalid end time; reset to default.');
       }
       if (!$errors) {
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorCalendarEventTransaction::TYPE_NAME)
           ->setNewValue($name);
 
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorCalendarEventTransaction::TYPE_START_DATE)
           ->setNewValue($start_value);
 
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorCalendarEventTransaction::TYPE_END_DATE)
           ->setNewValue($end_value);
 
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorCalendarEventTransaction::TYPE_STATUS)
           ->setNewValue($type);
 
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorTransactions::TYPE_SUBSCRIBERS)
           ->setNewValue(array('=' => array_fuse($subscribers)));
 
+        $xactions[] = id(new PhabricatorCalendarEventTransaction())
+          ->setTransactionType(
+            PhabricatorCalendarEventTransaction::TYPE_INVITE)
+          ->setNewValue($new_invitees);
+
         $xactions[] = id(new PhabricatorCalendarEventTransaction())
           ->setTransactionType(
             PhabricatorCalendarEventTransaction::TYPE_DESCRIPTION)
           ->setNewValue($description);
 
-        if ($invitees) {
-          $xactions[] = id(new PhabricatorCalendarEventTransaction())
-            ->setTransactionType(
-              PhabricatorCalendarEventTransaction::TYPE_INVITE)
-            ->setNewValue($invitees);
-        }
-
-
         $editor = id(new PhabricatorCalendarEventEditor())
           ->setActor($user)
           ->setContentSourceFromRequest($request)
           ->setContinueOnNoEffect(true);
 
         try {
           $xactions = $editor->applyTransactions($event, $xactions);
           $response = id(new AphrontRedirectResponse());
           return $response->setURI('/E'.$event->getID());
         } catch (PhabricatorApplicationTransactionValidationException $ex) {
           $validation_exception = $ex;
           $error_name = $ex
             ->getShortMessage(PhabricatorCalendarEventTransaction::TYPE_NAME);
         }
       }
     }
 
     $error_view = null;
     if ($errors) {
       $error_view = id(new PHUIInfoView())
         ->setTitle(pht('Status can not be set!'))
         ->setErrors($errors);
     }
 
     $name = id(new AphrontFormTextControl())
       ->setLabel(pht('Name'))
       ->setName('name')
       ->setValue($event->getName())
       ->setError($error_name);
 
     $status_select = id(new AphrontFormSelectControl())
       ->setLabel(pht('Status'))
       ->setName('status')
       ->setValue($event->getStatus())
       ->setOptions($event->getStatusOptions());
 
     $description = id(new AphrontFormTextAreaControl())
       ->setLabel(pht('Description'))
       ->setName('description')
       ->setValue($event->getDescription());
 
     $subscribers = id(new AphrontFormTokenizerControl())
       ->setLabel(pht('Subscribers'))
       ->setName('subscribers')
       ->setValue($subscribers)
       ->setUser($user)
       ->setDatasource(new PhabricatorMetaMTAMailableDatasource());
 
+    $invitees = id(new AphrontFormTokenizerControl())
+      ->setLabel(pht('Invitees'))
+      ->setName('invitees')
+      ->setValue($invitees)
+      ->setUser($user)
+      ->setDatasource(new PhabricatorMetaMTAMailableDatasource());
+
     $form = id(new AphrontFormView())
       ->setUser($user)
       ->appendChild($name)
       ->appendChild($status_select)
       ->appendChild($start_time)
       ->appendChild($end_time)
       ->appendControl($subscribers)
+      ->appendControl($invitees)
       ->appendChild($description);
 
     $submit = id(new AphrontFormSubmitControl())
       ->setValue($submit_label);
     if ($this->isCreate()) {
       $submit->addCancelButton($this->getApplicationURI());
     } else {
       $submit->addCancelButton('/E'.$event->getID());
     }
 
     $form->appendChild($submit);
 
     $form_box = id(new PHUIObjectBoxView())
       ->setHeaderText($page_title)
       ->setFormErrors($errors)
       ->setForm($form);
 
     $nav = $this->buildSideNavView($event);
     $nav->selectFilter($filter);
 
     $crumbs = $this->buildApplicationCrumbs();
 
     if (!$this->isCreate()) {
       $crumbs->addTextCrumb('E'.$event->getId(), '/E'.$event->getId());
     }
 
     $crumbs->addTextCrumb($page_title);
 
     $object_box = id(new PHUIObjectBoxView())
       ->setHeaderText($page_title)
       ->setValidationException($validation_exception)
       ->appendChild($form);
 
     $nav->appendChild(
       array(
         $crumbs,
         $object_box,
       ));
 
     return $this->buildApplicationPage(
       $nav,
       array(
         'title' => $page_title,
       ));
   }
 
+
+  public function getNewInviteeList(array $phids, $event) {
+    $invitees = $event->getInvitees();
+    $invitees = mpull($invitees, null, 'getInviteePHID');
+    $invited_status = PhabricatorCalendarEventInvitee::STATUS_INVITED;
+    $uninvited_status = PhabricatorCalendarEventInvitee::STATUS_UNINVITED;
+    $phids = array_fuse($phids);
+
+    $new = array();
+    foreach ($phids as $phid) {
+      $old_invitee = idx($invitees, $phid);
+      if ($old_invitee) {
+        $old_status = $old_invitee->getStatus();
+        if ($old_status != $uninvited_status) {
+          continue;
+        }
+      }
+      $new[$phid] = $invited_status;
+    }
+
+    foreach ($invitees as $invitee) {
+      $deleted_invitee = !idx($phids, $invitee->getInviteePHID());
+      if ($deleted_invitee) {
+        $new[$invitee->getInviteePHID()] = $uninvited_status;
+      }
+    }
+
+    return $new;
+  }
+
 }
diff --git a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
index fa7ef9cc3..e0c82edb5 100644
--- a/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
+++ b/src/applications/calendar/controller/PhabricatorCalendarEventViewController.php
@@ -1,154 +1,158 @@
 <?php
 
 final class PhabricatorCalendarEventViewController
   extends PhabricatorCalendarController {
 
   private $id;
 
   public function shouldAllowPublic() {
     return true;
   }
 
   public function willProcessRequest(array $data) {
     $this->id = $data['id'];
   }
 
   public function processRequest() {
     $request = $this->getRequest();
     $viewer = $request->getUser();
 
     $event = id(new PhabricatorCalendarEventQuery())
       ->setViewer($viewer)
       ->withIDs(array($this->id))
       ->executeOne();
     if (!$event) {
       return new Aphront404Response();
     }
 
     $title = 'E'.$event->getID();
     $page_title = $title.' '.$event->getName();
     $crumbs = $this->buildApplicationCrumbs();
     $crumbs->addTextCrumb($title, '/E'.$event->getID());
 
     $timeline = $this->buildTransactionTimeline(
       $event,
       new PhabricatorCalendarEventTransactionQuery());
 
     $header = $this->buildHeaderView($event);
     $actions = $this->buildActionView($event);
     $properties = $this->buildPropertyView($event);
 
     $properties->setActionList($actions);
     $box = id(new PHUIObjectBoxView())
       ->setHeader($header)
       ->addPropertyList($properties);
 
     return $this->buildApplicationPage(
       array(
         $crumbs,
         $box,
         $timeline,
       ),
       array(
         'title' => $page_title,
       ));
   }
 
   private function buildHeaderView(PhabricatorCalendarEvent $event) {
     $viewer = $this->getRequest()->getUser();
     $is_cancelled = $event->getIsCancelled();
     $icon = $is_cancelled ? ('fa-times') : ('fa-calendar');
     $color = $is_cancelled ? ('grey') : ('green');
     $status = $is_cancelled ? ('Cancelled') : ('Active');
 
     return id(new PHUIHeaderView())
       ->setUser($viewer)
       ->setHeader($event->getName())
       ->setStatus($icon, $color, $status)
       ->setPolicyObject($event);
   }
 
   private function buildActionView(PhabricatorCalendarEvent $event) {
     $viewer = $this->getRequest()->getUser();
     $id = $event->getID();
     $is_cancelled = $event->getIsCancelled();
 
     $actions = id(new PhabricatorActionListView())
       ->setObjectURI($this->getApplicationURI('event/'.$id.'/'))
       ->setUser($viewer)
       ->setObject($event);
 
     $can_edit = PhabricatorPolicyFilter::hasCapability(
       $viewer,
       $event,
       PhabricatorPolicyCapability::CAN_EDIT);
 
     $actions->addAction(
       id(new PhabricatorActionView())
         ->setName(pht('Edit Event'))
         ->setIcon('fa-pencil')
         ->setHref($this->getApplicationURI("event/edit/{$id}/"))
         ->setDisabled(!$can_edit)
         ->setWorkflow(!$can_edit));
 
     if ($is_cancelled) {
       $actions->addAction(
         id(new PhabricatorActionView())
           ->setName(pht('Reinstate Event'))
           ->setIcon('fa-plus')
           ->setHref($this->getApplicationURI("event/cancel/{$id}/"))
           ->setDisabled(!$can_edit)
           ->setWorkflow(true));
     } else {
       $actions->addAction(
         id(new PhabricatorActionView())
           ->setName(pht('Cancel Event'))
           ->setIcon('fa-times')
           ->setHref($this->getApplicationURI("event/cancel/{$id}/"))
           ->setDisabled(!$can_edit)
           ->setWorkflow(true));
     }
 
     return $actions;
   }
 
   private function buildPropertyView(PhabricatorCalendarEvent $event) {
     $viewer = $this->getRequest()->getUser();
 
     $properties = id(new PHUIPropertyListView())
       ->setUser($viewer)
       ->setObject($event);
 
     $properties->addProperty(
       pht('Starts'),
       phabricator_datetime($event->getDateFrom(), $viewer));
 
     $properties->addProperty(
       pht('Ends'),
       phabricator_datetime($event->getDateTo(), $viewer));
 
     $invitees = $event->getInvitees();
     $invitee_list = new PHUIStatusListView();
     foreach ($invitees as $invitee) {
+      if ($invitee->isUninvited()) {
+        continue;
+      }
       $item = new PHUIStatusItemView();
       $invitee_phid = $invitee->getInviteePHID();
       $target = $viewer->renderHandle($invitee_phid);
+      $item->setNote($invitee->getStatus());
       $item->setTarget($target);
       $invitee_list->addItem($item);
     }
 
     $properties->addProperty(
       pht('Invitees'),
       $invitee_list);
 
     $properties->invokeWillRenderEvent();
 
     $properties->addSectionHeader(
       pht('Description'),
       PHUIPropertyListView::ICON_SUMMARY);
     $properties->addTextContent($event->getDescription());
 
     return $properties;
   }
 
 }
diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
index 81bd5fd59..42dd48d8f 100644
--- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php
@@ -1,273 +1,274 @@
 <?php
 
 final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
   implements PhabricatorPolicyInterface,
   PhabricatorMarkupInterface,
   PhabricatorApplicationTransactionInterface,
   PhabricatorSubscribableInterface,
   PhabricatorTokenReceiverInterface,
   PhabricatorDestructibleInterface,
   PhabricatorMentionableInterface,
   PhabricatorFlaggableInterface {
 
   protected $name;
   protected $userPHID;
   protected $dateFrom;
   protected $dateTo;
   protected $status;
   protected $description;
   protected $isCancelled;
 
   private $invitees = self::ATTACHABLE;
 
   const STATUS_AWAY = 1;
   const STATUS_SPORADIC = 2;
 
   public static function initializeNewCalendarEvent(PhabricatorUser $actor) {
     $app = id(new PhabricatorApplicationQuery())
       ->setViewer($actor)
       ->withClasses(array('PhabricatorCalendarApplication'))
       ->executeOne();
 
     return id(new PhabricatorCalendarEvent())
       ->setUserPHID($actor->getPHID())
-      ->setIsCancelled(0);
+      ->setIsCancelled(0)
+      ->attachInvitees(array());
   }
 
   private static $statusTexts = array(
     self::STATUS_AWAY => 'away',
     self::STATUS_SPORADIC => 'sporadic',
   );
 
   public function setTextStatus($status) {
     $statuses = array_flip(self::$statusTexts);
     return $this->setStatus($statuses[$status]);
   }
 
   public function getTextStatus() {
     return self::$statusTexts[$this->status];
   }
 
   public function getStatusOptions() {
     return array(
       self::STATUS_AWAY     => pht('Away'),
       self::STATUS_SPORADIC => pht('Sporadic'),
     );
   }
 
   public function getHumanStatus() {
     $options = $this->getStatusOptions();
     return $options[$this->status];
   }
 
   protected function getConfiguration() {
     return array(
       self::CONFIG_AUX_PHID => true,
       self::CONFIG_COLUMN_SCHEMA => array(
         'name' => 'text',
         'dateFrom' => 'epoch',
         'dateTo' => 'epoch',
         'status' => 'uint32',
         'description' => 'text',
         'isCancelled' => 'bool',
       ),
       self::CONFIG_KEY_SCHEMA => array(
         'userPHID_dateFrom' => array(
           'columns' => array('userPHID', 'dateTo'),
         ),
       ),
     ) + parent::getConfiguration();
   }
 
   public function generatePHID() {
     return PhabricatorPHID::generateNewPHID(
       PhabricatorCalendarEventPHIDType::TYPECONST);
   }
 
   public function getMonogram() {
     return 'E'.$this->getID();
   }
 
   public function getTerseSummary(PhabricatorUser $viewer) {
     $until = phabricator_date($this->dateTo, $viewer);
     if ($this->status == PhabricatorCalendarEvent::STATUS_SPORADIC) {
       return pht('Sporadic until %s', $until);
     } else {
       return pht('Away until %s', $until);
     }
   }
 
   public static function getNameForStatus($value) {
     switch ($value) {
       case self::STATUS_AWAY:
         return pht('Away');
       case self::STATUS_SPORADIC:
         return pht('Sporadic');
       default:
         return pht('Unknown');
     }
   }
 
   public function loadCurrentStatuses($user_phids) {
     if (!$user_phids) {
       return array();
     }
 
     $statuses = $this->loadAllWhere(
       'userPHID IN (%Ls) AND UNIX_TIMESTAMP() BETWEEN dateFrom AND dateTo',
       $user_phids);
 
     return mpull($statuses, null, 'getUserPHID');
   }
 
   public function getInvitees() {
     return $this->assertAttached($this->invitees);
   }
 
   public function attachInvitees(array $invitees) {
     $this->invitees = $invitees;
     return $this;
   }
 
   /**
    * Validates data and throws exceptions for non-sensical status
    * windows
    */
   public function save() {
 
     if ($this->getDateTo() <= $this->getDateFrom()) {
       throw new PhabricatorCalendarEventInvalidEpochException();
     }
 
     return parent::save();
   }
 
 /* -(  Markup Interface  )--------------------------------------------------- */
 
 
   /**
    * @task markup
    */
   public function getMarkupFieldKey($field) {
     $hash = PhabricatorHash::digest($this->getMarkupText($field));
     $id = $this->getID();
     return "calendar:T{$id}:{$field}:{$hash}";
   }
 
 
   /**
    * @task markup
    */
   public function getMarkupText($field) {
     return $this->getDescription();
   }
 
 
   /**
    * @task markup
    */
   public function newMarkupEngine($field) {
     return PhabricatorMarkupEngine::newCalendarMarkupEngine();
   }
 
 
   /**
    * @task markup
    */
   public function didMarkupText(
     $field,
     $output,
     PhutilMarkupEngine $engine) {
     return $output;
   }
 
 
   /**
    * @task markup
    */
   public function shouldUseMarkupCache($field) {
     return (bool)$this->getID();
   }
 
 /* -(  PhabricatorPolicyInterface  )----------------------------------------- */
 
 
   public function getCapabilities() {
     return array(
       PhabricatorPolicyCapability::CAN_VIEW,
       PhabricatorPolicyCapability::CAN_EDIT,
     );
   }
 
   public function getPolicy($capability) {
     switch ($capability) {
       case PhabricatorPolicyCapability::CAN_VIEW:
         return PhabricatorPolicies::getMostOpenPolicy();
       case PhabricatorPolicyCapability::CAN_EDIT:
         return $this->getUserPHID();
     }
   }
 
   public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
     return false;
   }
 
   public function describeAutomaticCapability($capability) {
     return null;
   }
 
 /* -(  PhabricatorApplicationTransactionInterface  )------------------------- */
 
 
   public function getApplicationTransactionEditor() {
     return new PhabricatorCalendarEventEditor();
   }
 
   public function getApplicationTransactionObject() {
     return $this;
   }
 
   public function getApplicationTransactionTemplate() {
     return new PhabricatorCalendarEventTransaction();
   }
 
   public function willRenderTimeline(
     PhabricatorApplicationTransactionView $timeline,
     AphrontRequest $request) {
 
     return $timeline;
   }
 
 /* -(  PhabricatorSubscribableInterface  )----------------------------------- */
 
 
   public function isAutomaticallySubscribed($phid) {
     return ($phid == $this->getUserPHID());
   }
 
   public function shouldShowSubscribersProperty() {
     return true;
   }
 
   public function shouldAllowSubscription($phid) {
     return true;
   }
 
 /* -(  PhabricatorTokenReceiverInterface  )---------------------------------- */
 
 
   public function getUsersToNotifyOfTokenGiven() {
     return array($this->getUserPHID());
   }
 
 /* -(  PhabricatorDestructibleInterface  )----------------------------------- */
 
 
   public function destroyObjectPermanently(
     PhabricatorDestructionEngine $engine) {
 
     $this->openTransaction();
     $this->delete();
     $this->saveTransaction();
   }
 }
diff --git a/src/applications/calendar/storage/PhabricatorCalendarEventInvitee.php b/src/applications/calendar/storage/PhabricatorCalendarEventInvitee.php
index 8b7f9a063..9701a782e 100644
--- a/src/applications/calendar/storage/PhabricatorCalendarEventInvitee.php
+++ b/src/applications/calendar/storage/PhabricatorCalendarEventInvitee.php
@@ -1,64 +1,72 @@
 <?php
 
 final class PhabricatorCalendarEventInvitee extends PhabricatorCalendarDAO
   implements PhabricatorPolicyInterface {
 
   protected $eventPHID;
   protected $inviteePHID;
   protected $inviterPHID;
   protected $status;
 
   const STATUS_INVITED = 'invited';
   const STATUS_ATTENDING = 'attending';
   const STATUS_DECLINED = 'declined';
   const STATUS_UNINVITED = 'uninvited';
 
   public static function initializeNewCalendarEventInvitee(
     PhabricatorUser $actor, $event) {
     return id(new PhabricatorCalendarEventInvitee())
       ->setInviterPHID($actor->getPHID())
       ->setStatus(self::STATUS_INVITED)
       ->setEventPHID($event->getPHID());
   }
 
   protected function getConfiguration() {
     return array(
       self::CONFIG_COLUMN_SCHEMA => array(
         'status' => 'text64',
       ),
       self::CONFIG_KEY_SCHEMA => array(
         'key_event' => array(
           'columns' => array('eventPHID', 'inviteePHID'),
           'unique' => true,
         ),
         'key_invitee' => array(
           'columns' => array('inviteePHID'),
         ),
       ),
     ) + parent::getConfiguration();
   }
 
+  public function isUninvited() {
+    if ($this->getStatus() == self::STATUS_UNINVITED) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
 /* -(  PhabricatorPolicyInterface  )----------------------------------------- */
 
 
   public function getCapabilities() {
     return array(
       PhabricatorPolicyCapability::CAN_VIEW,
     );
   }
 
   public function getPolicy($capability) {
     switch ($capability) {
       case PhabricatorPolicyCapability::CAN_VIEW:
         return PhabricatorPolicies::getMostOpenPolicy();
     }
   }
 
   public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
     return false;
   }
 
   public function describeAutomaticCapability($capability) {
     return null;
   }
 }