       delete @modal
 
 
-  handleBroadcastMessage: (data) ->
-
-    {origin, type} = data
-
-    if origin is KD.nick()
-      switch type
-        when 'ParticipantWantsToLeave'
-          return @quit()
-        when 'ParticipantKicked'
-          return @handleParticipantKicked data.target
-        else return
-
-    switch type
-
-      when 'SessionEnded'
-
-        @showSessionEndedModal()
-
-      when 'ParticipantWantsToLeave'
-
-        @handleParticipantKicked data.origin
-
-      when 'ParticipantKicked'
-
-        return  unless data.origin is @collaborationHost
-
-        if data.target is KD.nick()
-          @removeMachineNode()
-          @showKickedModal()
-        else
-          @handleParticipantKicked data.target
-
-
-  unshareMachineAndKlient: (username, fetchUser = no) ->
-
-    if fetchUser
-      return KD.remote.cacheable username, (err, accounts) =>
-
-        return KD.showError err  if err
-
-        @setMachineUser accounts, no
-
-
-    @listChatParticipants (accounts) =>
-
-      for account in accounts when account.profile.nickname is username
-        target = account
-
-      @setMachineUser [target], no  if target
-
-
-  showKickedModal: ->
-    options        =
-      title        : 'Your session has been closed'
-      content      : "You have been removed from the session by @#{@collaborationHost}."
-      blocking     : yes
-      buttons      :
-        ok         :
-          title    : 'OK'
-          callback : => @modal.destroy()
-
-    @showModal options
-    @quit()
-
-
   quit: ->
 
-    KD.utils.killRepeat @autoSaveInterval
-    KD.utils.killRepeat @pingInterval
-    @rtm?.dispose()
-    @rtm = null
+    @cleanupCollaboration()
 
     KD.singletons.router.handleRoute '/IDE'
     KD.singletons.appManager.quit this
-
-
-  showSessionEndedModal: (content) ->
-
-    content ?= "This session is ended by @#{@collaborationHost} You won't be able to access it anymore."
-
-    options        =
-      title        : 'Session ended'
-      content      : content
-      blocking     : yes
-      buttons      :
-        quit       :
-          title    : 'LEAVE'
-          callback : => @modal.destroy()
-
-    @showModal options
-    @removeMachineNode()
-    @quit()
-
-
-  handleParticipantLeaveAction: ->
-
-    options   =
-      title   : 'Are you sure?'
-      content : "If you leave this session you won't be able to return back."
-
-    @showModal options, =>
-      @broadcastMessages.push origin: KD.nick(), type: 'ParticipantWantsToLeave'
-      @stopChatSession()
-      @modal.destroy()
-
-      options = channelId: @socialChannel.getId()
-      KD.singletons.socialapi.channel.leave options, (err) =>
-        return KD.showError err  if err
-        @setMachineUser [KD.whoami()], no, => @quit()
-        # remove the leaving participant's info from the collaborative doc
-        @removeParticipant KD.nick()
-
-
-  removeMachineNode: ->
-
-    KD.singletons.mainView.activitySidebar.removeMachineNode @mountedMachine
-
-
-  handleParticipantKicked: (username) ->
-
-    @chat.emit 'ParticipantLeft', username
-    @statusBar.removeParticipantAvatar username
-    @removeParticipantCursorWidget username
-    # remove participant's all data persisted in realtime appInfo
-    @removeParticipant username
-
-  getCollaborationData: (callback = noop) =>
-
-    collaborationData =
-      watchMap        : @myWatchMap?.values()
-      amIHost         : @amIHost
-
-    callback collaborationData
-
-
-  kickParticipant: (account) ->
-
-    return  unless @amIHost
-
-    options      =
-      channelId  : @socialChannel.id
-      accountIds : [ account.socialApiId ]
-
-    @setMachineUser [account], no, =>
-
-      KD.singletons.socialapi.channel.kickParticipants options, (err, result) =>
-
-        return KD.showError err  if err
-
-        targetUser = account.profile.nickname
-        message    =
-          type     : 'ParticipantKicked'
-          origin   : KD.nick()
-          target   : targetUser
-
-        @broadcastMessages.push message
-        @handleParticipantKicked targetUser
-
-
-  getCollaborationHost: -> if @amIHost then KD.nick() else @collaborationHost
-
-
-  isHostOnline: ->
-
-    host = @getCollaborationHost()
-
-    filtered = @participants
-      .asArray()
-      .filter (its) -> its.nickname is host
-
-    return no  unless filtered.length
-
-    { sessionId } = filtered.first
-
-    return no  unless sessionId
-
-    final = @rtm
-      .getCollaborators()
-      .filter (its) -> its.sessionId is sessionId
-
-    return final.length > 0
-
-
-  listenPings: ->
-
-    pingInterval = 1000 * 5
-    pongInterval = 1000 * 15
-
-    @pingInterval = if @amIHost
-    then KD.utils.repeat pingInterval, @bound 'sendPing'
-    else KD.utils.repeat pongInterval, @bound 'checkPing'
-
-
-  sendPing: -> @pingTime.setText Date.now().toString()
-
-
-  forceQuitCollaboration: ->
-
-    { Collaboration } = KD.remote.api
-    Collaboration.stop @rtmFileId, @workspaceData, (err) =>
-
-      return warn err  if err
-
-      KD.utils.killRepeat @pingInterval
-
-      @stopCollaborationSession =>
-        @quit()
-
-        new KDNotificationView
-          title    : "@#{@collaborationHost} has left the session."
-          duration : 3000
-
-
-  checkPing: do ->
-
-    lastCheckedAt = null
-    lastPing      = null
-    errorTryCount = 3
-    diffInterval  = KD.config.collaboration.timeout
-
-    return ->
-
-      ping = @pingTime.getText()
-
-      # kill session if `errorTryCount`
-      # limit is passed.
-      if errorTryCount <= 0
-        @forceQuitCollaboration()
-      # update the lastChecked at if the last ping
-      # is still the same, decrease the error try count.
-      else if ping is lastPing and errorTryCount > 0
-        errorTryCount -= 1
-        lastCheckedAt = Date.now()
-        return
-      # this is the happy path.
-      else if lastPing - ping < diffInterval
-        lastCheckedAt = Date.now()
-        lastPing      = ping
-        errorTryCount = 3
-        return
 
 
   removeParticipantCursorWidget: (targetUser) ->

    tabView.removePane paneView


  loadCollaborationFile: (fileId) ->

    return unless fileId

    @rtmFileId = fileId

    @rtm.getFile fileId

    @rtm.once 'FileLoaded', (doc) =>
      nickname = KD.nick()
      hostName = @collaborationHost

      @rtm.setRealtimeDoc doc

      @setCollaborativeReferences()

      if @amIHost
        @getView().setClass 'host'
      #   @changes.clear()
      #   @broadcastMessages.clear()

      isInList = no

      @participants.asArray().forEach (participant) =>
        isInList = yes  if participant.nickname is nickname

      if not isInList
        @addParticipant KD.whoami(), no

      @rtm.on 'CollaboratorJoined', (doc, participant) =>
        @handleParticipantAction 'join', participant

      @rtm.on 'CollaboratorLeft', (doc, participant) =>
        @handleParticipantAction 'left', participant

      @registerCollaborationSessionId()
      @bindRealtimeEvents()
      @listenPings()
      @rtm.isReady = yes
      @emit 'RTMIsReady'
      @resurrectSnapshot()  unless @amIHost

      unless @myWatchMap.values().length
        @listChatParticipants (accounts) =>
          accounts.forEach (account) =>
            {nickname} = account.profile
            @myWatchMap.set nickname, nickname

      if not @amIHost and @myWatchMap.values().indexOf(hostName) > -1
        hostSnapshot = @rtm.getFromModel "#{hostName}Snapshot"

        for key, change of hostSnapshot.values()
          @createPaneFromChange change

      @finderPane.on 'ChangeHappened', @bound 'syncChange'

      unless @amIHost
        @makeReadOnly()  if @permissions.get(nickname) is 'read'


  setCollaborativeReferences: ->

    nickname           = KD.nick()
    myWatchMapName     = "#{nickname}WatchMap"
    mySnapshotName     = "#{nickname}Snapshot"
    defaultPermission  = default: 'edit'

    @participants      = @rtm.getFromModel 'participants'
    @changes           = @rtm.getFromModel 'changes'
    @permissions       = @rtm.getFromModel 'permissions'
    @broadcastMessages = @rtm.getFromModel 'broadcastMessages'
    @pingTime          = @rtm.getFromModel 'pingTime'
    @myWatchMap        = @rtm.getFromModel myWatchMapName
    @mySnapshot        = @rtm.getFromModel mySnapshotName

    @participants      or= @rtm.create 'list',   'participants', []
    @changes           or= @rtm.create 'list',   'changes', []
    @permissions       or= @rtm.create 'map',    'permissions', defaultPermission
    @broadcastMessages or= @rtm.create 'list',   'broadcastMessages', []
    @pingTime          or= @rtm.create 'string', 'pingTime'
    @myWatchMap        or= @rtm.create 'map',    myWatchMapName, {}

    initialSnapshot      = if @amIHost then @getWorkspaceSnapshot() else {}
    @mySnapshot        or= @rtm.create 'map',    mySnapshotName, initialSnapshot


  registerCollaborationSessionId: ->

    collaborators = @rtm.getCollaborators()

    for collaborator in collaborators when collaborator.isMe
      participants = @participants.asArray()

      for user, index in participants when user.nickname is KD.nick()
        newData = KD.utils.dict()

        newData[key] = value  for key, value of user

        newData.sessionId = collaborator.sessionId
        @participants.remove index
        @participants.insert index, newData


  addParticipant: (account) ->

    {hash, nickname} = account.profile
    @participants.push { nickname, hash }


  getWorkspaceSnapshot: ->

    panes = {}

    return panes


  changeActiveTabView: (paneType) ->

    if paneType is 'terminal'
