diff --git a/openbis_all/source/ruby/dashboard/jira b/openbis_all/source/ruby/dashboard/jira
index dc5897b149a4e4bc221c17dd502aa730b2c4f4e9..6310000f57505097b33b8df6d1003547b2b68b9e 100755
--- a/openbis_all/source/ruby/dashboard/jira
+++ b/openbis_all/source/ruby/dashboard/jira
@@ -85,6 +85,12 @@ class Issue
     return self.fields["timetracking"]["remainingEstimateSeconds"] ? self.fields["timetracking"]["remainingEstimateSeconds"] : 0
   end
   
+  def time_spent
+    # The result is preformatted by JIRA
+    return "" if self.fields["timetracking"].nil?
+    return self.fields["timetracking"]["timeSpent"] ? self.fields["timetracking"]["timeSpent"] : ""
+  end
+  
   def status
     return self.fields["status"] ? self.fields["status"]["name"] : nil
   end
@@ -97,6 +103,10 @@ class Issue
     return self.fields["summary"]
   end
   
+  def assignee
+    return self.fields["assignee"] ? self.fields["assignee"]["name"] : nil
+  end
+  
   def fix_version
     fix_versions = self.fields["fixVersions"]
     return "Unscheduled" if fix_versions.nil?
@@ -104,6 +114,12 @@ class Issue
     return fix_versions[0]["name"]
   end
   
+  def fix_versions
+    fix_versions = self.fields["fixVersions"]
+    return "Unscheduled" if fix_versions.nil?
+    return fix_versions.collect { | each | each["name"] }.join(" ")
+  end
+  
   def transitions
     @issue["transitions"]
   end
@@ -199,6 +215,15 @@ module JiraHelpers
     return `#{update_cmd}`
   end
   
+  def JiraHelpers.add_fix_version(issue, fixversion)
+    fix_versions = issue.fields["fixVersions"]
+    fix_versions = [] unless fix_versions
+    fix_versions.push({"name" => fixversion })
+    update_data = { "fields" => { "fixVersions" => fix_versions } }
+    update_cmd = "curl -s --cookie #{$jira_cookie_path} -H 'Content-Type: application/json' '#{$jira_api_url}/issue/#{issue.key}' -X PUT -d '#{JSON.generate(update_data)}'"
+    return `#{update_cmd}`
+  end
+  
   def JiraHelpers.transition(bis_key, trans_id)
     transition_data = {
       "transition" => { "id" => "#{trans_id}"}
@@ -246,6 +271,14 @@ module JiraHelpers
   end
 end
 
+#
+# A module that simplifies interacting with git
+module GitHelpers
+  def GitHelpers.list_commits(key)
+    return `git cisd log --grep="#{key}" | sed -n '/git-svn-id/p' | sed -E 's/.*trunk@([0-9]+).*/r\\1/'`
+  end
+end
+
 #
 # A module that implements some helpful operations
 #
@@ -324,6 +357,8 @@ DESCRIPTION
     A simple api for jira. Login as jira user and get some info. The available commands are:    
 
 	login		asks for login and password to jira and stores a session cookie
+	
+	session		check if the session cookie is still valid
 
 	sprint S133	get the information about the given sprint
 
@@ -340,7 +375,7 @@ DESCRIPTION
 	rank SP-121 SP-122
 				ranks SP-121 after SP-122
 				
-	kanban 133 	returns a Kanban list of the issues in S133
+	kanban1304 133 	returns a Kanban list of the issues in S133 designated for the 1304 release
 	
 	create 133 	create issues for all BIS issues designated as next sprint	
 	create 133 BIS-111
@@ -354,6 +389,11 @@ DESCRIPTION
 				
 	move 133 	Set the fix version to 133 for all issues that are connected to the BIS issues
 	move 133 SP-452	Set the fix version of SP-452 to 133
+	
+	fix-add BIS-111 13.04.1 	Add the fix version of 13.04.1 to the BIS-111
+	
+	port1304 155 	returns a list of issues that need to be ported to the release branch
+	port1304 155 commit	returns a list of commits that need to be ported to the release branch	
   eos
   end
 end
@@ -649,9 +689,157 @@ class ListSprint < LoggedInCommand
 end
 
 #
-# Lists the issues in the kanban cycle
+# Lists the issues in the kanban cycle by combining information from the BIS project and SP project
+#
+class ListKanban1304 < LoggedInCommand
+  def initialize
+    super
+    @sprintNumber = InputHelpers.sprint_name(ARGV[1])
+    @restrict_to_release = true
+  end
+  
+  def description
+    return "kanban1304 #{@sprintNumber}"
+  end
+  
+  
+  def run_logged_in
+    sp_query = "project=SP AND fixVersion = #{@sprintNumber} ORDER BY \"Global Rank\" ASC" 
+    sp_issues = JiraHelpers.search_full(sp_query, @silent)
+    init_sp_issue_dict(sp_issues)
+    
+    bis_query= "project=BIS AND status not in (Resolved, Closed) OR (status in (Resolved, Closed) AND fixVersion = #{@sprintNumber}) ORDER BY \"Global Rank\" ASC"
+    bis_query= "project=BIS AND labels in (\"12.xx_REL\", \"13.04.X\") AND status not in (Resolved, Closed) OR (status in (Resolved, Closed) AND fixVersion = #{@sprintNumber}) ORDER BY \"Global Rank\" ASC" if @restrict_to_release
+    bis_issues = JiraHelpers.search_full(bis_query, @silent)
+    enrich_sp_issue_dict(JiraHelpers.retrieve_implementors(bis_issues, @silent))
+    
+    print_issues_table("BIS", bis_issues)
+    print_unseen_sp_issues_table(sp_issues)
+    
+    puts ("=" * 12)
+
+    # Nothing to show
+    issue_count = bis_issues.length
+    return "#{issue_count} issues"
+  end
+  
+  def init_sp_issue_dict(sp_issues)
+    @sp_issue_dict = {}
+    sp_issues.each do | issue |
+      key = issue.key
+      @sp_issue_dict[key] = issue
+    end
+    @seen_sp_issues = [].to_set
+  end
+  
+  #
+  # Take those issues that are not yet resolved / closed and add them to the sp issues dict
+  #
+  def enrich_sp_issue_dict(implementors)
+    implementors.each do | issue |
+      sp = issue.key
+      next if @sp_issue_dict[sp]
+      
+      status = issue.status
+      @sp_issue_dict[sp] = issue unless issue.resolved_or_closed?
+    end 
+  end
+  
+  def print_unseen_sp_issues_table(full_issues)
+    unseen_issues = full_issues.select do | issue |
+      sp = issue.key
+      !@seen_sp_issues.include?(sp)
+    end
+    
+    return if unseen_issues.length < 1
+    
+    puts ("=" * 12)
+    puts "SP Missed"
+    puts ("-" * 12)
+    header = "%12s\t%12s\t%6s\t%8s\t%8s\t%8s\t%s" % ["Key", "SP", "Time", "Devel", "Tester", "Status", "Summary"]
+    puts header
+    subtotal = 0.0
+    unseen_issues.each do | issue |
+      sp = issue.key
+      
+      key = "----"
+      key = issue.implements.key unless issue.implements.nil?
+      time_spent = issue.time_spent
+      assignee = issue.assignee
+      tester = issue.tester
+      summary = issue.summary
+      status = issue.status
+      # Tasks that are resolved can be considered to have 0 time remaining
+      status = issue.status
+      row = "%12s\t%12s\t%6s\t%8s\t%8s\t%8s\t%s" % [key, sp, time_spent, assignee, tester, status, summary]
+      puts row
+    end
+  end
+  
+  def print_issues_table(title, full_issues)
+    return if full_issues.length < 1
+    
+    puts ("=" * 12)
+    puts title
+    puts ("-" * 12)
+    header = "%12s\t%12s\t%6s\t%8s\t%8s\t%8s\t%s" % ["Key", "SP", "Time", "Devel", "Tester", "Status", "Summary"]
+    puts header
+    subtotal = 0.0
+    full_issues.each do | issue |
+      key = issue.key
+      summary = issue.summary
+      parent = issue.fields["parent"]
+      parent = parent["key"] unless parent.nil?
+      summary = "#{parent} / #{summary}" unless parent.nil?
+            
+      implementedby = []
+      issue.implemented_by.each do | sp_issue |
+        sp = sp_issue.key
+        # We are only interested in links to issues in the specified sprint
+        implementedby << sp if @sp_issue_dict[sp]
+      end
+      
+      if implementedby.length < 1
+        row = "%12s\t%12s\t%6s\t%8s\t%8s\t%8s\t%s" % [key, "", "", "", "", "", "[Unscheduled] #{summary}"]
+        puts row
+        next
+      end
+      
+      implementedby.each_with_index do | sp, index |
+        # print one row for each implemented by
+        spissue = @sp_issue_dict[sp]
+        next if spissue.nil?
+        next if @seen_sp_issues.include?(sp)
+        
+        spfields = spissue.fields
+        time_spent = spissue.time_spent
+        assignee = spissue.assignee
+        tester = spissue.tester
+
+        # Tasks that are resolved can be considered to have 0 time remaining
+        fix_version = spissue.fix_version
+        issue_in_different_sprint = fix_version != @sprintNumber
+        status = spissue.status
+        if index < 1 
+          issue_summary = summary
+          issue_summary =  "[#{fix_version}] #{issue_summary}" if issue_in_different_sprint
+          row = "%12s\t%12s\t%6s\t%8s\t%8s\t%8s\t%s" % [key, sp, time_spent, assignee, tester, status, issue_summary]
+        else
+          issue_summary = "\""
+          issue_summary =  "[#{fix_version}] #{issue_summary}" if issue_in_different_sprint
+          row = "%12s\t%12s\t%6s\t%8s\t%8s\t%8s\t%s" % ["\"", sp, time_spent, assignee, tester, status, issue_summary]
+        end
+        puts row
+        @seen_sp_issues.add(sp)
+      end
+    end
+  end
+end
+
+#
+# Lists the issues in the kanban cycle by referring only to the BIS project
 #
-class ListKanban < LoggedInCommand
+class ListKanbanOld < LoggedInCommand
   def initialize
     super
     @sprintNumber = InputHelpers.sprint_name(ARGV[1])
@@ -719,9 +907,14 @@ class PlanSprint < LoggedInCommand
     swe_issues = JiraHelpers.search_full(swe_query, @silent)
     enrich_sp_issue_dict(JiraHelpers.retrieve_implementors(swe_issues, @silent))
     
+    ysc_query= "project = YSC AND status not in (Resolved, Closed) AND \"Next Sprint\" = YES ORDER BY \"Global Rank\" ASC"
+    ysc_issues = JiraHelpers.search_full(ysc_query, @silent)
+    enrich_sp_issue_dict(JiraHelpers.retrieve_implementors(ysc_issues, @silent))    
+    
     print_issues_table("BIS", bis_issues)
     print_issues_table("CCS", ccs_issues)    
-    print_issues_table("SWE", swe_issues)    
+    print_issues_table("SWE", swe_issues)
+    print_issues_table("YSC", ysc_issues)    
     print_unseen_sp_issues_table(sp_issues)
     
     puts ("=" * 12)
@@ -780,6 +973,8 @@ class PlanSprint < LoggedInCommand
   end
   
   def print_issues_table(title, full_issues)
+    return if full_issues.length < 1
+    
     puts ("=" * 12)
     puts title
     puts ("-" * 12)
@@ -834,7 +1029,7 @@ class PlanSprint < LoggedInCommand
       end
     end
     @total = @total + subtotal
-  end  
+  end
 end
 
 #
@@ -1190,7 +1385,7 @@ class FinishSprint < LoggedInCommand
       print " Already Resolved"      
     end
     
-    JiraHelpers.set_fix_version(issue.key, @sprintNumber)
+    JiraHelpers.add_fix_version(issue, @sprintNumber)
     print ", Fix version #{@sprintNumber}"
     
   end
@@ -1336,6 +1531,225 @@ class MoveSprint < LoggedInCommand
   end
 end
 
+#
+#  Add a fix version to an issue
+#
+class FixVersionAdd < LoggedInCommand
+  def initialize
+    super
+    @issue_key = ARGV[1]
+    @fix_version = ARGV[2]
+  end
+  
+  def description
+    return "fix-add #{@issue_key} #{@fix_version}"
+  end
+  
+  
+  def run_logged_in
+    issue = JiraHelpers.issue(@issue_key)
+    return "fix [issue key] [fix version]" unless issue
+    return "#{issue.key} fix versions: #{issue.fix_versions}" unless @fix_version
+    ans = JiraHelpers.add_fix_version(issue, @fix_version)
+    puts ans
+    issue = JiraHelpers.issue(@issue_key)
+    return "#{issue.key} fix versions: #{issue.fix_versions}"
+  end
+end
+
+#
+# Lists the issues in the sprint that need to be ported to the release branch
+#
+class ListPort1304 < LoggedInCommand
+  def initialize
+    super
+    @sprintNumber = InputHelpers.sprint_name(ARGV[1])
+  end
+  
+  def description
+    return "port1304 #{@sprintNumber}"
+  end
+  
+  
+  def run_logged_in
+    sp_query = "project=SP AND fixVersion = #{@sprintNumber} ORDER BY \"Global Rank\" ASC" 
+    sp_issues = JiraHelpers.search_full(sp_query, @silent)
+    init_sp_issue_dict(sp_issues)
+    
+    bis_query= "project=BIS AND fixVersion = #{@sprintNumber} AND labels in (\"12.xx_REL\", \"13.04.X\") ORDER BY \"Global Rank\" ASC"
+    bis_issues = JiraHelpers.search_full(bis_query, @silent)
+    enrich_sp_issue_dict(JiraHelpers.retrieve_implementors(bis_issues, @silent))
+    
+    self.print_issues_table("BIS", bis_issues)
+    self.print_unseen_sp_issues_table(sp_issues)
+   return "Invoke to get commits: port1304 #{@sprintNumber} commits"       
+  end
+  
+  
+  def init_sp_issue_dict(sp_issues)
+    @sp_issue_dict = {}
+    sp_issues.each do | issue |
+      key = issue.key
+      @sp_issue_dict[key] = issue
+    end
+    @seen_sp_issues = [].to_set
+  end
+  
+  #
+  # Take those issues that are not yet resolved / closed and add them to the sp issues dict
+  #
+  def enrich_sp_issue_dict(implementors)
+    implementors.each do | issue |
+      sp = issue.key
+      next if @sp_issue_dict[sp]
+      
+      status = issue.status
+      @sp_issue_dict[sp] = issue unless issue.resolved_or_closed?
+    end 
+  end  
+  
+  def print_issues_table_old(full_issues)
+    header = "%8s\t%12s\t%s" % ["Key", "Status", "Commits"]
+    puts header
+    time_remaining = 0.0
+    full_issues.each do | issue |
+      key = issue.key
+      status = issue.status
+      commits = ""
+      row = "%8s\t%12s\t%s" % [key, status, commits]
+      puts row
+      
+    end
+    print " ", ("-" * 27), "\n"
+    print "#{full_issues.length} issues", "\n"
+  end
+  
+  def print_issues_table(title, full_issues)
+    return if full_issues.length < 1
+    
+    puts ("=" * 12)
+    puts title
+    puts ("-" * 12)
+    header = "%12s\t%12s\t%6s\t%s" % ["Key", "SP", "Port?", "Summary"]
+    puts header
+    full_issues.each do | issue |
+      key = issue.key
+      summary = issue.summary
+      parent = issue.fields["parent"]
+      parent = parent["key"] unless parent.nil?
+      summary = "#{parent} / #{summary}" unless parent.nil?
+            
+      implementedby = []
+      issue.implemented_by.each do | sp_issue |
+        sp = sp_issue.key
+        # We are only interested in links to issues in the specified sprint
+        implementedby << sp if @sp_issue_dict[sp]
+      end
+      
+      if implementedby.length < 1
+        row = "%12s\t%12s\t%6s\t%s" % [key, "----", "NO", summary]
+        puts row
+        next
+      end
+      
+      implementedby.each_with_index do | sp, index |
+        # print one row for each implemented by
+        spissue = @sp_issue_dict[sp]
+        next if spissue.nil?
+        next if @seen_sp_issues.include?(sp)
+        
+        spfields = spissue.fields
+        time = spissue.time
+
+        # Tasks that are resolved can be considered to have 0 time remaining
+        fix_version = spissue.fix_version
+        issue_in_different_sprint = fix_version != @sprintNumber
+        status = spissue.status
+        if index < 1 
+          issue_summary = summary
+          issue_summary =  "[#{fix_version}] #{issue_summary}" if issue_in_different_sprint
+          row = "%12s\t%12s\t%6s\t%s" % [key, sp, "YES", issue_summary]
+        else
+          issue_summary = "\""
+          issue_summary =  "[#{fix_version}] #{issue_summary}" if issue_in_different_sprint
+          row = "%12s\t%12s\t%6s\t%s" % ["\"", sp, "YES", issue_summary]
+        end
+        puts row
+        @seen_sp_issues.add(sp)
+      end
+    end
+  end
+  
+  def print_unseen_sp_issues_table(full_issues)
+    puts ("=" * 12)
+    puts "Not Ported"
+    puts ("-" * 12)
+    header = "%12s\t%12s\t%6s\t%s" % ["Key", "SP", "Port?", "Summary"]
+    puts header
+    full_issues.each do | issue |
+      sp = issue.key
+      next if @seen_sp_issues.include?(sp)
+      
+      key = "----"
+      key = issue.implements.key unless issue.implements.nil?
+      time = issue.time
+      summary = issue.summary
+      # Tasks that are resolved can be considered to have 0 time remaining
+      status = issue.status
+      row = "%12s\t%12s\t%6s\t%s" % [key, sp, "NO", summary]
+      puts row
+    end
+  end  
+
+end
+
+#
+# Lists the commits in the sprint that need to be ported to the stage branch
+#
+class ListPortCommits1304 < LoggedInCommand
+  def initialize
+    super
+    @sprintNumber = InputHelpers.sprint_name(ARGV[1])
+  end
+  
+  def description
+    return "port1304 #{@sprintNumber}"
+  end
+  
+  
+  def run_logged_in
+    query = "project=BIS AND fixVersion = #{@sprintNumber} AND labels in (\"12.xx_REL\", \"13.04.X\") ORDER BY \"Global Rank\" ASC" 
+    full_issues = JiraHelpers.search_full(query, @silent)
+    self.print_issues_table(full_issues)
+    # Nothing to show
+    return "#{full_issues.length} issues"
+  end
+  
+  def print_issues_table(full_issues)
+    header = "%8s\t%12s\t%s" % ["Key", "Status", "Commits"]
+    puts header
+    time_remaining = 0.0
+    full_issues.each do | issue |
+      key = issue.key
+      status = issue.status
+      commits = self.list_commits(issue)
+      row = "%8s\t%12s\t%s" % [key, status, commits]
+      puts row
+      
+    end
+    print " ", ("-" * 27), "\n"
+  end
+  
+  def list_commits(issue)
+    key = issue.key
+    # Restrict outselves to the svn reveion number lines and then print the revision number prefixed with 'r'
+    commits = GitHelpers.list_commits(key)
+    commits = commits.split(/\n/).join(',')
+    return commits
+  end
+end
+
+
 def get_command
   return Help.new if ARGV.length < 1
   
@@ -1347,12 +1761,14 @@ def get_command
   when "plan" then PlanSprint.new
 	when "cust" then CustIssues.new
 	when "rank" then ARGV.length > 2 ? RankIssue.new : RankSprint.new
-  when "kanban" then ListKanban.new
+  when "kanban1304" then ListKanban1304.new
   when "create" then CreateSprint.new
   when "start" then StartSprint.new
   when "finish" then FinishSprint.new
   when "move" then ARGV.length > 2 ? MoveIssue.new : MoveSprint.new
   when "session" then SessionValid.new
+  when "fix-add" then FixVersionAdd.new
+  when "port1304" then ARGV.length > 2 ? ListPortCommits1304.new : ListPort1304.new
   else Help.new
   end