diff --git a/CHANGELOG b/CHANGELOG
index 422c6f07b150810c027b59f6f42f5b23ebe44454..8099951b0953151666f5bfb46ad7a4aa33a191f7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,13 +1,21 @@
 Please view this file on the master branch, on stable branches it's out of date.
 
-v 8.3.0 (unreleased)
+v 8.4.0 (unreleased)
+  - Implement new UI for group page
+  - Add project permissions to all project API endpoints (Stan Hu)
+
+v 8.3.0
+  - Add CAS support (tduehr)
   - Bump rack-attack to 4.3.1 for security fix (Stan Hu)
   - API support for starred projects for authorized user (Zeger-Jan van de Weg)
+  - Add link to merge request on build detail page.
   - Add open_issues_count to project API (Stan Hu)
   - Expand character set of usernames created by Omniauth (Corey Hinshaw)
   - Add button to automatically merge a merge request when the build succeeds (Zeger-Jan van de Weg)
   - Provide better diagnostic message upon project creation errors (Stan Hu)
   - Bump devise to 3.5.3 to fix reset token expiring after account creation (Stan Hu)
+  - Remove api credentials from link to build_page
+  - Deprecate GitLabCiService making it to always be inactive
   - Bump gollum-lib to 4.1.0 (Stan Hu)
   - Fix broken group avatar upload under "New group" (Stan Hu)
   - Update project repositorize size and commit count during import:repos task (Stan Hu)
@@ -19,8 +27,10 @@ v 8.3.0 (unreleased)
   - Fix 500 error when update group member permission
   - Trim leading and trailing whitespace of milestone and issueable titles (Jose Corcuera)
   - Recognize issue/MR/snippet/commit links as references
+  - Backport JIRA features from EE to CE
   - Add ignore whitespace change option to commit view
   - Fire update hook from GitLab
+  - Allow account unlock via email
   - Style warning about mentioning many people in a comment
   - Fix: sort milestones by due date once again (Greg Smethells)
   - Migrate all CI::Services and CI::WebHooks to Services and WebHooks
@@ -58,6 +68,7 @@ v 8.3.0 (unreleased)
   - Do not show build status unless builds are enabled and `.gitlab-ci.yml` is present
   - Persist runners registration token in database
   - Fix online editor should not remove newlines at the end of the file
+  - Expose Git's version in the admin area
 
 v 8.2.3
   - Fix application settings cache not expiring after changes (Stan Hu)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7ced7c57889557f6da23e60a3a7c7e29fdfa3000..950824e35ab1095cdc78636b8813cfa977e5b77a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -358,7 +358,7 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
 [core team]: https://about.gitlab.com/core-team/
 [getting help page]: https://about.gitlab.com/getting-help/
 [Codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq
-[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up+for+grabs
+[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up-for-grabs
 [medium-up-for-grabs]: https://medium.com/@kentcdodds/first-timers-only-78281ea47455
 [ce-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/issues
 [ee-tracker]: https://gitlab.com/gitlab-org/gitlab-ee/issues
diff --git a/Gemfile b/Gemfile
index 76b4759499efdcba9969e1b4f876dd41dbae114b..3d4345978a7b85877c7cb0dde55cdd9afddc8649 100644
--- a/Gemfile
+++ b/Gemfile
@@ -23,6 +23,7 @@ gem 'devise-async',           '~> 0.9.0'
 gem 'doorkeeper',             '~> 2.2.0'
 gem 'omniauth',               '~> 1.2.2'
 gem 'omniauth-bitbucket',     '~> 0.0.2'
+gem 'omniauth-cas3',          '~> 1.1.2'
 gem 'omniauth-facebook',      '~> 3.0.0'
 gem 'omniauth-github',        '~> 1.1.1'
 gem 'omniauth-gitlab',        '~> 1.0.0'
@@ -101,6 +102,9 @@ gem 'wikicloth',     '0.8.1'
 gem 'asciidoctor',   '~> 1.5.2'
 gem 'rouge',         '~> 1.10.1'
 
+# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
+gem 'nokogiri', '1.6.7.1'
+
 # Diffs
 gem 'diffy', '~> 3.0.3'
 
@@ -186,7 +190,7 @@ gem 'mousetrap-rails', '~> 1.4.6'
 # Detect and convert string character encoding
 gem 'charlock_holmes', '~> 0.7.3'
 
-gem "sass-rails", '~> 4.0.5'
+gem "sass-rails", '~> 5.0.0'
 gem "coffee-rails", '~> 4.1.0'
 gem "uglifier", '~> 2.7.2'
 gem 'turbolinks', '~> 2.5.0'
@@ -198,9 +202,9 @@ gem 'font-awesome-rails', '~> 4.2'
 gem 'gitlab_emoji',       '~> 0.2.0'
 gem 'gon',                '~> 6.0.1'
 gem 'jquery-atwho-rails', '~> 1.3.2'
-gem 'jquery-rails',       '~> 3.1.3'
+gem 'jquery-rails',       '~> 4.0.0'
 gem 'jquery-scrollto-rails', '~> 1.4.3'
-gem 'jquery-ui-rails',    '~> 4.2.1'
+gem 'jquery-ui-rails',    '~> 5.0.0'
 gem 'nprogress-rails',    '~> 0.1.6.7'
 gem 'raphael-rails',      '~> 2.1.2'
 gem 'request_store',      '~> 1.2.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 88c7a6e34241f11835e8506b7f4fe65f0814685f..7477b42f2d8980d08adb6aa50b52b1a61e45af62 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -372,15 +372,16 @@ GEM
     inflecto (0.0.2)
     ipaddress (0.8.0)
     jquery-atwho-rails (1.3.2)
-    jquery-rails (3.1.4)
-      railties (>= 3.0, < 5.0)
+    jquery-rails (4.0.5)
+      rails-dom-testing (~> 1.0)
+      railties (>= 4.2.0)
       thor (>= 0.14, < 2.0)
     jquery-scrollto-rails (1.4.3)
       railties (> 3.1, < 5.0)
     jquery-turbolinks (2.1.0)
       railties (>= 3.1.0)
       turbolinks
-    jquery-ui-rails (4.2.1)
+    jquery-ui-rails (5.0.5)
       railties (>= 3.2.16)
     json (1.8.3)
     jwt (1.5.2)
@@ -420,7 +421,7 @@ GEM
       grape
       newrelic_rpm
     newrelic_rpm (3.9.4.245)
-    nokogiri (1.6.7)
+    nokogiri (1.6.7.1)
       mini_portile2 (~> 2.0.0.rc2)
     nprogress-rails (0.1.6.7)
     oauth (0.4.7)
@@ -439,6 +440,10 @@ GEM
       multi_json (~> 1.7)
       omniauth (~> 1.1)
       omniauth-oauth (~> 1.0)
+    omniauth-cas3 (1.1.3)
+      addressable (~> 2.3)
+      nokogiri (~> 1.6.6)
+      omniauth (~> 1.2)
     omniauth-facebook (3.0.0)
       omniauth-oauth2 (~> 1.2)
     omniauth-github (1.1.2)
@@ -643,12 +648,13 @@ GEM
     safe_yaml (1.0.4)
     sanitize (2.1.0)
       nokogiri (>= 1.4.4)
-    sass (3.2.19)
-    sass-rails (4.0.5)
+    sass (3.4.20)
+    sass-rails (5.0.4)
       railties (>= 4.0.0, < 5.0)
-      sass (~> 3.2.2)
-      sprockets (~> 2.8, < 3.0)
-      sprockets-rails (~> 2.0)
+      sass (~> 3.1)
+      sprockets (>= 2.8, < 4.0)
+      sprockets-rails (>= 2.0, < 4.0)
+      tilt (>= 1.1, < 3)
     sawyer (0.6.0)
       addressable (~> 2.3.5)
       faraday (~> 0.8, < 0.10)
@@ -874,10 +880,10 @@ DEPENDENCIES
   html-pipeline (~> 1.11.0)
   httparty (~> 0.13.3)
   jquery-atwho-rails (~> 1.3.2)
-  jquery-rails (~> 3.1.3)
+  jquery-rails (~> 4.0.0)
   jquery-scrollto-rails (~> 1.4.3)
   jquery-turbolinks (~> 2.1.0)
-  jquery-ui-rails (~> 4.2.1)
+  jquery-ui-rails (~> 5.0.0)
   kaminari (~> 0.16.3)
   letter_opener (~> 1.1.2)
   mail_room (~> 0.6.1)
@@ -888,11 +894,13 @@ DEPENDENCIES
   net-ssh (~> 3.0.1)
   newrelic-grape
   newrelic_rpm (~> 3.9.4.245)
+  nokogiri (= 1.6.7.1)
   nprogress-rails (~> 0.1.6.7)
   oauth2 (~> 1.0.0)
   octokit (~> 3.7.0)
   omniauth (~> 1.2.2)
   omniauth-bitbucket (~> 0.0.2)
+  omniauth-cas3 (~> 1.1.2)
   omniauth-facebook (~> 3.0.0)
   omniauth-github (~> 1.1.1)
   omniauth-gitlab (~> 1.0.0)
@@ -928,7 +936,7 @@ DEPENDENCIES
   rubocop (~> 0.35.0)
   ruby-fogbugz (~> 0.2.1)
   sanitize (~> 2.0)
-  sass-rails (~> 4.0.5)
+  sass-rails (~> 5.0.0)
   sdoc (~> 0.3.20)
   seed-fu (~> 2.3.5)
   select2-rails (~> 3.5.9)
diff --git a/VERSION b/VERSION
index 8d0676ff07ba5372063bb36af9529a8d976c16ad..ce669730119df83f8d693ec9e7401baf55b9245a 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-8.3.0.pre
+8.4.0.pre
diff --git a/app/assets/images/emoji.png b/app/assets/images/emoji.png
new file mode 100644
index 0000000000000000000000000000000000000000..a8ad7b6eab612af71df106bf8ac26541a92fe217
Binary files /dev/null and b/app/assets/images/emoji.png differ
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 1539eba0faa9e0ad0bb136cca26533492669c3e0..affab5bb030d8c72eba0fb7295f700cca0aecf1a 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -5,7 +5,7 @@
 # the compiled file.
 #
 #= require jquery
-#= require jquery.ui.all
+#= require jquery-ui
 #= require jquery_ujs
 #= require jquery.cookie
 #= require jquery.endless-scroll
diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee
index 3ff9ba77dfc7fd77187b66aacfdaf73877f6390b..84e7287e48dc52fbd7ffbcd2719c0095c56b464b 100644
--- a/app/assets/javascripts/awards_handler.coffee
+++ b/app/assets/javascripts/awards_handler.coffee
@@ -1,12 +1,23 @@
 class @AwardsHandler
   constructor: (@post_emoji_url, @noteable_type, @noteable_id, @aliases) ->
+    $(".add-award").click (event)->
+      event.stopPropagation()
+      event.preventDefault()
+      $(".emoji-menu").show()
+
+    $("html").click ->
+      if !$(event.target).closest(".emoji-menu").length
+        if $(".emoji-menu").is(":visible")
+          $(".emoji-menu").hide()
 
   addAward: (emoji) ->
     emoji = @normilizeEmojiName(emoji)
     @postEmoji emoji, =>
       @addAwardToEmojiBar(emoji)
+
+    $(".emoji-menu").hide()
     
-  addAwardToEmojiBar: (emoji, custom_path = '') ->
+  addAwardToEmojiBar: (emoji) ->
     emoji = @normilizeEmojiName(emoji)
     if @exist(emoji)
       if @isActive(emoji)
@@ -17,7 +28,7 @@ class @AwardsHandler
         counter.parent().addClass("active")
         @addMeToAuthorList(emoji)
     else
-      @createEmoji(emoji, custom_path)
+      @createEmoji(emoji)
 
   exist: (emoji) ->
     @findEmojiIcon(emoji).length > 0
@@ -54,31 +65,29 @@ class @AwardsHandler
   resetTooltip: (award) ->
     award.tooltip("destroy")
 
-    # "destroy" call is asynchronous, this is why we need to set timeout.
+    # "destroy" call is asynchronous and there is no appropriate callback on it, this is why we need to set timeout.
     setTimeout (->
       award.tooltip()
     ), 200
     
 
-  createEmoji: (emoji, custom_path) ->
+  createEmoji: (emoji) ->
+    emojiCssClass = @resolveNameToCssClass(emoji)
+
     nodes = []
     nodes.push("<div class='award active' title='me'>")
-    nodes.push("<div class='icon' data-emoji='" + emoji + "'>")
-    nodes.push(@getImage(emoji, custom_path))
+    nodes.push("<div class='icon emoji-icon " + emojiCssClass + "' data-emoji='" + emoji + "'></div>")
+    nodes.push("<div class='counter'>1</div>")
     nodes.push("</div>")
-    nodes.push("<div class='counter'>1")
-    nodes.push("</div></div>")
 
-    $(".awards-controls").before(nodes.join("\n"))
+    emoji_node = $(nodes.join("\n")).insertBefore(".awards-controls").find(".emoji-icon").data("emoji", emoji)
 
     $(".award").tooltip()
 
-  getImage: (emoji, custom_path) ->
-    if custom_path
-      $("<img>").attr({src: custom_path, width: 20, height: 20}).wrap("<div>").parent().html()
-    else
-      $("li[data-emoji='" + emoji + "']").html()
+  resolveNameToCssClass: (emoji) ->
+    unicodeName = $(".emoji-menu-content [data-emoji='?']".replace("?", emoji)).data("unicode-name")
 
+    "emoji-" + unicodeName
 
   postEmoji: (emoji, callback) ->
     $.post @post_emoji_url, { note: {
@@ -90,7 +99,7 @@ class @AwardsHandler
         callback.call()
 
   findEmojiIcon: (emoji) ->
-    $(".icon[data-emoji='" + emoji + "']")
+    $(".award [data-emoji='" + emoji + "']")
 
   scrollToAwards: ->
     $('body, html').animate({
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 35dc7829da2d95571c8a7b41797709115a206f25..9e5204bfeebb7b474ad935e64a3eb59e46d2daa2 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -127,7 +127,7 @@ class @Notes
       @initTaskList()
 
     if note.award
-      awards_handler.addAwardToEmojiBar(note.note, note.emoji_path)
+      awards_handler.addAwardToEmojiBar(note.note)
       awards_handler.scrollToAwards()
 
   ###
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 7b060ce48532c36dadd52950c5f8f293a7515821..0c0451fe4ddffcca924242dc13424067609af4a0 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -2,8 +2,8 @@
  * This is a manifest file that'll automatically include all the stylesheets available in this directory
  * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
  * the top of the compiled file, but it's generally better to create a new file per style scope.
- *= require jquery.ui.datepicker
- *= require jquery.ui.autocomplete
+ *= require jquery-ui/datepicker
+ *= require jquery-ui/autocomplete
  *= require jquery.atwho
  *= require select2
  *= require_self
@@ -48,4 +48,4 @@
 /*
  * Styles for JS behaviors.
  */
-@import "behaviors.scss";
\ No newline at end of file
+@import "behaviors.scss";
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index a62c0f62a4c862cd950accfcf367e17ecc5dfc4c..206d39cc9b3b198f42f82729eb5b1aca18062876 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -76,7 +76,7 @@
 
 .cover-block {
   text-align: center;
-  background: #f7f8fa;
+  background: $background-color;
   margin: -$gl-padding;
   margin-bottom: 0;
   padding: 44px $gl-padding;
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index fe56266284b9d5c5709ce5d2cdd0f2d00eb6226e..97a94638847576c5b8695581e3dd83f21c781865 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -1,10 +1,9 @@
 @mixin btn-default {
-  @include border-radius(2px);
+  @include border-radius(3px);
   border-width: 1px;
   border-style: solid;
-  text-transform: uppercase;
-  font-size: 13px;
-  font-weight: 600;
+  font-size: 15px;
+  font-weight: 500;
   line-height: 18px;
   padding: 11px $gl-padding;
   letter-spacing: .4px;
@@ -18,7 +17,7 @@
 
 @mixin btn-middle {
   @include btn-default;
-  @include border-radius(2px);
+  @include border-radius(3px);
   padding: 11px 24px;
 }
 
@@ -51,6 +50,10 @@
   @include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #FFFFFF);
 }
 
+@mixin btn-blue-medium {
+  @include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, #FFFFFF);
+}
+
 @mixin btn-orange {
   @include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #FFFFFF);
 }
@@ -60,7 +63,7 @@
 }
 
 @mixin btn-gray {
-  @include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-normal, $gray-dark, $border-gray-dark, #313236);
+  @include btn-color($gray-light, $border-gray-light, $gray-normal, $border-gray-light, $gray-dark, $border-gray-dark, #313236);
 }
 
 @mixin btn-white {
@@ -75,6 +78,10 @@
     padding: 5px 10px;
   }
 
+  &.btn-nr {
+    padding: 7px 10px;
+  }
+
   &.btn-xs {
     padding: 1px 5px;
   }
@@ -91,11 +98,15 @@
     @include btn-gray;
   }
 
-  &.btn-primary,
+  &.btn-primary {
+    @include btn-blue-medium;
+  }
+
   &.btn-info {
     @include btn-blue;
   }
 
+  &.btn-close,
   &.btn-warning {
     @include btn-orange;
   }
@@ -110,20 +121,8 @@
     float: right;
   }
 
-  &.btn-close {
-    color: $gl-danger;
-    border-color: $gl-danger;
-    &:hover {
-      color: #B94A48;
-    }
-  }
-
   &.btn-reopen {
-    color: $gl-success;
-    border-color: $gl-success;
-    &:hover {
-      color: #468847;
-    }
+    /* should be same as parent class for now */
   }
 
   &.btn-grouped {
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 7562ef6d24b9ea77ff2f05c834833f6acd0267f0..11730000f85e32f06b75fe0c282f7c3e0e00d802 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -374,7 +374,7 @@ table {
   }
 }
 
-.center-top-menu {
+.center-top-menu, .left-top-menu {
   @include nav-menu;
   text-align: center;
   margin-top: 5px;
@@ -408,6 +408,11 @@ table {
   }
 }
 
+.left-top-menu {
+  text-align: left;
+  border-bottom: 1px solid #EEE;
+}
+
 .center-middle-menu {
   @include nav-menu;
   padding: 0;
diff --git a/app/assets/stylesheets/framework/issue_box.scss b/app/assets/stylesheets/framework/issue_box.scss
index fba67ba0b64a0a3e552a9e6ef05cea22214878ae..e93dbab0c423673007ae683e417780c04031c27f 100644
--- a/app/assets/stylesheets/framework/issue_box.scss
+++ b/app/assets/stylesheets/framework/issue_box.scss
@@ -5,7 +5,7 @@
  */
 
 .status-box {
-  @include border-radius(2px);
+  @include border-radius(3px);
 
   display: block;
   float: left;
@@ -25,7 +25,7 @@
   }
 
   &.status-box-open {
-    background-color: #019875;
+    background-color: $green-light;
     color: #FFF;
   }
 
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index aa5acb93cc52cb96882493e1300bfe3ba94128bc..a1a9990241d6964d96bda9f13e882c2c7ae9c66e 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -5,7 +5,7 @@ html {
 }
 
 body {
-  background-color: #EAEBEC !important;
+  background-color: #F3F3F3 !important;
 
   &.navless {
     background-color: white !important;
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 11c48d26ab53a27e50564b4c261ce0224653e6b0..41fd890f14f8046b858b3e6f56fffb4dd16ba338 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -123,7 +123,6 @@
   padding: 0;
   margin: 0;
   list-style: none;
-  margin-top: 5px;
   height: 56px;
 
   li {
@@ -131,9 +130,9 @@
 
     a {
       padding: 14px;
-      font-size: 17px;
+      font-size: 15px;
       line-height: 28px;
-      color: #7f8fa4;
+      color: #959494;
       border-bottom: 2px solid transparent;
 
       &:hover, &:active, &:focus {
@@ -143,8 +142,8 @@
     }
 
     &.active a {
-      color: #4c4e54;
-      border-bottom: 2px solid #1cacfc;
+      color: #616060;
+      border-bottom: 2px solid #4688f1;
     }
 
     .badge {
diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss
index 6f44c323732325d73eed22088c5ee1f8c43883b7..c00709fb6bb9a3bb1d7f07080ed77ff2502610a1 100644
--- a/app/assets/stylesheets/framework/mobile.scss
+++ b/app/assets/stylesheets/framework/mobile.scss
@@ -81,7 +81,7 @@
     display: none;
   }
 
-  .center-top-menu {
+  .center-top-menu, .left-top-menu {
     li a {
       font-size: 14px;
       padding: 19px 10px;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 2ef40a6e51738724399a45b592faf9a30c757152..af75123b0af367508648ead871ee196e231dc049 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -1,9 +1,9 @@
-$hover: #FFFAF1;
+$hover: #faf9f9;
 $gl-text-color: #54565B;
 $gl-text-green: #4A2;
 $gl-text-red: #D12F19;
 $gl-text-orange: #D90;
-$gl-header-color: #4c4e54;
+$gl-header-color: #323232;
 $gl-link-color: #333c48;
 $md-text-color: #444;
 $md-link-color: #3084bb;
@@ -15,13 +15,14 @@ $sidebar_width: 230px;
 $avatar_radius: 50%;
 $code_font_size: 13px;
 $code_line_height: 1.5;
-$border-color: #dce0e6;
+$border-color: #efeff1;
 $table-border-color: #eef0f2;
-$background-color: #F7F8FA;
+$background-color: #faf9f9;
 $header-height: 58px;
 $fixed-layout-width: 1280px;
-$gl-gray: #7f8fa4;
+$gl-gray: #5a5a5a;
 $gl-padding: 16px;
+$gl-padding-top:10px;
 $gl-avatar-size: 46px;
 
 /*
@@ -29,12 +30,12 @@ $gl-avatar-size: 46px;
  */
 
 $white-light: #FFFFFF;
-$white-normal: #DCE0E5;
-$white-dark: #E4E7ED;
+$white-normal: #ededed;
+$white-dark: #ededed;
 
-$gray-light: #F0F2F5;
-$gray-normal: #DCE0E5;
-$gray-dark: #E4E7ED;
+$gray-light: #f7f7f7;
+$gray-normal: #ededed;
+$gray-dark: #ededed;
 
 $green-light: #31AF64;
 $green-normal: #2FAA60;
@@ -44,6 +45,10 @@ $blue-light: #2EA8E5;
 $blue-normal: #2D9FD8;
 $blue-dark: #2897CE;
 
+$blue-medium-light: #3498CB;
+$blue-medium: #2F8EBF;
+$blue-medium-dark: #2D86B4;
+
 $orange-light: #FC6443;
 $orange-normal: #E75E40;
 $orange-dark: #CE5237;
@@ -52,11 +57,11 @@ $red-light: #F43263;
 $red-normal: #E52C5A;
 $red-dark: #D22852;
 
-$border-white-light: #E3E7EC;
+$border-white-light: #F1F2F4;
 $border-white-normal: #D6DAE2;
 $border-white-dark: #C6CACF;
 
-$border-gray-light: #DCE0E5;
+$border-gray-light: #d1d1d1;
 $border-gray-normal: #D6DAE2;
 $border-gray-dark: #C6CACF;
 
@@ -76,6 +81,8 @@ $border-red-light: #E52C5A;
 $border-red-normal: #D22852;
 $border-red-dark: #CA264F;
 
+/* header */
+$light-grey-header: #faf9f9;
 
 /*
  * State colors:
diff --git a/app/assets/stylesheets/pages/awards.scss b/app/assets/stylesheets/pages/awards.scss
index 041b811a606b6f418e6417cb3e27fd4c43c04135..aa1a06b2fcc09ad521df17bf7ead22479379f257 100644
--- a/app/assets/stylesheets/pages/awards.scss
+++ b/app/assets/stylesheets/pages/awards.scss
@@ -2,6 +2,12 @@
   @include clearfix;
   line-height: 34px;
 
+  .emoji-icon {
+    width: 20px;
+    height: 20px;
+    margin: 7px 0 0 5px;
+  }
+
   .award {
     @include border-radius(5px);
 
@@ -40,6 +46,7 @@
   }
 
   .awards-controls {
+    position: relative;
     margin-left: 10px;
     float: left;
 
@@ -55,32 +62,60 @@
       }
     }
 
-    .awards-menu {
-      padding: $gl-padding;
-      min-width: 214px;
-
-      > li {
-        cursor: pointer;
-        width: 30px;
-        height: 30px;
-        text-align: center;
-        @include border-radius(5px);
+    .emoji-menu{
+      position: absolute;
+      top: 100%;
+      left: 0;
+      z-index: 1000;
+      display: none;
+      float: left;
+      min-width: 160px;
+      padding: 5px 0;
+      margin: 2px 0 0;
+      font-size: 14px;
+      text-align: left;
+      list-style: none;
+      background-color: #fff;
+      -webkit-background-clip: padding-box;
+      background-clip: padding-box;
+      border: 1px solid #ccc;
+      border: 1px solid rgba(0,0,0,.15);
+      border-radius: 4px;
+      -webkit-box-shadow: 0 6px 12px rgba(0,0,0,.175);
+      box-shadow: 0 6px 12px rgba(0,0,0,.175);
+
+      .emoji-menu-content {
+        padding: $gl-padding;
+        width: 300px;
+        height: 300px;
+        overflow-y: scroll;
+
+        h5 {
+          clear: left;
+        }
 
-        img {
-          margin-bottom: 2px;
+        ul {
+          list-style-type: none;
+          margin-left: -20px;
+          margin-bottom: 20px;
+          overflow: auto;
         }
 
-        &:hover {
-          background-color: #ccc;
+        li {
+          cursor: pointer;
+          width: 30px;
+          height: 30px;
+          text-align: center;
+          float: left;
+          margin: 3px;
+          list-decorate: none;
+          @include border-radius(5px);
+
+          &:hover {
+            background-color: #ccc;
+          }
         }
       }
     }
   }
-
-  .awards-menu{
-    li {
-      float: left;
-      margin: 3px;
-    }
-  }
 }
diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss
index 0f3463a914474988f71ac010dedfbe37401e8508..deab805dbc2988ab003f6f5b47675e7cb1697a92 100644
--- a/app/assets/stylesheets/pages/detail_page.scss
+++ b/app/assets/stylesheets/pages/detail_page.scss
@@ -5,7 +5,7 @@
   border-bottom: 1px solid $border-color;
   color: #5c5d5e;
   font-size: 16px;
-  line-height: 42px;
+  line-height: 34px;
 
   .author {
     color: #5c5d5e;
diff --git a/app/assets/stylesheets/pages/emojis.scss b/app/assets/stylesheets/pages/emojis.scss
new file mode 100644
index 0000000000000000000000000000000000000000..819ec9a2f5f3142d3f5aa10beba50553ab7d57df
--- /dev/null
+++ b/app/assets/stylesheets/pages/emojis.scss
@@ -0,0 +1,1272 @@
+/*
+File is generated by https://github.com/jakesgordon/sprite-factory and midified manualy
+The source: gemojione gem.
+*/
+
+.emoji-icon{
+  background-image: url(emoji.png);
+  background-repeat: no-repeat;
+}
+
+.emoji-0023-20E3 { background-position: 0px 0px; }
+.emoji-0030-20E3 { background-position: -20px 0px; }
+.emoji-0031-20E3 { background-position: -40px 0px; }
+.emoji-0032-20E3 { background-position: -60px 0px; }
+.emoji-0033-20E3 { background-position: -80px 0px; }
+.emoji-0034-20E3 { background-position: -100px 0px; }
+.emoji-0035-20E3 { background-position: -120px 0px; }
+.emoji-0036-20E3 { background-position: -140px 0px; }
+.emoji-0037-20E3 { background-position: -160px 0px; }
+.emoji-0038-20E3 { background-position: -180px 0px; }
+.emoji-0039-20E3 { background-position: -200px 0px; }
+.emoji-00A9 { background-position: -220px 0px; }
+.emoji-00AE { background-position: -240px 0px; }
+.emoji-1F004 { background-position: -260px 0px; }
+.emoji-1F0CF { background-position: -280px 0px; }
+.emoji-1F170 { background-position: -300px 0px; }
+.emoji-1F171 { background-position: -320px 0px; }
+.emoji-1F17E { background-position: -340px 0px; }
+.emoji-1F17F { background-position: -360px 0px; }
+.emoji-1F18E { background-position: -380px 0px; }
+.emoji-1F191 { background-position: -400px 0px; }
+.emoji-1F192 { background-position: -420px 0px; }
+.emoji-1F193 { background-position: -440px 0px; }
+.emoji-1F194 { background-position: -460px 0px; }
+.emoji-1F195 { background-position: -480px 0px; }
+.emoji-1F196 { background-position: -500px 0px; }
+.emoji-1F197 { background-position: -520px 0px; }
+.emoji-1F198 { background-position: -540px 0px; }
+.emoji-1F199 { background-position: -560px 0px; }
+.emoji-1F19A { background-position: -580px 0px; }
+.emoji-1F1E6-1F1E8 { background-position: -600px 0px; }
+.emoji-1F1E6-1F1E9 { background-position: -620px 0px; }
+.emoji-1F1E6-1F1EA { background-position: -640px 0px; }
+.emoji-1F1E6-1F1EB { background-position: -660px 0px; }
+.emoji-1F1E6-1F1EC { background-position: -680px 0px; }
+.emoji-1F1E6-1F1EE { background-position: -700px 0px; }
+.emoji-1F1E6-1F1F1 { background-position: -720px 0px; }
+.emoji-1F1E6-1F1F2 { background-position: -740px 0px; }
+.emoji-1F1E6-1F1F4 { background-position: -760px 0px; }
+.emoji-1F1E6-1F1F7 { background-position: -780px 0px; }
+.emoji-1F1E6-1F1F9 { background-position: -800px 0px; }
+.emoji-1F1E6-1F1FA { background-position: -820px 0px; }
+.emoji-1F1E6-1F1FC { background-position: -840px 0px; }
+.emoji-1F1E6-1F1FF { background-position: -860px 0px; }
+.emoji-1F1E7-1F1E6 { background-position: -880px 0px; }
+.emoji-1F1E7-1F1E7 { background-position: -900px 0px; }
+.emoji-1F1E7-1F1E9 { background-position: -920px 0px; }
+.emoji-1F1E7-1F1EA { background-position: -940px 0px; }
+.emoji-1F1E7-1F1EB { background-position: -960px 0px; }
+.emoji-1F1E7-1F1EC { background-position: -980px 0px; }
+.emoji-1F1E7-1F1ED { background-position: -1000px 0px; }
+.emoji-1F1E7-1F1EE { background-position: -1020px 0px; }
+.emoji-1F1E7-1F1EF { background-position: -1040px 0px; }
+.emoji-1F1E7-1F1F2 { background-position: -1060px 0px; }
+.emoji-1F1E7-1F1F3 { background-position: -1080px 0px; }
+.emoji-1F1E7-1F1F4 { background-position: -1100px 0px; }
+.emoji-1F1E7-1F1F7 { background-position: -1120px 0px; }
+.emoji-1F1E7-1F1F8 { background-position: -1140px 0px; }
+.emoji-1F1E7-1F1F9 { background-position: -1160px 0px; }
+.emoji-1F1E7-1F1FC { background-position: -1180px 0px; }
+.emoji-1F1E7-1F1FE { background-position: -1200px 0px; }
+.emoji-1F1E7-1F1FF { background-position: -1220px 0px; }
+.emoji-1F1E8-1F1E6 { background-position: -1240px 0px; }
+.emoji-1F1E8-1F1E9 { background-position: -1260px 0px; }
+.emoji-1F1E8-1F1EB { background-position: -1280px 0px; }
+.emoji-1F1E8-1F1EC { background-position: -1300px 0px; }
+.emoji-1F1E8-1F1ED { background-position: -1320px 0px; }
+.emoji-1F1E8-1F1EE { background-position: -1340px 0px; }
+.emoji-1F1E8-1F1F1 { background-position: -1360px 0px; }
+.emoji-1F1E8-1F1F2 { background-position: -1380px 0px; }
+.emoji-1F1E8-1F1F3 { background-position: -1400px 0px; }
+.emoji-1F1E8-1F1F4 { background-position: -1420px 0px; }
+.emoji-1F1E8-1F1F7 { background-position: -1440px 0px; }
+.emoji-1F1E8-1F1FA { background-position: -1460px 0px; }
+.emoji-1F1E8-1F1FB { background-position: -1480px 0px; }
+.emoji-1F1E8-1F1FE { background-position: -1500px 0px; }
+.emoji-1F1E8-1F1FF { background-position: -1520px 0px; }
+.emoji-1F1E9-1F1EA { background-position: -1540px 0px; }
+.emoji-1F1E9-1F1EF { background-position: -1560px 0px; }
+.emoji-1F1E9-1F1F0 { background-position: -1580px 0px; }
+.emoji-1F1E9-1F1F2 { background-position: -1600px 0px; }
+.emoji-1F1E9-1F1F4 { background-position: -1620px 0px; }
+.emoji-1F1E9-1F1FF { background-position: -1640px 0px; }
+.emoji-1F1EA-1F1E8 { background-position: -1660px 0px; }
+.emoji-1F1EA-1F1EA { background-position: -1680px 0px; }
+.emoji-1F1EA-1F1EC { background-position: -1700px 0px; }
+.emoji-1F1EA-1F1ED { background-position: -1720px 0px; }
+.emoji-1F1EA-1F1F7 { background-position: -1740px 0px; }
+.emoji-1F1EA-1F1F8 { background-position: -1760px 0px; }
+.emoji-1F1EA-1F1F9 { background-position: -1780px 0px; }
+.emoji-1F1EB-1F1EE { background-position: -1800px 0px; }
+.emoji-1F1EB-1F1EF { background-position: -1820px 0px; }
+.emoji-1F1EB-1F1F0 { background-position: -1840px 0px; }
+.emoji-1F1EB-1F1F2 { background-position: -1860px 0px; }
+.emoji-1F1EB-1F1F4 { background-position: -1880px 0px; }
+.emoji-1F1EB-1F1F7 { background-position: -1900px 0px; }
+.emoji-1F1EC-1F1E6 { background-position: -1920px 0px; }
+.emoji-1F1EC-1F1E7 { background-position: -1940px 0px; }
+.emoji-1F1EC-1F1E9 { background-position: -1960px 0px; }
+.emoji-1F1EC-1F1EA { background-position: -1980px 0px; }
+.emoji-1F1EC-1F1ED { background-position: -2000px 0px; }
+.emoji-1F1EC-1F1EE { background-position: -2020px 0px; }
+.emoji-1F1EC-1F1F1 { background-position: -2040px 0px; }
+.emoji-1F1EC-1F1F2 { background-position: -2060px 0px; }
+.emoji-1F1EC-1F1F3 { background-position: -2080px 0px; }
+.emoji-1F1EC-1F1F6 { background-position: -2100px 0px; }
+.emoji-1F1EC-1F1F7 { background-position: -2120px 0px; }
+.emoji-1F1EC-1F1F9 { background-position: -2140px 0px; }
+.emoji-1F1EC-1F1FA { background-position: -2160px 0px; }
+.emoji-1F1EC-1F1FC { background-position: -2180px 0px; }
+.emoji-1F1EC-1F1FE { background-position: -2200px 0px; }
+.emoji-1F1ED-1F1F0 { background-position: -2220px 0px; }
+.emoji-1F1ED-1F1F3 { background-position: -2240px 0px; }
+.emoji-1F1ED-1F1F7 { background-position: -2260px 0px; }
+.emoji-1F1ED-1F1F9 { background-position: -2280px 0px; }
+.emoji-1F1ED-1F1FA { background-position: -2300px 0px; }
+.emoji-1F1EE-1F1E9 { background-position: -2320px 0px; }
+.emoji-1F1EE-1F1EA { background-position: -2340px 0px; }
+.emoji-1F1EE-1F1F1 { background-position: -2360px 0px; }
+.emoji-1F1EE-1F1F3 { background-position: -2380px 0px; }
+.emoji-1F1EE-1F1F6 { background-position: -2400px 0px; }
+.emoji-1F1EE-1F1F7 { background-position: -2420px 0px; }
+.emoji-1F1EE-1F1F8 { background-position: -2440px 0px; }
+.emoji-1F1EE-1F1F9 { background-position: -2460px 0px; }
+.emoji-1F1EF-1F1EA { background-position: -2480px 0px; }
+.emoji-1F1EF-1F1F2 { background-position: -2500px 0px; }
+.emoji-1F1EF-1F1F4 { background-position: -2520px 0px; }
+.emoji-1F1EF-1F1F5 { background-position: -2540px 0px; }
+.emoji-1F1F0-1F1EA { background-position: -2560px 0px; }
+.emoji-1F1F0-1F1EC { background-position: -2580px 0px; }
+.emoji-1F1F0-1F1ED { background-position: -2600px 0px; }
+.emoji-1F1F0-1F1EE { background-position: -2620px 0px; }
+.emoji-1F1F0-1F1F2 { background-position: -2640px 0px; }
+.emoji-1F1F0-1F1F3 { background-position: -2660px 0px; }
+.emoji-1F1F0-1F1F5 { background-position: -2680px 0px; }
+.emoji-1F1F0-1F1F7 { background-position: -2700px 0px; }
+.emoji-1F1F0-1F1FC { background-position: -2720px 0px; }
+.emoji-1F1F0-1F1FE { background-position: -2740px 0px; }
+.emoji-1F1F0-1F1FF { background-position: -2760px 0px; }
+.emoji-1F1F1-1F1E6 { background-position: -2780px 0px; }
+.emoji-1F1F1-1F1E7 { background-position: -2800px 0px; }
+.emoji-1F1F1-1F1E8 { background-position: -2820px 0px; }
+.emoji-1F1F1-1F1EE { background-position: -2840px 0px; }
+.emoji-1F1F1-1F1F0 { background-position: -2860px 0px; }
+.emoji-1F1F1-1F1F7 { background-position: -2880px 0px; }
+.emoji-1F1F1-1F1F8 { background-position: -2900px 0px; }
+.emoji-1F1F1-1F1F9 { background-position: -2920px 0px; }
+.emoji-1F1F1-1F1FA { background-position: -2940px 0px; }
+.emoji-1F1F1-1F1FB { background-position: -2960px 0px; }
+.emoji-1F1F1-1F1FE { background-position: -2980px 0px; }
+.emoji-1F1F2-1F1E6 { background-position: -3000px 0px; }
+.emoji-1F1F2-1F1E8 { background-position: -3020px 0px; }
+.emoji-1F1F2-1F1E9 { background-position: -3040px 0px; }
+.emoji-1F1F2-1F1EA { background-position: -3060px 0px; }
+.emoji-1F1F2-1F1EC { background-position: -3080px 0px; }
+.emoji-1F1F2-1F1ED { background-position: -3100px 0px; }
+.emoji-1F1F2-1F1F0 { background-position: -3120px 0px; }
+.emoji-1F1F2-1F1F1 { background-position: -3140px 0px; }
+.emoji-1F1F2-1F1F2 { background-position: -3160px 0px; }
+.emoji-1F1F2-1F1F3 { background-position: -3180px 0px; }
+.emoji-1F1F2-1F1F4 { background-position: -3200px 0px; }
+.emoji-1F1F2-1F1F7 { background-position: -3220px 0px; }
+.emoji-1F1F2-1F1F8 { background-position: -3240px 0px; }
+.emoji-1F1F2-1F1F9 { background-position: -3260px 0px; }
+.emoji-1F1F2-1F1FA { background-position: -3280px 0px; }
+.emoji-1F1F2-1F1FB { background-position: -3300px 0px; }
+.emoji-1F1F2-1F1FC { background-position: -3320px 0px; }
+.emoji-1F1F2-1F1FD { background-position: -3340px 0px; }
+.emoji-1F1F2-1F1FE { background-position: -3360px 0px; }
+.emoji-1F1F2-1F1FF { background-position: -3380px 0px; }
+.emoji-1F1F3-1F1E6 { background-position: -3400px 0px; }
+.emoji-1F1F3-1F1E8 { background-position: -3420px 0px; }
+.emoji-1F1F3-1F1EA { background-position: -3440px 0px; }
+.emoji-1F1F3-1F1EC { background-position: -3460px 0px; }
+.emoji-1F1F3-1F1EE { background-position: -3480px 0px; }
+.emoji-1F1F3-1F1F1 { background-position: -3500px 0px; }
+.emoji-1F1F3-1F1F4 { background-position: -3520px 0px; }
+.emoji-1F1F3-1F1F5 { background-position: -3540px 0px; }
+.emoji-1F1F3-1F1F7 { background-position: -3560px 0px; }
+.emoji-1F1F3-1F1FA { background-position: -3580px 0px; }
+.emoji-1F1F3-1F1FF { background-position: -3600px 0px; }
+.emoji-1F1F4-1F1F2 { background-position: -3620px 0px; }
+.emoji-1F1F5-1F1E6 { background-position: -3640px 0px; }
+.emoji-1F1F5-1F1EA { background-position: -3660px 0px; }
+.emoji-1F1F5-1F1EB { background-position: -3680px 0px; }
+.emoji-1F1F5-1F1EC { background-position: -3700px 0px; }
+.emoji-1F1F5-1F1ED { background-position: -3720px 0px; }
+.emoji-1F1F5-1F1F0 { background-position: -3740px 0px; }
+.emoji-1F1F5-1F1F1 { background-position: -3760px 0px; }
+.emoji-1F1F5-1F1F7 { background-position: -3780px 0px; }
+.emoji-1F1F5-1F1F8 { background-position: -3800px 0px; }
+.emoji-1F1F5-1F1F9 { background-position: -3820px 0px; }
+.emoji-1F1F5-1F1FC { background-position: -3840px 0px; }
+.emoji-1F1F5-1F1FE { background-position: -3860px 0px; }
+.emoji-1F1F6-1F1E6 { background-position: -3880px 0px; }
+.emoji-1F1F7-1F1F4 { background-position: -3900px 0px; }
+.emoji-1F1F7-1F1F8 { background-position: -3920px 0px; }
+.emoji-1F1F7-1F1FA { background-position: -3940px 0px; }
+.emoji-1F1F7-1F1FC { background-position: -3960px 0px; }
+.emoji-1F1F8-1F1E6 { background-position: -3980px 0px; }
+.emoji-1F1F8-1F1E7 { background-position: -4000px 0px; }
+.emoji-1F1F8-1F1E8 { background-position: -4020px 0px; }
+.emoji-1F1F8-1F1E9 { background-position: -4040px 0px; }
+.emoji-1F1F8-1F1EA { background-position: -4060px 0px; }
+.emoji-1F1F8-1F1EC { background-position: -4080px 0px; }
+.emoji-1F1F8-1F1ED { background-position: -4100px 0px; }
+.emoji-1F1F8-1F1EE { background-position: -4120px 0px; }
+.emoji-1F1F8-1F1F0 { background-position: -4140px 0px; }
+.emoji-1F1F8-1F1F1 { background-position: -4160px 0px; }
+.emoji-1F1F8-1F1F2 { background-position: -4180px 0px; }
+.emoji-1F1F8-1F1F3 { background-position: -4200px 0px; }
+.emoji-1F1F8-1F1F4 { background-position: -4220px 0px; }
+.emoji-1F1F8-1F1F7 { background-position: -4240px 0px; }
+.emoji-1F1F8-1F1F9 { background-position: -4260px 0px; }
+.emoji-1F1F8-1F1FB { background-position: -4280px 0px; }
+.emoji-1F1F8-1F1FE { background-position: -4300px 0px; }
+.emoji-1F1F8-1F1FF { background-position: -4320px 0px; }
+.emoji-1F1F9-1F1E9 { background-position: -4340px 0px; }
+.emoji-1F1F9-1F1EC { background-position: -4360px 0px; }
+.emoji-1F1F9-1F1ED { background-position: -4380px 0px; }
+.emoji-1F1F9-1F1EF { background-position: -4400px 0px; }
+.emoji-1F1F9-1F1F1 { background-position: -4420px 0px; }
+.emoji-1F1F9-1F1F2 { background-position: -4440px 0px; }
+.emoji-1F1F9-1F1F3 { background-position: -4460px 0px; }
+.emoji-1F1F9-1F1F4 { background-position: -4480px 0px; }
+.emoji-1F1F9-1F1F7 { background-position: -4500px 0px; }
+.emoji-1F1F9-1F1F9 { background-position: -4520px 0px; }
+.emoji-1F1F9-1F1FB { background-position: -4540px 0px; }
+.emoji-1F1F9-1F1FC { background-position: -4560px 0px; }
+.emoji-1F1F9-1F1FF { background-position: -4580px 0px; }
+.emoji-1F1FA-1F1E6 { background-position: -4600px 0px; }
+.emoji-1F1FA-1F1EC { background-position: -4620px 0px; }
+.emoji-1F1FA-1F1F8 { background-position: -4640px 0px; }
+.emoji-1F1FA-1F1FE { background-position: -4660px 0px; }
+.emoji-1F1FA-1F1FF { background-position: -4680px 0px; }
+.emoji-1F1FB-1F1E6 { background-position: -4700px 0px; }
+.emoji-1F1FB-1F1E8 { background-position: -4720px 0px; }
+.emoji-1F1FB-1F1EA { background-position: -4740px 0px; }
+.emoji-1F1FB-1F1EE { background-position: -4760px 0px; }
+.emoji-1F1FB-1F1F3 { background-position: -4780px 0px; }
+.emoji-1F1FB-1F1FA { background-position: -4800px 0px; }
+.emoji-1F1FC-1F1EB { background-position: -4820px 0px; }
+.emoji-1F1FC-1F1F8 { background-position: -4840px 0px; }
+.emoji-1F1FD-1F1F0 { background-position: -4860px 0px; }
+.emoji-1F1FE-1F1EA { background-position: -4880px 0px; }
+.emoji-1F1FF-1F1E6 { background-position: -4900px 0px; }
+.emoji-1F1FF-1F1F2 { background-position: -4920px 0px; }
+.emoji-1F1FF-1F1FC { background-position: -4940px 0px; }
+.emoji-1F201 { background-position: -4960px 0px; }
+.emoji-1F202 { background-position: -4980px 0px; }
+.emoji-1F21A { background-position: -5000px 0px; }
+.emoji-1F22F { background-position: -5020px 0px; }
+.emoji-1F232 { background-position: -5040px 0px; }
+.emoji-1F233 { background-position: -5060px 0px; }
+.emoji-1F234 { background-position: -5080px 0px; }
+.emoji-1F235 { background-position: -5100px 0px; }
+.emoji-1F236 { background-position: -5120px 0px; }
+.emoji-1F237 { background-position: -5140px 0px; }
+.emoji-1F238 { background-position: -5160px 0px; }
+.emoji-1F239 { background-position: -5180px 0px; }
+.emoji-1F23A { background-position: -5200px 0px; }
+.emoji-1F250 { background-position: -5220px 0px; }
+.emoji-1F251 { background-position: -5240px 0px; }
+.emoji-1F300 { background-position: -5260px 0px; }
+.emoji-1F301 { background-position: -5280px 0px; }
+.emoji-1F302 { background-position: -5300px 0px; }
+.emoji-1F303 { background-position: -5320px 0px; }
+.emoji-1F304 { background-position: -5340px 0px; }
+.emoji-1F305 { background-position: -5360px 0px; }
+.emoji-1F306 { background-position: -5380px 0px; }
+.emoji-1F307 { background-position: -5400px 0px; }
+.emoji-1F308 { background-position: -5420px 0px; }
+.emoji-1F309 { background-position: -5440px 0px; }
+.emoji-1F30A { background-position: -5460px 0px; }
+.emoji-1F30B { background-position: -5480px 0px; }
+.emoji-1F30C { background-position: -5500px 0px; }
+.emoji-1F30D { background-position: -5520px 0px; }
+.emoji-1F30E { background-position: -5540px 0px; }
+.emoji-1F30F { background-position: -5560px 0px; }
+.emoji-1F310 { background-position: -5580px 0px; }
+.emoji-1F311 { background-position: -5600px 0px; }
+.emoji-1F312 { background-position: -5620px 0px; }
+.emoji-1F313 { background-position: -5640px 0px; }
+.emoji-1F314 { background-position: -5660px 0px; }
+.emoji-1F315 { background-position: -5680px 0px; }
+.emoji-1F316 { background-position: -5700px 0px; }
+.emoji-1F317 { background-position: -5720px 0px; }
+.emoji-1F318 { background-position: -5740px 0px; }
+.emoji-1F319 { background-position: -5760px 0px; }
+.emoji-1F31A { background-position: -5780px 0px; }
+.emoji-1F31B { background-position: -5800px 0px; }
+.emoji-1F31C { background-position: -5820px 0px; }
+.emoji-1F31D { background-position: -5840px 0px; }
+.emoji-1F31E { background-position: -5860px 0px; }
+.emoji-1F31F { background-position: -5880px 0px; }
+.emoji-1F320 { background-position: -5900px 0px; }
+.emoji-1F321 { background-position: -5920px 0px; }
+.emoji-1F327 { background-position: -5940px 0px; }
+.emoji-1F328 { background-position: -5960px 0px; }
+.emoji-1F329 { background-position: -5980px 0px; }
+.emoji-1F32A { background-position: -6000px 0px; }
+.emoji-1F32B { background-position: -6020px 0px; }
+.emoji-1F32C { background-position: -6040px 0px; }
+.emoji-1F330 { background-position: -6060px 0px; }
+.emoji-1F331 { background-position: -6080px 0px; }
+.emoji-1F332 { background-position: -6100px 0px; }
+.emoji-1F333 { background-position: -6120px 0px; }
+.emoji-1F334 { background-position: -6140px 0px; }
+.emoji-1F335 { background-position: -6160px 0px; }
+.emoji-1F336 { background-position: -6180px 0px; }
+.emoji-1F337 { background-position: -6200px 0px; }
+.emoji-1F338 { background-position: -6220px 0px; }
+.emoji-1F339 { background-position: -6240px 0px; }
+.emoji-1F33A { background-position: -6260px 0px; }
+.emoji-1F33B { background-position: -6280px 0px; }
+.emoji-1F33C { background-position: -6300px 0px; }
+.emoji-1F33D { background-position: -6320px 0px; }
+.emoji-1F33E { background-position: -6340px 0px; }
+.emoji-1F33F { background-position: -6360px 0px; }
+.emoji-1F340 { background-position: -6380px 0px; }
+.emoji-1F341 { background-position: -6400px 0px; }
+.emoji-1F342 { background-position: -6420px 0px; }
+.emoji-1F343 { background-position: -6440px 0px; }
+.emoji-1F344 { background-position: -6460px 0px; }
+.emoji-1F345 { background-position: -6480px 0px; }
+.emoji-1F346 { background-position: -6500px 0px; }
+.emoji-1F347 { background-position: -6520px 0px; }
+.emoji-1F348 { background-position: -6540px 0px; }
+.emoji-1F349 { background-position: -6560px 0px; }
+.emoji-1F34A { background-position: -6580px 0px; }
+.emoji-1F34B { background-position: -6600px 0px; }
+.emoji-1F34C { background-position: -6620px 0px; }
+.emoji-1F34D { background-position: -6640px 0px; }
+.emoji-1F34E { background-position: -6660px 0px; }
+.emoji-1F34F { background-position: -6680px 0px; }
+.emoji-1F350 { background-position: -6700px 0px; }
+.emoji-1F351 { background-position: -6720px 0px; }
+.emoji-1F352 { background-position: -6740px 0px; }
+.emoji-1F353 { background-position: -6760px 0px; }
+.emoji-1F354 { background-position: -6780px 0px; }
+.emoji-1F355 { background-position: -6800px 0px; }
+.emoji-1F356 { background-position: -6820px 0px; }
+.emoji-1F357 { background-position: -6840px 0px; }
+.emoji-1F358 { background-position: -6860px 0px; }
+.emoji-1F359 { background-position: -6880px 0px; }
+.emoji-1F35A { background-position: -6900px 0px; }
+.emoji-1F35B { background-position: -6920px 0px; }
+.emoji-1F35C { background-position: -6940px 0px; }
+.emoji-1F35D { background-position: -6960px 0px; }
+.emoji-1F35E { background-position: -6980px 0px; }
+.emoji-1F35F { background-position: -7000px 0px; }
+.emoji-1F360 { background-position: -7020px 0px; }
+.emoji-1F361 { background-position: -7040px 0px; }
+.emoji-1F362 { background-position: -7060px 0px; }
+.emoji-1F363 { background-position: -7080px 0px; }
+.emoji-1F364 { background-position: -7100px 0px; }
+.emoji-1F365 { background-position: -7120px 0px; }
+.emoji-1F366 { background-position: -7140px 0px; }
+.emoji-1F367 { background-position: -7160px 0px; }
+.emoji-1F368 { background-position: -7180px 0px; }
+.emoji-1F369 { background-position: -7200px 0px; }
+.emoji-1F36A { background-position: -7220px 0px; }
+.emoji-1F36B { background-position: -7240px 0px; }
+.emoji-1F36C { background-position: -7260px 0px; }
+.emoji-1F36D { background-position: -7280px 0px; }
+.emoji-1F36E { background-position: -7300px 0px; }
+.emoji-1F36F { background-position: -7320px 0px; }
+.emoji-1F370 { background-position: -7340px 0px; }
+.emoji-1F371 { background-position: -7360px 0px; }
+.emoji-1F372 { background-position: -7380px 0px; }
+.emoji-1F373 { background-position: -7400px 0px; }
+.emoji-1F374 { background-position: -7420px 0px; }
+.emoji-1F375 { background-position: -7440px 0px; }
+.emoji-1F376 { background-position: -7460px 0px; }
+.emoji-1F377 { background-position: -7480px 0px; }
+.emoji-1F378 { background-position: -7500px 0px; }
+.emoji-1F379 { background-position: -7520px 0px; }
+.emoji-1F37A { background-position: -7540px 0px; }
+.emoji-1F37B { background-position: -7560px 0px; }
+.emoji-1F37C { background-position: -7580px 0px; }
+.emoji-1F37D { background-position: -7600px 0px; }
+.emoji-1F380 { background-position: -7620px 0px; }
+.emoji-1F381 { background-position: -7640px 0px; }
+.emoji-1F382 { background-position: -7660px 0px; }
+.emoji-1F383 { background-position: -7680px 0px; }
+.emoji-1F384 { background-position: -7700px 0px; }
+.emoji-1F385 { background-position: -7720px 0px; }
+.emoji-1F386 { background-position: -7740px 0px; }
+.emoji-1F387 { background-position: -7760px 0px; }
+.emoji-1F388 { background-position: -7780px 0px; }
+.emoji-1F389 { background-position: -7800px 0px; }
+.emoji-1F38A { background-position: -7820px 0px; }
+.emoji-1F38B { background-position: -7840px 0px; }
+.emoji-1F38C { background-position: -7860px 0px; }
+.emoji-1F38D { background-position: -7880px 0px; }
+.emoji-1F38E { background-position: -7900px 0px; }
+.emoji-1F38F { background-position: -7920px 0px; }
+.emoji-1F390 { background-position: -7940px 0px; }
+.emoji-1F391 { background-position: -7960px 0px; }
+.emoji-1F392 { background-position: -7980px 0px; }
+.emoji-1F393 { background-position: -8000px 0px; }
+.emoji-1F394 { background-position: -8020px 0px; }
+.emoji-1F395 { background-position: -8040px 0px; }
+.emoji-1F396 { background-position: -8060px 0px; }
+.emoji-1F397 { background-position: -8080px 0px; }
+.emoji-1F398 { background-position: -8100px 0px; }
+.emoji-1F399 { background-position: -8120px 0px; }
+.emoji-1F39A { background-position: -8140px 0px; }
+.emoji-1F39B { background-position: -8160px 0px; }
+.emoji-1F39C { background-position: -8180px 0px; }
+.emoji-1F39D { background-position: -8200px 0px; }
+.emoji-1F39E { background-position: -8220px 0px; }
+.emoji-1F39F { background-position: -8240px 0px; }
+.emoji-1F3A0 { background-position: -8260px 0px; }
+.emoji-1F3A1 { background-position: -8280px 0px; }
+.emoji-1F3A2 { background-position: -8300px 0px; }
+.emoji-1F3A3 { background-position: -8320px 0px; }
+.emoji-1F3A4 { background-position: -8340px 0px; }
+.emoji-1F3A5 { background-position: -8360px 0px; }
+.emoji-1F3A6 { background-position: -8380px 0px; }
+.emoji-1F3A7 { background-position: -8400px 0px; }
+.emoji-1F3A8 { background-position: -8420px 0px; }
+.emoji-1F3A9 { background-position: -8440px 0px; }
+.emoji-1F3AA { background-position: -8460px 0px; }
+.emoji-1F3AB { background-position: -8480px 0px; }
+.emoji-1F3AC { background-position: -8500px 0px; }
+.emoji-1F3AD { background-position: -8520px 0px; }
+.emoji-1F3AE { background-position: -8540px 0px; }
+.emoji-1F3AF { background-position: -8560px 0px; }
+.emoji-1F3B0 { background-position: -8580px 0px; }
+.emoji-1F3B1 { background-position: -8600px 0px; }
+.emoji-1F3B2 { background-position: -8620px 0px; }
+.emoji-1F3B3 { background-position: -8640px 0px; }
+.emoji-1F3B4 { background-position: -8660px 0px; }
+.emoji-1F3B5 { background-position: -8680px 0px; }
+.emoji-1F3B6 { background-position: -8700px 0px; }
+.emoji-1F3B7 { background-position: -8720px 0px; }
+.emoji-1F3B8 { background-position: -8740px 0px; }
+.emoji-1F3B9 { background-position: -8760px 0px; }
+.emoji-1F3BA { background-position: -8780px 0px; }
+.emoji-1F3BB { background-position: -8800px 0px; }
+.emoji-1F3BC { background-position: -8820px 0px; }
+.emoji-1F3BD { background-position: -8840px 0px; }
+.emoji-1F3BE { background-position: -8860px 0px; }
+.emoji-1F3BF { background-position: -8880px 0px; }
+.emoji-1F3C0 { background-position: -8900px 0px; }
+.emoji-1F3C1 { background-position: -8920px 0px; }
+.emoji-1F3C2 { background-position: -8940px 0px; }
+.emoji-1F3C3 { background-position: -8960px 0px; }
+.emoji-1F3C4 { background-position: -8980px 0px; }
+.emoji-1F3C5 { background-position: -9000px 0px; }
+.emoji-1F3C6 { background-position: -9020px 0px; }
+.emoji-1F3C7 { background-position: -9040px 0px; }
+.emoji-1F3C8 { background-position: -9060px 0px; }
+.emoji-1F3C9 { background-position: -9080px 0px; }
+.emoji-1F3CA { background-position: -9100px 0px; }
+.emoji-1F3CB { background-position: -9120px 0px; }
+.emoji-1F3CC { background-position: -9140px 0px; }
+.emoji-1F3CD { background-position: -9160px 0px; }
+.emoji-1F3CE { background-position: -9180px 0px; }
+.emoji-1F3D4 { background-position: -9200px 0px; }
+.emoji-1F3D5 { background-position: -9220px 0px; }
+.emoji-1F3D6 { background-position: -9240px 0px; }
+.emoji-1F3D7 { background-position: -9260px 0px; }
+.emoji-1F3D8 { background-position: -9280px 0px; }
+.emoji-1F3D9 { background-position: -9300px 0px; }
+.emoji-1F3DA { background-position: -9320px 0px; }
+.emoji-1F3DB { background-position: -9340px 0px; }
+.emoji-1F3DC { background-position: -9360px 0px; }
+.emoji-1F3DD { background-position: -9380px 0px; }
+.emoji-1F3DE { background-position: -9400px 0px; }
+.emoji-1F3DF { background-position: -9420px 0px; }
+.emoji-1F3E0 { background-position: -9440px 0px; }
+.emoji-1F3E1 { background-position: -9460px 0px; }
+.emoji-1F3E2 { background-position: -9480px 0px; }
+.emoji-1F3E3 { background-position: -9500px 0px; }
+.emoji-1F3E4 { background-position: -9520px 0px; }
+.emoji-1F3E5 { background-position: -9540px 0px; }
+.emoji-1F3E6 { background-position: -9560px 0px; }
+.emoji-1F3E7 { background-position: -9580px 0px; }
+.emoji-1F3E8 { background-position: -9600px 0px; }
+.emoji-1F3E9 { background-position: -9620px 0px; }
+.emoji-1F3EA { background-position: -9640px 0px; }
+.emoji-1F3EB { background-position: -9660px 0px; }
+.emoji-1F3EC { background-position: -9680px 0px; }
+.emoji-1F3ED { background-position: -9700px 0px; }
+.emoji-1F3EE { background-position: -9720px 0px; }
+.emoji-1F3EF { background-position: -9740px 0px; }
+.emoji-1F3F0 { background-position: -9760px 0px; }
+.emoji-1F3F1 { background-position: -9780px 0px; }
+.emoji-1F3F2 { background-position: -9800px 0px; }
+.emoji-1F3F3 { background-position: -9820px 0px; }
+.emoji-1F3F4 { background-position: -9840px 0px; }
+.emoji-1F3F5 { background-position: -9860px 0px; }
+.emoji-1F3F6 { background-position: -9880px 0px; }
+.emoji-1F3F7 { background-position: -9900px 0px; }
+.emoji-1F400 { background-position: -9920px 0px; }
+.emoji-1F401 { background-position: -9940px 0px; }
+.emoji-1F402 { background-position: -9960px 0px; }
+.emoji-1F403 { background-position: -9980px 0px; }
+.emoji-1F404 { background-position: -10000px 0px; }
+.emoji-1F405 { background-position: -10020px 0px; }
+.emoji-1F406 { background-position: -10040px 0px; }
+.emoji-1F407 { background-position: -10060px 0px; }
+.emoji-1F408 { background-position: -10080px 0px; }
+.emoji-1F409 { background-position: -10100px 0px; }
+.emoji-1F40A { background-position: -10120px 0px; }
+.emoji-1F40B { background-position: -10140px 0px; }
+.emoji-1F40C { background-position: -10160px 0px; }
+.emoji-1F40D { background-position: -10180px 0px; }
+.emoji-1F40E { background-position: -10200px 0px; }
+.emoji-1F40F { background-position: -10220px 0px; }
+.emoji-1F410 { background-position: -10240px 0px; }
+.emoji-1F411 { background-position: -10260px 0px; }
+.emoji-1F412 { background-position: -10280px 0px; }
+.emoji-1F413 { background-position: -10300px 0px; }
+.emoji-1F414 { background-position: -10320px 0px; }
+.emoji-1F415 { background-position: -10340px 0px; }
+.emoji-1F416 { background-position: -10360px 0px; }
+.emoji-1F417 { background-position: -10380px 0px; }
+.emoji-1F418 { background-position: -10400px 0px; }
+.emoji-1F419 { background-position: -10420px 0px; }
+.emoji-1F41A { background-position: -10440px 0px; }
+.emoji-1F41B { background-position: -10460px 0px; }
+.emoji-1F41C { background-position: -10480px 0px; }
+.emoji-1F41D { background-position: -10500px 0px; }
+.emoji-1F41E { background-position: -10520px 0px; }
+.emoji-1F41F { background-position: -10540px 0px; }
+.emoji-1F420 { background-position: -10560px 0px; }
+.emoji-1F421 { background-position: -10580px 0px; }
+.emoji-1F422 { background-position: -10600px 0px; }
+.emoji-1F423 { background-position: -10620px 0px; }
+.emoji-1F424 { background-position: -10640px 0px; }
+.emoji-1F425 { background-position: -10660px 0px; }
+.emoji-1F426 { background-position: -10680px 0px; }
+.emoji-1F427 { background-position: -10700px 0px; }
+.emoji-1F428 { background-position: -10720px 0px; }
+.emoji-1F429 { background-position: -10740px 0px; }
+.emoji-1F42A { background-position: -10760px 0px; }
+.emoji-1F42B { background-position: -10780px 0px; }
+.emoji-1F42C { background-position: -10800px 0px; }
+.emoji-1F42D { background-position: -10820px 0px; }
+.emoji-1F42E { background-position: -10840px 0px; }
+.emoji-1F42F { background-position: -10860px 0px; }
+.emoji-1F430 { background-position: -10880px 0px; }
+.emoji-1F431 { background-position: -10900px 0px; }
+.emoji-1F432 { background-position: -10920px 0px; }
+.emoji-1F433 { background-position: -10940px 0px; }
+.emoji-1F434 { background-position: -10960px 0px; }
+.emoji-1F435 { background-position: -10980px 0px; }
+.emoji-1F436 { background-position: -11000px 0px; }
+.emoji-1F437 { background-position: -11020px 0px; }
+.emoji-1F438 { background-position: -11040px 0px; }
+.emoji-1F439 { background-position: -11060px 0px; }
+.emoji-1F43A { background-position: -11080px 0px; }
+.emoji-1F43B { background-position: -11100px 0px; }
+.emoji-1F43C { background-position: -11120px 0px; }
+.emoji-1F43D { background-position: -11140px 0px; }
+.emoji-1F43E { background-position: -11160px 0px; }
+.emoji-1F43F { background-position: -11180px 0px; }
+.emoji-1F440 { background-position: -11200px 0px; }
+.emoji-1F441 { background-position: -11220px 0px; }
+.emoji-1F442 { background-position: -11240px 0px; }
+.emoji-1F443 { background-position: -11260px 0px; }
+.emoji-1F444 { background-position: -11280px 0px; }
+.emoji-1F445 { background-position: -11300px 0px; }
+.emoji-1F446 { background-position: -11320px 0px; }
+.emoji-1F447 { background-position: -11340px 0px; }
+.emoji-1F448 { background-position: -11360px 0px; }
+.emoji-1F449 { background-position: -11380px 0px; }
+.emoji-1F44A { background-position: -11400px 0px; }
+.emoji-1F44B { background-position: -11420px 0px; }
+.emoji-1F44C { background-position: -11440px 0px; }
+.emoji-1F44D { background-position: -11460px 0px; }
+.emoji-1F44E { background-position: -11480px 0px; }
+.emoji-1F44F { background-position: -11500px 0px; }
+.emoji-1F450 { background-position: -11520px 0px; }
+.emoji-1F451 { background-position: -11540px 0px; }
+.emoji-1F452 { background-position: -11560px 0px; }
+.emoji-1F453 { background-position: -11580px 0px; }
+.emoji-1F454 { background-position: -11600px 0px; }
+.emoji-1F455 { background-position: -11620px 0px; }
+.emoji-1F456 { background-position: -11640px 0px; }
+.emoji-1F457 { background-position: -11660px 0px; }
+.emoji-1F458 { background-position: -11680px 0px; }
+.emoji-1F459 { background-position: -11700px 0px; }
+.emoji-1F45A { background-position: -11720px 0px; }
+.emoji-1F45B { background-position: -11740px 0px; }
+.emoji-1F45C { background-position: -11760px 0px; }
+.emoji-1F45D { background-position: -11780px 0px; }
+.emoji-1F45E { background-position: -11800px 0px; }
+.emoji-1F45F { background-position: -11820px 0px; }
+.emoji-1F460 { background-position: -11840px 0px; }
+.emoji-1F461 { background-position: -11860px 0px; }
+.emoji-1F462 { background-position: -11880px 0px; }
+.emoji-1F463 { background-position: -11900px 0px; }
+.emoji-1F464 { background-position: -11920px 0px; }
+.emoji-1F465 { background-position: -11940px 0px; }
+.emoji-1F466 { background-position: -11960px 0px; }
+.emoji-1F467 { background-position: -11980px 0px; }
+.emoji-1F468 { background-position: -12000px 0px; }
+.emoji-1F468-1F468-1F466 { background-position: -12020px 0px; }
+.emoji-1F468-1F468-1F466-1F466 { background-position: -12040px 0px; }
+.emoji-1F468-1F468-1F467 { background-position: -12060px 0px; }
+.emoji-1F468-1F468-1F467-1F466 { background-position: -12080px 0px; }
+.emoji-1F468-1F468-1F467-1F467 { background-position: -12100px 0px; }
+.emoji-1F468-1F469-1F466-1F466 { background-position: -12120px 0px; }
+.emoji-1F468-1F469-1F467 { background-position: -12140px 0px; }
+.emoji-1F468-1F469-1F467-1F466 { background-position: -12160px 0px; }
+.emoji-1F468-1F469-1F467-1F467 { background-position: -12180px 0px; }
+.emoji-1F468-2764-1F468 { background-position: -12200px 0px; }
+.emoji-1F468-2764-1F48B-1F468 { background-position: -12220px 0px; }
+.emoji-1F469 { background-position: -12240px 0px; }
+.emoji-1F469-1F469-1F466 { background-position: -12260px 0px; }
+.emoji-1F469-1F469-1F466-1F466 { background-position: -12280px 0px; }
+.emoji-1F469-1F469-1F467 { background-position: -12300px 0px; }
+.emoji-1F469-1F469-1F467-1F466 { background-position: -12320px 0px; }
+.emoji-1F469-1F469-1F467-1F467 { background-position: -12340px 0px; }
+.emoji-1F469-2764-1F469 { background-position: -12360px 0px; }
+.emoji-1F469-2764-1F48B-1F469 { background-position: -12380px 0px; }
+.emoji-1F46A { background-position: -12400px 0px; }
+.emoji-1F46B { background-position: -12420px 0px; }
+.emoji-1F46C { background-position: -12440px 0px; }
+.emoji-1F46D { background-position: -12460px 0px; }
+.emoji-1F46E { background-position: -12480px 0px; }
+.emoji-1F46F { background-position: -12500px 0px; }
+.emoji-1F470 { background-position: -12520px 0px; }
+.emoji-1F471 { background-position: -12540px 0px; }
+.emoji-1F472 { background-position: -12560px 0px; }
+.emoji-1F473 { background-position: -12580px 0px; }
+.emoji-1F474 { background-position: -12600px 0px; }
+.emoji-1F475 { background-position: -12620px 0px; }
+.emoji-1F476 { background-position: -12640px 0px; }
+.emoji-1F477 { background-position: -12660px 0px; }
+.emoji-1F478 { background-position: -12680px 0px; }
+.emoji-1F479 { background-position: -12700px 0px; }
+.emoji-1F47A { background-position: -12720px 0px; }
+.emoji-1F47B { background-position: -12740px 0px; }
+.emoji-1F47C { background-position: -12760px 0px; }
+.emoji-1F47D { background-position: -12780px 0px; }
+.emoji-1F47E { background-position: -12800px 0px; }
+.emoji-1F47F { background-position: -12820px 0px; }
+.emoji-1F480 { background-position: -12840px 0px; }
+.emoji-1F481 { background-position: -12860px 0px; }
+.emoji-1F482 { background-position: -12880px 0px; }
+.emoji-1F483 { background-position: -12900px 0px; }
+.emoji-1F484 { background-position: -12920px 0px; }
+.emoji-1F485 { background-position: -12940px 0px; }
+.emoji-1F486 { background-position: -12960px 0px; }
+.emoji-1F487 { background-position: -12980px 0px; }
+.emoji-1F488 { background-position: -13000px 0px; }
+.emoji-1F489 { background-position: -13020px 0px; }
+.emoji-1F48A { background-position: -13040px 0px; }
+.emoji-1F48B { background-position: -13060px 0px; }
+.emoji-1F48C { background-position: -13080px 0px; }
+.emoji-1F48D { background-position: -13100px 0px; }
+.emoji-1F48E { background-position: -13120px 0px; }
+.emoji-1F48F { background-position: -13140px 0px; }
+.emoji-1F490 { background-position: -13160px 0px; }
+.emoji-1F491 { background-position: -13180px 0px; }
+.emoji-1F492 { background-position: -13200px 0px; }
+.emoji-1F493 { background-position: -13220px 0px; }
+.emoji-1F494 { background-position: -13240px 0px; }
+.emoji-1F495 { background-position: -13260px 0px; }
+.emoji-1F496 { background-position: -13280px 0px; }
+.emoji-1F497 { background-position: -13300px 0px; }
+.emoji-1F498 { background-position: -13320px 0px; }
+.emoji-1F499 { background-position: -13340px 0px; }
+.emoji-1F49A { background-position: -13360px 0px; }
+.emoji-1F49B { background-position: -13380px 0px; }
+.emoji-1F49C { background-position: -13400px 0px; }
+.emoji-1F49D { background-position: -13420px 0px; }
+.emoji-1F49E { background-position: -13440px 0px; }
+.emoji-1F49F { background-position: -13460px 0px; }
+.emoji-1F4A0 { background-position: -13480px 0px; }
+.emoji-1F4A1 { background-position: -13500px 0px; }
+.emoji-1F4A2 { background-position: -13520px 0px; }
+.emoji-1F4A3 { background-position: -13540px 0px; }
+.emoji-1F4A4 { background-position: -13560px 0px; }
+.emoji-1F4A5 { background-position: -13580px 0px; }
+.emoji-1F4A6 { background-position: -13600px 0px; }
+.emoji-1F4A7 { background-position: -13620px 0px; }
+.emoji-1F4A8 { background-position: -13640px 0px; }
+.emoji-1F4A9 { background-position: -13660px 0px; }
+.emoji-1F4AA { background-position: -13680px 0px; }
+.emoji-1F4AB { background-position: -13700px 0px; }
+.emoji-1F4AC { background-position: -13720px 0px; }
+.emoji-1F4AD { background-position: -13740px 0px; }
+.emoji-1F4AE { background-position: -13760px 0px; }
+.emoji-1F4AF { background-position: -13780px 0px; }
+.emoji-1F4B0 { background-position: -13800px 0px; }
+.emoji-1F4B1 { background-position: -13820px 0px; }
+.emoji-1F4B2 { background-position: -13840px 0px; }
+.emoji-1F4B3 { background-position: -13860px 0px; }
+.emoji-1F4B4 { background-position: -13880px 0px; }
+.emoji-1F4B5 { background-position: -13900px 0px; }
+.emoji-1F4B6 { background-position: -13920px 0px; }
+.emoji-1F4B7 { background-position: -13940px 0px; }
+.emoji-1F4B8 { background-position: -13960px 0px; }
+.emoji-1F4B9 { background-position: -13980px 0px; }
+.emoji-1F4BA { background-position: -14000px 0px; }
+.emoji-1F4BB { background-position: -14020px 0px; }
+.emoji-1F4BC { background-position: -14040px 0px; }
+.emoji-1F4BD { background-position: -14060px 0px; }
+.emoji-1F4BE { background-position: -14080px 0px; }
+.emoji-1F4BF { background-position: -14100px 0px; }
+.emoji-1F4C0 { background-position: -14120px 0px; }
+.emoji-1F4C1 { background-position: -14140px 0px; }
+.emoji-1F4C2 { background-position: -14160px 0px; }
+.emoji-1F4C3 { background-position: -14180px 0px; }
+.emoji-1F4C4 { background-position: -14200px 0px; }
+.emoji-1F4C5 { background-position: -14220px 0px; }
+.emoji-1F4C6 { background-position: -14240px 0px; }
+.emoji-1F4C7 { background-position: -14260px 0px; }
+.emoji-1F4C8 { background-position: -14280px 0px; }
+.emoji-1F4C9 { background-position: -14300px 0px; }
+.emoji-1F4CA { background-position: -14320px 0px; }
+.emoji-1F4CB { background-position: -14340px 0px; }
+.emoji-1F4CC { background-position: -14360px 0px; }
+.emoji-1F4CD { background-position: -14380px 0px; }
+.emoji-1F4CE { background-position: -14400px 0px; }
+.emoji-1F4CF { background-position: -14420px 0px; }
+.emoji-1F4D0 { background-position: -14440px 0px; }
+.emoji-1F4D1 { background-position: -14460px 0px; }
+.emoji-1F4D2 { background-position: -14480px 0px; }
+.emoji-1F4D3 { background-position: -14500px 0px; }
+.emoji-1F4D4 { background-position: -14520px 0px; }
+.emoji-1F4D5 { background-position: -14540px 0px; }
+.emoji-1F4D6 { background-position: -14560px 0px; }
+.emoji-1F4D7 { background-position: -14580px 0px; }
+.emoji-1F4D8 { background-position: -14600px 0px; }
+.emoji-1F4D9 { background-position: -14620px 0px; }
+.emoji-1F4DA { background-position: -14640px 0px; }
+.emoji-1F4DB { background-position: -14660px 0px; }
+.emoji-1F4DC { background-position: -14680px 0px; }
+.emoji-1F4DD { background-position: -14700px 0px; }
+.emoji-1F4DE { background-position: -14720px 0px; }
+.emoji-1F4DF { background-position: -14740px 0px; }
+.emoji-1F4E0 { background-position: -14760px 0px; }
+.emoji-1F4E1 { background-position: -14780px 0px; }
+.emoji-1F4E2 { background-position: -14800px 0px; }
+.emoji-1F4E3 { background-position: -14820px 0px; }
+.emoji-1F4E4 { background-position: -14840px 0px; }
+.emoji-1F4E5 { background-position: -14860px 0px; }
+.emoji-1F4E6 { background-position: -14880px 0px; }
+.emoji-1F4E7 { background-position: -14900px 0px; }
+.emoji-1F4E8 { background-position: -14920px 0px; }
+.emoji-1F4E9 { background-position: -14940px 0px; }
+.emoji-1F4EA { background-position: -14960px 0px; }
+.emoji-1F4EB { background-position: -14980px 0px; }
+.emoji-1F4EC { background-position: -15000px 0px; }
+.emoji-1F4ED { background-position: -15020px 0px; }
+.emoji-1F4EE { background-position: -15040px 0px; }
+.emoji-1F4EF { background-position: -15060px 0px; }
+.emoji-1F4F0 { background-position: -15080px 0px; }
+.emoji-1F4F1 { background-position: -15100px 0px; }
+.emoji-1F4F2 { background-position: -15120px 0px; }
+.emoji-1F4F3 { background-position: -15140px 0px; }
+.emoji-1F4F4 { background-position: -15160px 0px; }
+.emoji-1F4F5 { background-position: -15180px 0px; }
+.emoji-1F4F6 { background-position: -15200px 0px; }
+.emoji-1F4F7 { background-position: -15220px 0px; }
+.emoji-1F4F8 { background-position: -15240px 0px; }
+.emoji-1F4F9 { background-position: -15260px 0px; }
+.emoji-1F4FA { background-position: -15280px 0px; }
+.emoji-1F4FB { background-position: -15300px 0px; }
+.emoji-1F4FC { background-position: -15320px 0px; }
+.emoji-1F4FD { background-position: -15340px 0px; }
+.emoji-1F4FE { background-position: -15360px 0px; }
+.emoji-1F500 { background-position: -15380px 0px; }
+.emoji-1F501 { background-position: -15400px 0px; }
+.emoji-1F502 { background-position: -15420px 0px; }
+.emoji-1F503 { background-position: -15440px 0px; }
+.emoji-1F504 { background-position: -15460px 0px; }
+.emoji-1F505 { background-position: -15480px 0px; }
+.emoji-1F506 { background-position: -15500px 0px; }
+.emoji-1F507 { background-position: -15520px 0px; }
+.emoji-1F508 { background-position: -15540px 0px; }
+.emoji-1F509 { background-position: -15560px 0px; }
+.emoji-1F50A { background-position: -15580px 0px; }
+.emoji-1F50B { background-position: -15600px 0px; }
+.emoji-1F50C { background-position: -15620px 0px; }
+.emoji-1F50D { background-position: -15640px 0px; }
+.emoji-1F50E { background-position: -15660px 0px; }
+.emoji-1F50F { background-position: -15680px 0px; }
+.emoji-1F510 { background-position: -15700px 0px; }
+.emoji-1F511 { background-position: -15720px 0px; }
+.emoji-1F512 { background-position: -15740px 0px; }
+.emoji-1F513 { background-position: -15760px 0px; }
+.emoji-1F514 { background-position: -15780px 0px; }
+.emoji-1F515 { background-position: -15800px 0px; }
+.emoji-1F516 { background-position: -15820px 0px; }
+.emoji-1F517 { background-position: -15840px 0px; }
+.emoji-1F518 { background-position: -15860px 0px; }
+.emoji-1F519 { background-position: -15880px 0px; }
+.emoji-1F51A { background-position: -15900px 0px; }
+.emoji-1F51B { background-position: -15920px 0px; }
+.emoji-1F51C { background-position: -15940px 0px; }
+.emoji-1F51D { background-position: -15960px 0px; }
+.emoji-1F51E { background-position: -15980px 0px; }
+.emoji-1F51F { background-position: -16000px 0px; }
+.emoji-1F520 { background-position: -16020px 0px; }
+.emoji-1F521 { background-position: -16040px 0px; }
+.emoji-1F522 { background-position: -16060px 0px; }
+.emoji-1F523 { background-position: -16080px 0px; }
+.emoji-1F524 { background-position: -16100px 0px; }
+.emoji-1F525 { background-position: -16120px 0px; }
+.emoji-1F526 { background-position: -16140px 0px; }
+.emoji-1F527 { background-position: -16160px 0px; }
+.emoji-1F528 { background-position: -16180px 0px; }
+.emoji-1F529 { background-position: -16200px 0px; }
+.emoji-1F52A { background-position: -16220px 0px; }
+.emoji-1F52B { background-position: -16240px 0px; }
+.emoji-1F52C { background-position: -16260px 0px; }
+.emoji-1F52D { background-position: -16280px 0px; }
+.emoji-1F52E { background-position: -16300px 0px; }
+.emoji-1F52F { background-position: -16320px 0px; }
+.emoji-1F530 { background-position: -16340px 0px; }
+.emoji-1F531 { background-position: -16360px 0px; }
+.emoji-1F532 { background-position: -16380px 0px; }
+.emoji-1F533 { background-position: -16400px 0px; }
+.emoji-1F534 { background-position: -16420px 0px; }
+.emoji-1F535 { background-position: -16440px 0px; }
+.emoji-1F536 { background-position: -16460px 0px; }
+.emoji-1F537 { background-position: -16480px 0px; }
+.emoji-1F538 { background-position: -16500px 0px; }
+.emoji-1F539 { background-position: -16520px 0px; }
+.emoji-1F53A { background-position: -16540px 0px; }
+.emoji-1F53B { background-position: -16560px 0px; }
+.emoji-1F53C { background-position: -16580px 0px; }
+.emoji-1F53D { background-position: -16600px 0px; }
+.emoji-1F546 { background-position: -16620px 0px; }
+.emoji-1F547 { background-position: -16640px 0px; }
+.emoji-1F548 { background-position: -16660px 0px; }
+.emoji-1F549 { background-position: -16680px 0px; }
+.emoji-1F54A { background-position: -16700px 0px; }
+.emoji-1F550 { background-position: -16720px 0px; }
+.emoji-1F551 { background-position: -16740px 0px; }
+.emoji-1F552 { background-position: -16760px 0px; }
+.emoji-1F553 { background-position: -16780px 0px; }
+.emoji-1F554 { background-position: -16800px 0px; }
+.emoji-1F555 { background-position: -16820px 0px; }
+.emoji-1F556 { background-position: -16840px 0px; }
+.emoji-1F557 { background-position: -16860px 0px; }
+.emoji-1F558 { background-position: -16880px 0px; }
+.emoji-1F559 { background-position: -16900px 0px; }
+.emoji-1F55A { background-position: -16920px 0px; }
+.emoji-1F55B { background-position: -16940px 0px; }
+.emoji-1F55C { background-position: -16960px 0px; }
+.emoji-1F55D { background-position: -16980px 0px; }
+.emoji-1F55E { background-position: -17000px 0px; }
+.emoji-1F55F { background-position: -17020px 0px; }
+.emoji-1F560 { background-position: -17040px 0px; }
+.emoji-1F561 { background-position: -17060px 0px; }
+.emoji-1F562 { background-position: -17080px 0px; }
+.emoji-1F563 { background-position: -17100px 0px; }
+.emoji-1F564 { background-position: -17120px 0px; }
+.emoji-1F565 { background-position: -17140px 0px; }
+.emoji-1F566 { background-position: -17160px 0px; }
+.emoji-1F567 { background-position: -17180px 0px; }
+.emoji-1F568 { background-position: -17200px 0px; }
+.emoji-1F569 { background-position: -17220px 0px; }
+.emoji-1F56A { background-position: -17240px 0px; }
+.emoji-1F56B { background-position: -17260px 0px; }
+.emoji-1F56C { background-position: -17280px 0px; }
+.emoji-1F56D { background-position: -17300px 0px; }
+.emoji-1F56E { background-position: -17320px 0px; }
+.emoji-1F56F { background-position: -17340px 0px; }
+.emoji-1F570 { background-position: -17360px 0px; }
+.emoji-1F571 { background-position: -17380px 0px; }
+.emoji-1F572 { background-position: -17400px 0px; }
+.emoji-1F573 { background-position: -17420px 0px; }
+.emoji-1F574 { background-position: -17440px 0px; }
+.emoji-1F575 { background-position: -17460px 0px; }
+.emoji-1F576 { background-position: -17480px 0px; }
+.emoji-1F577 { background-position: -17500px 0px; }
+.emoji-1F578 { background-position: -17520px 0px; }
+.emoji-1F579 { background-position: -17540px 0px; }
+.emoji-1F57B { background-position: -17560px 0px; }
+.emoji-1F57E { background-position: -17580px 0px; }
+.emoji-1F57F { background-position: -17600px 0px; }
+.emoji-1F581 { background-position: -17620px 0px; }
+.emoji-1F582 { background-position: -17640px 0px; }
+.emoji-1F583 { background-position: -17660px 0px; }
+.emoji-1F585 { background-position: -17680px 0px; }
+.emoji-1F586 { background-position: -17700px 0px; }
+.emoji-1F587 { background-position: -17720px 0px; }
+.emoji-1F588 { background-position: -17740px 0px; }
+.emoji-1F589 { background-position: -17760px 0px; }
+.emoji-1F58A { background-position: -17780px 0px; }
+.emoji-1F58B { background-position: -17800px 0px; }
+.emoji-1F58C { background-position: -17820px 0px; }
+.emoji-1F58D { background-position: -17840px 0px; }
+.emoji-1F58E { background-position: -17860px 0px; }
+.emoji-1F58F { background-position: -17880px 0px; }
+.emoji-1F590 { background-position: -17900px 0px; }
+.emoji-1F591 { background-position: -17920px 0px; }
+.emoji-1F592 { background-position: -17940px 0px; }
+.emoji-1F593 { background-position: -17960px 0px; }
+.emoji-1F594 { background-position: -17980px 0px; }
+.emoji-1F595 { background-position: -18000px 0px; }
+.emoji-1F596 { background-position: -18020px 0px; }
+.emoji-1F597 { background-position: -18040px 0px; }
+.emoji-1F598 { background-position: -18060px 0px; }
+.emoji-1F599 { background-position: -18080px 0px; }
+.emoji-1F59E { background-position: -18100px 0px; }
+.emoji-1F59F { background-position: -18120px 0px; }
+.emoji-1F5A5 { background-position: -18140px 0px; }
+.emoji-1F5A6 { background-position: -18160px 0px; }
+.emoji-1F5A7 { background-position: -18180px 0px; }
+.emoji-1F5A8 { background-position: -18200px 0px; }
+.emoji-1F5A9 { background-position: -18220px 0px; }
+.emoji-1F5AA { background-position: -18240px 0px; }
+.emoji-1F5AB { background-position: -18260px 0px; }
+.emoji-1F5AD { background-position: -18280px 0px; }
+.emoji-1F5AE { background-position: -18300px 0px; }
+.emoji-1F5AF { background-position: -18320px 0px; }
+.emoji-1F5B2 { background-position: -18340px 0px; }
+.emoji-1F5B3 { background-position: -18360px 0px; }
+.emoji-1F5B4 { background-position: -18380px 0px; }
+.emoji-1F5B8 { background-position: -18400px 0px; }
+.emoji-1F5B9 { background-position: -18420px 0px; }
+.emoji-1F5BC { background-position: -18440px 0px; }
+.emoji-1F5BD { background-position: -18460px 0px; }
+.emoji-1F5BE { background-position: -18480px 0px; }
+.emoji-1F5C0 { background-position: -18500px 0px; }
+.emoji-1F5C1 { background-position: -18520px 0px; }
+.emoji-1F5C2 { background-position: -18540px 0px; }
+.emoji-1F5C3 { background-position: -18560px 0px; }
+.emoji-1F5C4 { background-position: -18580px 0px; }
+.emoji-1F5C6 { background-position: -18600px 0px; }
+.emoji-1F5C7 { background-position: -18620px 0px; }
+.emoji-1F5C9 { background-position: -18640px 0px; }
+.emoji-1F5CA { background-position: -18660px 0px; }
+.emoji-1F5CE { background-position: -18680px 0px; }
+.emoji-1F5CF { background-position: -18700px 0px; }
+.emoji-1F5D0 { background-position: -18720px 0px; }
+.emoji-1F5D1 { background-position: -18740px 0px; }
+.emoji-1F5D2 { background-position: -18760px 0px; }
+.emoji-1F5D3 { background-position: -18780px 0px; }
+.emoji-1F5D4 { background-position: -18800px 0px; }
+.emoji-1F5D8 { background-position: -18820px 0px; }
+.emoji-1F5D9 { background-position: -18840px 0px; }
+.emoji-1F5DC { background-position: -18860px 0px; }
+.emoji-1F5DD { background-position: -18880px 0px; }
+.emoji-1F5DE { background-position: -18900px 0px; }
+.emoji-1F5E0 { background-position: -18920px 0px; }
+.emoji-1F5E1 { background-position: -18940px 0px; }
+.emoji-1F5E2 { background-position: -18960px 0px; }
+.emoji-1F5E3 { background-position: -18980px 0px; }
+.emoji-1F5E8 { background-position: -19000px 0px; }
+.emoji-1F5E9 { background-position: -19020px 0px; }
+.emoji-1F5EA { background-position: -19040px 0px; }
+.emoji-1F5EB { background-position: -19060px 0px; }
+.emoji-1F5EC { background-position: -19080px 0px; }
+.emoji-1F5ED { background-position: -19100px 0px; }
+.emoji-1F5EE { background-position: -19120px 0px; }
+.emoji-1F5EF { background-position: -19140px 0px; }
+.emoji-1F5F0 { background-position: -19160px 0px; }
+.emoji-1F5F1 { background-position: -19180px 0px; }
+.emoji-1F5F2 { background-position: -19200px 0px; }
+.emoji-1F5F3 { background-position: -19220px 0px; }
+.emoji-1F5F4 { background-position: -19240px 0px; }
+.emoji-1F5F5 { background-position: -19260px 0px; }
+.emoji-1F5F8 { background-position: -19280px 0px; }
+.emoji-1F5F9 { background-position: -19300px 0px; }
+.emoji-1F5FA { background-position: -19320px 0px; }
+.emoji-1F5FB { background-position: -19340px 0px; }
+.emoji-1F5FC { background-position: -19360px 0px; }
+.emoji-1F5FD { background-position: -19380px 0px; }
+.emoji-1F5FE { background-position: -19400px 0px; }
+.emoji-1F5FF { background-position: -19420px 0px; }
+.emoji-1F600 { background-position: -19440px 0px; }
+.emoji-1F601 { background-position: -19460px 0px; }
+.emoji-1F602 { background-position: -19480px 0px; }
+.emoji-1F603 { background-position: -19500px 0px; }
+.emoji-1F604 { background-position: -19520px 0px; }
+.emoji-1F605 { background-position: -19540px 0px; }
+.emoji-1F606 { background-position: -19560px 0px; }
+.emoji-1F607 { background-position: -19580px 0px; }
+.emoji-1F608 { background-position: -19600px 0px; }
+.emoji-1F609 { background-position: -19620px 0px; }
+.emoji-1F60A { background-position: -19640px 0px; }
+.emoji-1F60B { background-position: -19660px 0px; }
+.emoji-1F60C { background-position: -19680px 0px; }
+.emoji-1F60D { background-position: -19700px 0px; }
+.emoji-1F60E { background-position: -19720px 0px; }
+.emoji-1F60F { background-position: -19740px 0px; }
+.emoji-1F610 { background-position: -19760px 0px; }
+.emoji-1F611 { background-position: -19780px 0px; }
+.emoji-1F612 { background-position: -19800px 0px; }
+.emoji-1F613 { background-position: -19820px 0px; }
+.emoji-1F614 { background-position: -19840px 0px; }
+.emoji-1F615 { background-position: -19860px 0px; }
+.emoji-1F616 { background-position: -19880px 0px; }
+.emoji-1F617 { background-position: -19900px 0px; }
+.emoji-1F618 { background-position: -19920px 0px; }
+.emoji-1F619 { background-position: -19940px 0px; }
+.emoji-1F61A { background-position: -19960px 0px; }
+.emoji-1F61B { background-position: -19980px 0px; }
+.emoji-1F61C { background-position: -20000px 0px; }
+.emoji-1F61D { background-position: -20020px 0px; }
+.emoji-1F61E { background-position: -20040px 0px; }
+.emoji-1F61F { background-position: -20060px 0px; }
+.emoji-1F620 { background-position: -20080px 0px; }
+.emoji-1F621 { background-position: -20100px 0px; }
+.emoji-1F622 { background-position: -20120px 0px; }
+.emoji-1F623 { background-position: -20140px 0px; }
+.emoji-1F624 { background-position: -20160px 0px; }
+.emoji-1F625 { background-position: -20180px 0px; }
+.emoji-1F626 { background-position: -20200px 0px; }
+.emoji-1F627 { background-position: -20220px 0px; }
+.emoji-1F628 { background-position: -20240px 0px; }
+.emoji-1F629 { background-position: -20260px 0px; }
+.emoji-1F62A { background-position: -20280px 0px; }
+.emoji-1F62B { background-position: -20300px 0px; }
+.emoji-1F62C { background-position: -20320px 0px; }
+.emoji-1F62D { background-position: -20340px 0px; }
+.emoji-1F62E { background-position: -20360px 0px; }
+.emoji-1F62F { background-position: -20380px 0px; }
+.emoji-1F630 { background-position: -20400px 0px; }
+.emoji-1F631 { background-position: -20420px 0px; }
+.emoji-1F632 { background-position: -20440px 0px; }
+.emoji-1F633 { background-position: -20460px 0px; }
+.emoji-1F634 { background-position: -20480px 0px; }
+.emoji-1F635 { background-position: -20500px 0px; }
+.emoji-1F636 { background-position: -20520px 0px; }
+.emoji-1F637 { background-position: -20540px 0px; }
+.emoji-1F638 { background-position: -20560px 0px; }
+.emoji-1F639 { background-position: -20580px 0px; }
+.emoji-1F63A { background-position: -20600px 0px; }
+.emoji-1F63B { background-position: -20620px 0px; }
+.emoji-1F63C { background-position: -20640px 0px; }
+.emoji-1F63D { background-position: -20660px 0px; }
+.emoji-1F63E { background-position: -20680px 0px; }
+.emoji-1F63F { background-position: -20700px 0px; }
+.emoji-1F640 { background-position: -20720px 0px; }
+.emoji-1F641 { background-position: -20740px 0px; }
+.emoji-1F642 { background-position: -20760px 0px; }
+.emoji-1F645 { background-position: -20780px 0px; }
+.emoji-1F646 { background-position: -20800px 0px; }
+.emoji-1F647 { background-position: -20820px 0px; }
+.emoji-1F648 { background-position: -20840px 0px; }
+.emoji-1F649 { background-position: -20860px 0px; }
+.emoji-1F64A { background-position: -20880px 0px; }
+.emoji-1F64B { background-position: -20900px 0px; }
+.emoji-1F64C { background-position: -20920px 0px; }
+.emoji-1F64D { background-position: -20940px 0px; }
+.emoji-1F64E { background-position: -20960px 0px; }
+.emoji-1F64F { background-position: -20980px 0px; }
+.emoji-1F680 { background-position: -21000px 0px; }
+.emoji-1F681 { background-position: -21020px 0px; }
+.emoji-1F682 { background-position: -21040px 0px; }
+.emoji-1F683 { background-position: -21060px 0px; }
+.emoji-1F684 { background-position: -21080px 0px; }
+.emoji-1F685 { background-position: -21100px 0px; }
+.emoji-1F686 { background-position: -21120px 0px; }
+.emoji-1F687 { background-position: -21140px 0px; }
+.emoji-1F688 { background-position: -21160px 0px; }
+.emoji-1F689 { background-position: -21180px 0px; }
+.emoji-1F68A { background-position: -21200px 0px; }
+.emoji-1F68B { background-position: -21220px 0px; }
+.emoji-1F68C { background-position: -21240px 0px; }
+.emoji-1F68D { background-position: -21260px 0px; }
+.emoji-1F68E { background-position: -21280px 0px; }
+.emoji-1F68F { background-position: -21300px 0px; }
+.emoji-1F690 { background-position: -21320px 0px; }
+.emoji-1F691 { background-position: -21340px 0px; }
+.emoji-1F692 { background-position: -21360px 0px; }
+.emoji-1F693 { background-position: -21380px 0px; }
+.emoji-1F694 { background-position: -21400px 0px; }
+.emoji-1F695 { background-position: -21420px 0px; }
+.emoji-1F696 { background-position: -21440px 0px; }
+.emoji-1F697 { background-position: -21460px 0px; }
+.emoji-1F698 { background-position: -21480px 0px; }
+.emoji-1F699 { background-position: -21500px 0px; }
+.emoji-1F69A { background-position: -21520px 0px; }
+.emoji-1F69B { background-position: -21540px 0px; }
+.emoji-1F69C { background-position: -21560px 0px; }
+.emoji-1F69D { background-position: -21580px 0px; }
+.emoji-1F69E { background-position: -21600px 0px; }
+.emoji-1F69F { background-position: -21620px 0px; }
+.emoji-1F6A0 { background-position: -21640px 0px; }
+.emoji-1F6A1 { background-position: -21660px 0px; }
+.emoji-1F6A2 { background-position: -21680px 0px; }
+.emoji-1F6A3 { background-position: -21700px 0px; }
+.emoji-1F6A4 { background-position: -21720px 0px; }
+.emoji-1F6A5 { background-position: -21740px 0px; }
+.emoji-1F6A6 { background-position: -21760px 0px; }
+.emoji-1F6A7 { background-position: -21780px 0px; }
+.emoji-1F6A8 { background-position: -21800px 0px; }
+.emoji-1F6A9 { background-position: -21820px 0px; }
+.emoji-1F6AA { background-position: -21840px 0px; }
+.emoji-1F6AB { background-position: -21860px 0px; }
+.emoji-1F6AC { background-position: -21880px 0px; }
+.emoji-1F6AD { background-position: -21900px 0px; }
+.emoji-1F6AE { background-position: -21920px 0px; }
+.emoji-1F6AF { background-position: -21940px 0px; }
+.emoji-1F6B0 { background-position: -21960px 0px; }
+.emoji-1F6B1 { background-position: -21980px 0px; }
+.emoji-1F6B2 { background-position: -22000px 0px; }
+.emoji-1F6B3 { background-position: -22020px 0px; }
+.emoji-1F6B4 { background-position: -22040px 0px; }
+.emoji-1F6B5 { background-position: -22060px 0px; }
+.emoji-1F6B6 { background-position: -22080px 0px; }
+.emoji-1F6B7 { background-position: -22100px 0px; }
+.emoji-1F6B8 { background-position: -22120px 0px; }
+.emoji-1F6B9 { background-position: -22140px 0px; }
+.emoji-1F6BA { background-position: -22160px 0px; }
+.emoji-1F6BB { background-position: -22180px 0px; }
+.emoji-1F6BC { background-position: -22200px 0px; }
+.emoji-1F6BD { background-position: -22220px 0px; }
+.emoji-1F6BE { background-position: -22240px 0px; }
+.emoji-1F6BF { background-position: -22260px 0px; }
+.emoji-1F6C0 { background-position: -22280px 0px; }
+.emoji-1F6C1 { background-position: -22300px 0px; }
+.emoji-1F6C2 { background-position: -22320px 0px; }
+.emoji-1F6C3 { background-position: -22340px 0px; }
+.emoji-1F6C4 { background-position: -22360px 0px; }
+.emoji-1F6C5 { background-position: -22380px 0px; }
+.emoji-1F6C6 { background-position: -22400px 0px; }
+.emoji-1F6C7 { background-position: -22420px 0px; }
+.emoji-1F6C8 { background-position: -22440px 0px; }
+.emoji-1F6C9 { background-position: -22460px 0px; }
+.emoji-1F6CA { background-position: -22480px 0px; }
+.emoji-1F6CB { background-position: -22500px 0px; }
+.emoji-1F6CC { background-position: -22520px 0px; }
+.emoji-1F6CD { background-position: -22540px 0px; }
+.emoji-1F6CE { background-position: -22560px 0px; }
+.emoji-1F6CF { background-position: -22580px 0px; }
+.emoji-1F6E0 { background-position: -22600px 0px; }
+.emoji-1F6E1 { background-position: -22620px 0px; }
+.emoji-1F6E2 { background-position: -22640px 0px; }
+.emoji-1F6E3 { background-position: -22660px 0px; }
+.emoji-1F6E4 { background-position: -22680px 0px; }
+.emoji-1F6E5 { background-position: -22700px 0px; }
+.emoji-1F6E6 { background-position: -22720px 0px; }
+.emoji-1F6E7 { background-position: -22740px 0px; }
+.emoji-1F6E8 { background-position: -22760px 0px; }
+.emoji-1F6E9 { background-position: -22780px 0px; }
+.emoji-1F6EA { background-position: -22800px 0px; }
+.emoji-1F6EB { background-position: -22820px 0px; }
+.emoji-1F6EC { background-position: -22840px 0px; }
+.emoji-1F6F0 { background-position: -22860px 0px; }
+.emoji-1F6F1 { background-position: -22880px 0px; }
+.emoji-1F6F2 { background-position: -22900px 0px; }
+.emoji-1F6F3 { background-position: -22920px 0px; }
+.emoji-203C { background-position: -22940px 0px; }
+.emoji-2049 { background-position: -22960px 0px; }
+.emoji-2122 { background-position: -22980px 0px; }
+.emoji-2139 { background-position: -23000px 0px; }
+.emoji-2194 { background-position: -23020px 0px; }
+.emoji-2195 { background-position: -23040px 0px; }
+.emoji-2196 { background-position: -23060px 0px; }
+.emoji-2197 { background-position: -23080px 0px; }
+.emoji-2198 { background-position: -23100px 0px; }
+.emoji-2199 { background-position: -23120px 0px; }
+.emoji-21A9 { background-position: -23140px 0px; }
+.emoji-21AA { background-position: -23160px 0px; }
+.emoji-231A { background-position: -23180px 0px; }
+.emoji-231B { background-position: -23200px 0px; }
+.emoji-23E9 { background-position: -23220px 0px; }
+.emoji-23EA { background-position: -23240px 0px; }
+.emoji-23EB { background-position: -23260px 0px; }
+.emoji-23EC { background-position: -23280px 0px; }
+.emoji-23F0 { background-position: -23300px 0px; }
+.emoji-23F3 { background-position: -23320px 0px; }
+.emoji-24C2 { background-position: -23340px 0px; }
+.emoji-25AA { background-position: -23360px 0px; }
+.emoji-25AB { background-position: -23380px 0px; }
+.emoji-25B6 { background-position: -23400px 0px; }
+.emoji-25C0 { background-position: -23420px 0px; }
+.emoji-25FB { background-position: -23440px 0px; }
+.emoji-25FC { background-position: -23460px 0px; }
+.emoji-25FD { background-position: -23480px 0px; }
+.emoji-25FE { background-position: -23500px 0px; }
+.emoji-2600 { background-position: -23520px 0px; }
+.emoji-2601 { background-position: -23540px 0px; }
+.emoji-260E { background-position: -23560px 0px; }
+.emoji-2611 { background-position: -23580px 0px; }
+.emoji-2614 { background-position: -23600px 0px; }
+.emoji-2615 { background-position: -23620px 0px; }
+.emoji-261D { background-position: -23640px 0px; }
+.emoji-263A { background-position: -23660px 0px; }
+.emoji-2648 { background-position: -23680px 0px; }
+.emoji-2649 { background-position: -23700px 0px; }
+.emoji-264A { background-position: -23720px 0px; }
+.emoji-264B { background-position: -23740px 0px; }
+.emoji-264C { background-position: -23760px 0px; }
+.emoji-264D { background-position: -23780px 0px; }
+.emoji-264E { background-position: -23800px 0px; }
+.emoji-264F { background-position: -23820px 0px; }
+.emoji-2650 { background-position: -23840px 0px; }
+.emoji-2651 { background-position: -23860px 0px; }
+.emoji-2652 { background-position: -23880px 0px; }
+.emoji-2653 { background-position: -23900px 0px; }
+.emoji-2660 { background-position: -23920px 0px; }
+.emoji-2663 { background-position: -23940px 0px; }
+.emoji-2665 { background-position: -23960px 0px; }
+.emoji-2666 { background-position: -23980px 0px; }
+.emoji-2668 { background-position: -24000px 0px; }
+.emoji-267B { background-position: -24020px 0px; }
+.emoji-267F { background-position: -24040px 0px; }
+.emoji-2693 { background-position: -24060px 0px; }
+.emoji-26A0 { background-position: -24080px 0px; }
+.emoji-26A1 { background-position: -24100px 0px; }
+.emoji-26AA { background-position: -24120px 0px; }
+.emoji-26AB { background-position: -24140px 0px; }
+.emoji-26BD { background-position: -24160px 0px; }
+.emoji-26BE { background-position: -24180px 0px; }
+.emoji-26C4 { background-position: -24200px 0px; }
+.emoji-26C5 { background-position: -24220px 0px; }
+.emoji-26CE { background-position: -24240px 0px; }
+.emoji-26D4 { background-position: -24260px 0px; }
+.emoji-26EA { background-position: -24280px 0px; }
+.emoji-26F2 { background-position: -24300px 0px; }
+.emoji-26F3 { background-position: -24320px 0px; }
+.emoji-26F5 { background-position: -24340px 0px; }
+.emoji-26FA { background-position: -24360px 0px; }
+.emoji-26FD { background-position: -24380px 0px; }
+.emoji-2702 { background-position: -24400px 0px; }
+.emoji-2705 { background-position: -24420px 0px; }
+.emoji-2708 { background-position: -24440px 0px; }
+.emoji-2709 { background-position: -24460px 0px; }
+.emoji-270A { background-position: -24480px 0px; }
+.emoji-270B { background-position: -24500px 0px; }
+.emoji-270C { background-position: -24520px 0px; }
+.emoji-270F { background-position: -24540px 0px; }
+.emoji-2712 { background-position: -24560px 0px; }
+.emoji-2714 { background-position: -24580px 0px; }
+.emoji-2716 { background-position: -24600px 0px; }
+.emoji-2728 { background-position: -24620px 0px; }
+.emoji-2733 { background-position: -24640px 0px; }
+.emoji-2734 { background-position: -24660px 0px; }
+.emoji-2744 { background-position: -24680px 0px; }
+.emoji-2747 { background-position: -24700px 0px; }
+.emoji-274C { background-position: -24720px 0px; }
+.emoji-274E { background-position: -24740px 0px; }
+.emoji-2753 { background-position: -24760px 0px; }
+.emoji-2754 { background-position: -24780px 0px; }
+.emoji-2755 { background-position: -24800px 0px; }
+.emoji-2757 { background-position: -24820px 0px; }
+.emoji-2764 { background-position: -24840px 0px; }
+.emoji-2795 { background-position: -24860px 0px; }
+.emoji-2796 { background-position: -24880px 0px; }
+.emoji-2797 { background-position: -24900px 0px; }
+.emoji-27A1 { background-position: -24920px 0px; }
+.emoji-27B0 { background-position: -24940px 0px; }
+.emoji-27BF { background-position: -24960px 0px; }
+.emoji-2934 { background-position: -24980px 0px; }
+.emoji-2935 { background-position: -25000px 0px; }
+.emoji-2B05 { background-position: -25020px 0px; }
+.emoji-2B06 { background-position: -25040px 0px; }
+.emoji-2B07 { background-position: -25060px 0px; }
+.emoji-2B1B { background-position: -25080px 0px; }
+.emoji-2B1C { background-position: -25100px 0px; }
+.emoji-2B50 { background-position: -25120px 0px; }
+.emoji-2B55 { background-position: -25140px 0px; }
+.emoji-3030 { background-position: -25160px 0px; }
+.emoji-303D { background-position: -25180px 0px; }
+.emoji-3297 { background-position: -25200px 0px; }
+.emoji-3299 { background-position: -25220px 0px; }
\ No newline at end of file
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index 4cf1a28c459f33a277d855500e51a8837cad64cf..d86259f93fbcfe672cf0fab9d84d03ad196a21fe 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -75,16 +75,15 @@
 
 .common-note-form {
   margin: 0;
-  background: #F7F8FA;
+  background: #fff;
   padding: $gl-padding;
   margin-left: -$gl-padding;
   margin-right: -$gl-padding;
-  border-top: 1px solid $border-color;
   margin-bottom: -$gl-padding;
 }
 
 .note-form-actions {
-  background: #F9F9F9;
+  background: #fff;
 
   .note-form-option {
     margin-top: 8px;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 4dff87abaa4ec2d556c336014544c62cefcebf25..72b0ed29a698b1d2e95b79c8c654f61784a2165f 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -128,7 +128,7 @@ ul.notes {
     }
 
     &:last-child {
-      border-bottom: none;
+      border-bottom: 1px solid $border-color;
     }
   }
 }
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 2ded32dba123746e77ff1d319852ac21f3ad1755..99006b9f5d1b3e47806e7730e63bc5b4b96db25b 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -335,6 +335,36 @@ ul.nav.nav-projects-tabs {
   }
 }
 
+.top-area {
+  border-bottom: 1px solid #EEE;
+
+  ul.left-top-menu {
+    display: inline-block;
+    width: 50%;
+    margin-bottom: 0px;
+    border-bottom: none;
+  }
+
+  .projects-search-form {
+    width: 50%;
+    display: inline-block;
+    float: right;
+    padding-top: 7px;
+    text-align: right;
+
+    .btn-green {
+      margin-top: -2px;
+      margin-left: 10px;
+    }
+  }
+
+  @media (max-width: $screen-xs-max) {
+    .projects-search-form {
+      padding-top: 15px;
+    }
+  }
+}
+
 .fork-namespaces {
   .fork-thumbnail {
     text-align: center;
@@ -412,11 +442,18 @@ pre.light-well {
 
 .projects-search-form {
   margin: -$gl-padding;
-  background-color: #f8fafc;
   padding: $gl-padding;
   margin-bottom: 0px;
-  border-top: 1px solid #e7e9ed;
-  border-bottom: 1px solid #e7e9ed;
+
+  input {
+    display: inline-block;
+    width: calc(100% - 151px);
+  }
+
+  .btn {
+    display: inline-block;
+    width: 135px;
+  }
 }
 
 .git-empty {
diff --git a/app/controllers/admin/identities_controller.rb b/app/controllers/admin/identities_controller.rb
index d28614731f9211cf66fb1ef3af5e76a2c3fe972d..e383fe38ea68352c5ba172a396a978f805a27527 100644
--- a/app/controllers/admin/identities_controller.rb
+++ b/app/controllers/admin/identities_controller.rb
@@ -1,6 +1,21 @@
 class Admin::IdentitiesController < Admin::ApplicationController
   before_action :user
-  before_action :identity, except: :index
+  before_action :identity, except: [:index, :new, :create]
+
+  def new
+    @identity = Identity.new
+  end
+
+  def create
+    @identity = Identity.new(identity_params)
+    @identity.user_id = user.id
+
+    if @identity.save
+      redirect_to admin_user_identities_path(@user), notice: 'User identity was successfully created.'
+    else
+      render :new
+    end
+  end
 
   def index
     @identities = @user.identities
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 0d182e8eb04d92fded1152636459a9be917d82c1..01e2e7b2f980c3f544f7e34cc977923666ef5cf3 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -10,6 +10,7 @@ class ApplicationController < ActionController::Base
 
   before_action :authenticate_user_from_token!
   before_action :authenticate_user!
+  before_action :validate_user_service_ticket!
   before_action :reject_blocked!
   before_action :check_password_expiration
   before_action :ldap_security_check
@@ -202,6 +203,20 @@ class ApplicationController < ActionController::Base
     end
   end
 
+  def validate_user_service_ticket!
+    return unless signed_in? && session[:service_tickets]
+
+    valid = session[:service_tickets].all? do |provider, ticket|
+      Gitlab::OAuth::Session.valid?(provider, ticket)
+    end
+
+    unless valid
+      session[:service_tickets] = nil
+      sign_out current_user
+      redirect_to new_user_session_path
+    end
+  end
+
   def check_password_expiration
     if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now  && !current_user.ldap_user?
       redirect_to new_profile_password_path and return
diff --git a/app/controllers/ci/lints_controller.rb b/app/controllers/ci/lints_controller.rb
index 7ed78ff8e989492249818665fc8ae1a7c6ea5784..e782a51e7eb93dce8ca605dd2236cd749a272119 100644
--- a/app/controllers/ci/lints_controller.rb
+++ b/app/controllers/ci/lints_controller.rb
@@ -19,8 +19,10 @@ module Ci
       @error = e.message
       @status = false
     rescue
-      @error = "Undefined error"
+      @error = 'Undefined error'
       @status = false
+    ensure
+      render :show
     end
   end
 end
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index f809fa7500a09fd37a547238198987e80501f5ea..4cad98b8e98bdd7044ed442ea0622418e14f016a 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -1,6 +1,6 @@
 class OmniauthCallbacksController < Devise::OmniauthCallbacksController
 
-  protect_from_forgery except: [:kerberos, :saml]
+  protect_from_forgery except: [:kerberos, :saml, :cas3]
 
   Gitlab.config.omniauth.providers.each do |provider|
     define_method provider['name'] do
@@ -42,6 +42,14 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
     render 'errors/omniauth_error', layout: "errors", status: 422
   end
 
+  def cas3
+    ticket = params['ticket']
+    if ticket
+      handle_service_ticket oauth['provider'], ticket
+    end
+    handle_omniauth
+  end
+
   private
 
   def handle_omniauth
@@ -84,6 +92,12 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
     redirect_to new_user_session_path
   end
 
+  def handle_service_ticket provider, ticket
+    Gitlab::OAuth::Session.create provider, ticket
+    session[:service_tickets] ||= {}
+    session[:service_tickets][provider] = ticket
+  end
+
   def oauth
     @oauth ||= request.env['omniauth.auth']
   end
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index ee705f32e814b7994d01cf4971fac1cd3a90ec2a..6f1e186d4084d4eb4729a74b989785c48115ad6a 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -139,7 +139,6 @@ class Projects::NotesController < Projects::ApplicationController
         discussion_id: note.discussion_id,
         html: note_to_html(note),
         award: note.is_award,
-        emoji_path: note.is_award ? view_context.image_url(::AwardEmoji.path_to_emoji_image(note.note)) : "",
         note: note.note,
         discussion_html: note_to_discussion_html(note),
         discussion_with_diff_html: note_to_discussion_with_diff_html(note)
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 6e7590260ff0e3bfa6f88fc706e54054b0b14c32..8b2577aebe1e537dc368cac0598bfc1154650c30 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -1,5 +1,5 @@
 class Projects::ServicesController < Projects::ApplicationController
-  ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :api_version, :subdomain,
+  ALLOWED_PARAMS = [:title, :token, :type, :active, :api_key, :api_url, :api_version, :subdomain,
                     :room, :recipients, :project_url, :webhook,
                     :user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
                     :build_key, :server, :teamcity_url, :drone_url, :build_type,
@@ -10,7 +10,8 @@ class Projects::ServicesController < Projects::ApplicationController
                     :notify_only_broken_builds, :add_pusher,
                     :send_from_committer_email, :disable_diffs, :external_wiki_url,
                     :notify, :color,
-                    :server_host, :server_port, :default_irc_uri, :enable_ssl_verification]
+                    :server_host, :server_port, :default_irc_uri, :enable_ssl_verification,
+                    :jira_issue_transition_id]
 
   # Parameters to ignore if no value is specified
   FILTER_BLANK_PARAMS = [:password]
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 1f0f6aeeac2cf0a1a57c5f37731a05ec582ed2f0..2f893c40209c12649d28347448883b5eb0043c74 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -98,11 +98,13 @@ module IssuesHelper
     end.sort.to_sentence(last_word_connector: ', or ')
   end
 
-  def url_to_emoji(name)
-    emoji_path = ::AwardEmoji.path_to_emoji_image(name)
-    url_to_image(emoji_path)
-  rescue StandardError
-    ""
+  def emoji_icon(name, unicode = nil)
+    unicode ||= Emoji.emoji_filename(name)
+
+    content_tag :div, "",
+      class: "icon emoji-icon emoji-#{unicode}",
+      "data-emoji" => name,
+      "data-unicode-name" => unicode
   end
 
   def emoji_author_list(notes, current_user)
@@ -113,10 +115,6 @@ module IssuesHelper
     list.join(", ")
   end
 
-  def emoji_list
-    ::AwardEmoji::EMOJI_LIST
-  end
-
   def note_active_class(notes, current_user)
     if current_user && notes.pluck(:author_id).include?(current_user.id)
       "active"
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 6c32647594d5a0642d70f52ed57cb93b5989badb..1dd07a2a2204b0368671f57e3b89b05b82432477 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -27,7 +27,16 @@ module MergeRequestsHelper
   end
 
   def ci_build_details_path(merge_request)
-    merge_request.source_project.ci_service.build_page(merge_request.last_commit.sha, merge_request.source_branch)
+    build_url = merge_request.source_project.ci_service.build_page(merge_request.last_commit.sha, merge_request.source_branch)
+    return nil unless build_url
+
+    parsed_url = URI.parse(build_url)
+
+    unless parsed_url.userinfo.blank?
+      parsed_url.userinfo = ''
+    end
+
+    parsed_url.to_s
   end
 
   def merge_path_description(merge_request, separator)
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 777817e24aa0f7615b08cde7adec1616d3aad86c..77ba612548a11785dbb214bbd2e8026e9c879946 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -105,6 +105,14 @@ module ProjectsHelper
     end
   end
 
+  def user_max_access_in_project(user_id, project)
+    level = project.team.max_member_access(user_id)
+
+    if level
+      Gitlab::Access.options_with_owner.key(level)
+    end
+  end
+
   private
 
   def get_project_nav_tabs(project, current_user)
@@ -277,14 +285,6 @@ module ProjectsHelper
     end
   end
 
-  def user_max_access_in_project(user, project)
-    level = project.team.max_member_access(user)
-
-    if level
-      Gitlab::Access.options_with_owner.key(level)
-    end
-  end
-
   def leave_project_message(project)
     "Are you sure you want to leave \"#{project.name}\" project?"
   end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 1f4e8b3ef24c8d4dddc370fa0a5edf6fc4fdf585..724429e755855737ed3c66b75f5224e8f2fa0425 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -134,4 +134,8 @@ class ApplicationSetting < ActiveRecord::Base
       /x)
     self.restricted_signup_domains.reject! { |d| d.empty? }
   end
+
+  def runners_registration_token
+    ensure_runners_registration_token!
+  end
 end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 6d9cdb95295d395186ab3b6e5597b4bad8e08d79..7b89fe069ea158061ee29c98d3f0c2fcc2e13c84 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -135,6 +135,16 @@ module Ci
       predefined_variables + yaml_variables + project_variables + trigger_variables
     end
 
+    def merge_request
+      merge_requests = MergeRequest.includes(:merge_request_diff)
+                                   .where(source_branch: ref, source_project_id: commit.gl_project_id)
+                                   .reorder(iid: :asc)
+
+      merge_requests.find do |merge_request|
+        merge_request.commits.any? { |ci| ci.id == commit.sha }
+      end
+    end
+
     def project
       commit.project
     end
@@ -170,7 +180,8 @@ module Ci
 
     def extract_coverage(text, regex)
       begin
-        matches = text.gsub(Regexp.new(regex)).to_a.last
+        matches = text.scan(Regexp.new(regex)).last
+        matches = matches.last if matches.kind_of?(Array)
         coverage = matches.gsub(/\d+(\.\d+)?/).first
 
         if coverage.present?
diff --git a/app/models/concerns/participable.rb b/app/models/concerns/participable.rb
index 808d80b0530fb417885ae5cf2524d77bbd0c09bc..fc6f83b918b4929240bd85acfb9906af1ea51b1a 100644
--- a/app/models/concerns/participable.rb
+++ b/app/models/concerns/participable.rb
@@ -37,7 +37,7 @@ module Participable
 
   # Be aware that this method makes a lot of sql queries.
   # Save result into variable if you are going to reuse it inside same request
-  def participants(current_user = self.author, load_lazy_references: true)
+  def participants(current_user = self.author)
     participants =
       Gitlab::ReferenceExtractor.lazily do
         self.class.participant_attrs.flat_map do |attr|
diff --git a/app/models/concerns/token_authenticatable.rb b/app/models/concerns/token_authenticatable.rb
index 488ff8c31b7d9e23f1a0232269c6ef518967fa92..885deaf78d2d480b0ad416a04f0d3a970ed45833 100644
--- a/app/models/concerns/token_authenticatable.rb
+++ b/app/models/concerns/token_authenticatable.rb
@@ -18,15 +18,16 @@ module TokenAuthenticatable
 
       define_method("ensure_#{token_field}") do
         current_token = read_attribute(token_field)
-        if current_token.blank?
-          write_attribute(token_field, generate_token_for(token_field))
-        else
-          current_token
-        end
+        current_token.blank? ? write_new_token(token_field) : current_token
+      end
+
+      define_method("ensure_#{token_field}!") do
+        send("reset_#{token_field}!") if read_attribute(token_field).blank?
+        read_attribute(token_field)
       end
 
       define_method("reset_#{token_field}!") do
-        write_attribute(token_field, generate_token_for(token_field))
+        write_new_token(token_field)
         save!
       end
     end
@@ -34,7 +35,12 @@ module TokenAuthenticatable
 
   private
 
-  def generate_token_for(token_field)
+  def write_new_token(token_field)
+    new_token = generate_token(token_field)
+    write_attribute(token_field, new_token)
+  end
+
+  def generate_token(token_field)
     loop do
       token = Devise.friendly_token
       break token unless self.class.unscoped.find_by(token_field => token)
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 4571d7f0ee10bed4688e06811318984dd779fa6f..80ecd15077f188864ad3719fa8bb223492cc5b58 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -86,7 +86,7 @@ class Issue < ActiveRecord::Base
   def referenced_merge_requests
     Gitlab::ReferenceExtractor.lazily do
       [self, *notes].flat_map do |note|
-        note.all_references(load_lazy_references: false).merge_requests
+        note.all_references.merge_requests
       end
     end.sort_by(&:iid)
   end
diff --git a/app/models/jira_issue.rb b/app/models/jira_issue.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5b21aac5e43c5902e67e0ed1af87aa155ae9fcce
--- /dev/null
+++ b/app/models/jira_issue.rb
@@ -0,0 +1,2 @@
+class JiraIssue < ExternalIssue
+end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index d7430d36c41c53a3ac62253ca0a065e656ad396a..ac25d38eb6338be998c93c6711e54c806df77a47 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -335,7 +335,7 @@ class MergeRequest < ActiveRecord::Base
       issues = commits.flat_map { |c| c.closes_issues(current_user) }
       issues.push(*Gitlab::ClosingIssueExtractor.new(project, current_user).
                   closed_by_message(description))
-      issues.uniq
+      issues.uniq(&:id)
     else
       []
     end
diff --git a/app/models/project.rb b/app/models/project.rb
index 13fd383237c7684ad124708c44282c76e422de56..b28a7ca429c32a954a0472e09b9f63f50cec6b30 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -499,6 +499,10 @@ class Project < ActiveRecord::Base
     @ci_service ||= ci_services.find(&:activated?)
   end
 
+  def jira_tracker?
+    issues_tracker.to_param == 'jira'
+  end
+
   def avatar_type
     unless self.avatar.image?
       self.errors.add :avatar, 'only images allowed'
@@ -799,6 +803,10 @@ class Project < ActiveRecord::Base
     false
   end
 
+  def jira_tracker_active?
+    jira_tracker? && jira_service.active
+  end
+
   def ci_commit(sha)
     ci_commits.find_by(sha: sha)
   end
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index d73182d40ac6235cee37728b063bf8365a4247f4..b64d97ce75dc5d2ebd90f410812b527c88a6d11d 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -18,6 +18,11 @@
 #  note_events           :boolean          default(TRUE), not null
 #
 
+# TODO(ayufan): The GitLabCiService is deprecated and the type should be removed when the database entries are removed
 class GitlabCiService < CiService
-  # this is no longer used
+  # We override the active accessor to always make GitLabCiService disabled
+  # Otherwise the GitLabCiService can be picked, but should never be since it's deprecated
+  def active
+    false
+  end
 end
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index 35e30b1cb0b76370baa3d5c714afbde0f2269209..e216f406e1cb672187d8dadfd2f91a375b878143 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -19,9 +19,24 @@
 #
 
 class JiraService < IssueTrackerService
+  include HTTParty
   include Gitlab::Application.routes.url_helpers
 
-  prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+  DEFAULT_API_VERSION = 2
+
+  prop_accessor :username, :password, :api_url, :jira_issue_transition_id,
+                :title, :description, :project_url, :issues_url, :new_issue_url
+
+  before_validation :set_api_url, :set_jira_issue_transition_id
+
+  before_update :reset_password
+
+  def reset_password
+    # don't reset the password if a new one is provided
+    if api_url_changed? && !password_touched?
+      self.password = nil
+    end
+  end
 
   def help
     line1 = 'Setting `project_url`, `issues_url` and `new_issue_url` will '\
@@ -54,4 +69,228 @@ class JiraService < IssueTrackerService
   def to_param
     'jira'
   end
+
+  def fields
+    super.push(
+      { type: 'text', name: 'api_url', placeholder: 'https://jira.example.com/rest/api/2' },
+      { type: 'text', name: 'username', placeholder: '' },
+      { type: 'password', name: 'password', placeholder: '' },
+      { type: 'text', name: 'jira_issue_transition_id', placeholder: '2' }
+    )
+  end
+
+  def execute(push, issue = nil)
+    if issue.nil?
+      # No specific issue, that means
+      # we just want to test settings
+      test_settings
+    else
+      close_issue(push, issue)
+    end
+  end
+
+  def create_cross_reference_note(mentioned, noteable, author)
+    issue_name = mentioned.id
+    project = self.project
+    noteable_name = noteable.class.name.underscore.downcase
+    noteable_id = if noteable.is_a?(Commit)
+                    noteable.id
+                  else
+                    noteable.iid
+                  end
+
+    entity_url = build_entity_url(noteable_name.to_sym, noteable_id)
+
+    data = {
+      user: {
+        name: author.name,
+        url: resource_url(user_path(author)),
+      },
+      project: {
+        name: project.path_with_namespace,
+        url: resource_url(namespace_project_path(project.namespace, project))
+      },
+      entity: {
+        name: noteable_name.humanize.downcase,
+        url: entity_url
+      }
+    }
+
+    add_comment(data, issue_name)
+  end
+
+  def test_settings
+    result = JiraService.get(
+      jira_api_test_url,
+      headers: {
+        'Content-Type' => 'application/json',
+        'Authorization' => "Basic #{auth}"
+      }
+    )
+
+    case result.code
+    when 201, 200
+      Rails.logger.info("#{self.class.name} SUCCESS #{result.code}: Successfully connected to #{api_url}.")
+      true
+    else
+      Rails.logger.info("#{self.class.name} ERROR #{result.code}: #{result.parsed_response}")
+      false
+    end
+  rescue Errno::ECONNREFUSED => e
+    Rails.logger.info "#{self.class.name} ERROR: #{e.message}. API URL: #{api_url}."
+    false
+  end
+
+  private
+
+  def build_api_url_from_project_url
+    server = URI(project_url)
+    default_ports = [["http",80],["https",443]].include?([server.scheme,server.port])
+    server_url = "#{server.scheme}://#{server.host}"
+    server_url.concat(":#{server.port}") unless default_ports
+    "#{server_url}/rest/api/#{DEFAULT_API_VERSION}"
+  rescue
+    "" # looks like project URL was not valid
+  end
+
+  def set_api_url
+    self.api_url = build_api_url_from_project_url if self.api_url.blank?
+  end
+
+  def set_jira_issue_transition_id
+    self.jira_issue_transition_id ||= "2"
+  end
+
+  def close_issue(entity, issue)
+    commit_id = if entity.is_a?(Commit)
+                  entity.id
+                elsif entity.is_a?(MergeRequest)
+                  entity.last_commit.id
+                end
+    commit_url = build_entity_url(:commit, commit_id)
+
+    # Depending on the JIRA project's workflow, a comment during transition
+    # may or may not be allowed. Split the operation in to two calls so the
+    # comment always works.
+    transition_issue(issue)
+    add_issue_solved_comment(issue, commit_id, commit_url)
+  end
+
+  def transition_issue(issue)
+    message = {
+      transition: {
+        id: jira_issue_transition_id
+      }
+    }
+    send_message(close_issue_url(issue.iid), message.to_json)
+  end
+
+  def add_issue_solved_comment(issue, commit_id, commit_url)
+    comment = {
+      body: "Issue solved with [#{commit_id}|#{commit_url}]."
+    }
+
+    send_message(comment_url(issue.iid), comment.to_json)
+  end
+
+  def add_comment(data, issue_name)
+    url = comment_url(issue_name)
+    user_name = data[:user][:name]
+    user_url = data[:user][:url]
+    entity_name = data[:entity][:name]
+    entity_url = data[:entity][:url]
+    project_name = data[:project][:name]
+
+    message = {
+      body: "[#{user_name}|#{user_url}] mentioned this issue in [a #{entity_name} of #{project_name}|#{entity_url}]."
+    }
+
+    unless existing_comment?(issue_name, message[:body])
+      send_message(url, message.to_json)
+    end
+  end
+
+
+  def auth
+    require 'base64'
+    Base64.urlsafe_encode64("#{self.username}:#{self.password}")
+  end
+
+  def send_message(url, message)
+    result = JiraService.post(
+      url,
+      body: message,
+      headers: {
+        'Content-Type' => 'application/json',
+        'Authorization' => "Basic #{auth}"
+      }
+    )
+
+    message = case result.code
+              when 201, 200, 204
+                "#{self.class.name} SUCCESS #{result.code}: Successfully posted to #{url}."
+              when 401
+                "#{self.class.name} ERROR 401: Unauthorized. Check the #{self.username} credentials and JIRA access permissions and try again."
+              else
+                "#{self.class.name} ERROR #{result.code}: #{result.parsed_response}"
+              end
+
+    Rails.logger.info(message)
+    message
+  rescue URI::InvalidURIError, Errno::ECONNREFUSED => e
+    Rails.logger.info "#{self.class.name} ERROR: #{e.message}. Hostname: #{url}."
+  end
+
+  def existing_comment?(issue_name, new_comment)
+    result = JiraService.get(
+      comment_url(issue_name),
+      headers: {
+        'Content-Type' => 'application/json',
+        'Authorization' => "Basic #{auth}"
+      }
+    )
+
+    case result.code
+    when 201, 200
+      existing_comments = JSON.parse(result.body)['comments']
+
+      if existing_comments.present?
+        return existing_comments.map { |comment| comment['body'].include?(new_comment) }.any?
+      end
+    end
+
+    false
+  rescue JSON::ParserError
+    false
+  end
+
+  def resource_url(resource)
+    "#{Settings.gitlab['url'].chomp("/")}#{resource}"
+  end
+
+  def build_entity_url(entity_name, entity_id)
+    resource_url(
+      polymorphic_url(
+        [
+          self.project.namespace.becomes(Namespace),
+          self.project,
+          entity_name
+        ],
+        id: entity_id,
+        routing_type: :path
+      )
+    )
+  end
+
+  def close_issue_url(issue_name)
+    "#{self.api_url}/issue/#{issue_name}/transitions"
+  end
+
+  def comment_url(issue_name)
+    "#{self.api_url}/issue/#{issue_name}/comment"
+  end
+
+  def jira_api_test_url
+    "#{self.api_url}/myself"
+  end
 end
diff --git a/app/models/user.rb b/app/models/user.rb
index e0ce091c54ebf06a1687294ada0ab67d8453cd60..df87f3b79bd66735c96a65eda8298d1c7fabcfe5 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -26,6 +26,7 @@
 #  bio                        :string(255)
 #  failed_attempts            :integer          default(0)
 #  locked_at                  :datetime
+#  unlock_token               :string(255)
 #  username                   :string(255)
 #  can_create_group           :boolean          default(TRUE), not null
 #  can_create_team            :boolean          default(TRUE), not null
diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb
index 3d85f97b7e5a357e4c8188053e5b521f5fe156a1..a1a20e476819df6d507312edd8667da35a4a0016 100644
--- a/app/services/issues/close_service.rb
+++ b/app/services/issues/close_service.rb
@@ -1,6 +1,11 @@
 module Issues
   class CloseService < Issues::BaseService
     def execute(issue, commit = nil)
+      if project.jira_tracker? && project.jira_service.active
+        project.jira_service.execute(commit, issue)
+        return issue
+      end
+
       if project.default_issues_tracker? && issue.close
         event_service.close_issue(issue, current_user)
         create_note(issue, commit)
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 6975b2ee55b55f2a2c713799cc37221188b91f3c..98a71cbf1ada720854f7627ce00206d709b5206d 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -241,9 +241,14 @@ class SystemNoteService
       note_options.merge!(noteable: noteable)
     end
 
-    create_note(note_options)
+    if noteable.is_a?(ExternalIssue)
+      noteable.project.issues_tracker.create_cross_reference_note(noteable, mentioner, author)
+    else
+      create_note(note_options)
+    end
   end
 
+
   def self.cross_reference?(note_text)
     note_text.start_with?(cross_reference_note_prefix)
   end
@@ -259,7 +264,7 @@ class SystemNoteService
   #
   # Returns Boolean
   def self.cross_reference_disallowed?(noteable, mentioner)
-    return true if noteable.is_a?(ExternalIssue)
+    return true if noteable.is_a?(ExternalIssue) && !noteable.project.jira_tracker_active?
     return false unless mentioner.is_a?(MergeRequest)
     return false unless noteable.is_a?(Commit)
 
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 8657d2c71fe83eae1a39a5b521ca922acbbdca4c..531247e9148565a0e3b475a435c5a5bd709858bb 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -79,6 +79,10 @@
         GitLab API
         %span.pull-right
           = API::API::version
+      %p
+        Git
+        %span.pull-right
+          = Gitlab::Git.version
       %p
         Ruby
         %span.pull-right
diff --git a/app/views/admin/identities/index.html.haml b/app/views/admin/identities/index.html.haml
index 8358a14445b24c20eaa0e7edc661f42fd1187c32..741d111fb7d40c3db8e27f3127784eefc652e345 100644
--- a/app/views/admin/identities/index.html.haml
+++ b/app/views/admin/identities/index.html.haml
@@ -1,6 +1,7 @@
 - page_title "Identities", @user.name, "Users"
 = render 'admin/users/head'
 
+= link_to 'New Identity', new_admin_user_identity_path, class: 'pull-right btn btn-new'
 - if @identities.present?
   .table-holder
     %table.table
diff --git a/app/views/admin/identities/new.html.haml b/app/views/admin/identities/new.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..e30bf0ef0ee23fd90f03946282c2ecf315e4b316
--- /dev/null
+++ b/app/views/admin/identities/new.html.haml
@@ -0,0 +1,4 @@
+- page_title "New Identity"
+%h3.page-title New identity
+%hr
+= render 'form'
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index c5fb3c95506e2ea52b4bcc2ae8b17d78525747d3..c407972cd0875dd3c4b329acd7c649216eccf0f5 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -3,7 +3,7 @@
     To register a new runner you should enter the following registration token.
     With this token the runner will request a unique runner token and use that for future communication.
     Registration token is
-    %code{ id: 'runners-token' } #{current_application_settings.ensure_runners_registration_token}
+    %code{ id: 'runners-token' } #{current_application_settings.runners_registration_token}
 
 .bs-callout.clearfix
   .pull-left
diff --git a/app/views/ci/lints/_create.html.haml b/app/views/ci/lints/_create.html.haml
index 77f78caa8d886ac22324b676429399862314e8e3..f7875e68b7e668745e10e238e7c7d1899b820a66 100644
--- a/app/views/ci/lints/_create.html.haml
+++ b/app/views/ci/lints/_create.html.haml
@@ -41,5 +41,3 @@
     %i.fa.fa-remove.incorrect-syntax
   %b Error:
   = @error
-
-    
diff --git a/app/views/ci/lints/create.js.haml b/app/views/ci/lints/create.js.haml
deleted file mode 100644
index a96c0b11b6e06cb89baed0c3730f8c028883f675..0000000000000000000000000000000000000000
--- a/app/views/ci/lints/create.js.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-:plain
-  $(".results").html("#{escape_javascript(render "create")}")
\ No newline at end of file
diff --git a/app/views/ci/lints/show.html.haml b/app/views/ci/lints/show.html.haml
index fb9057e4882069229f557c83af711e1dbc719ab3..a144c43be477a260ccdad87422f114634285f135 100644
--- a/app/views/ci/lints/show.html.haml
+++ b/app/views/ci/lints/show.html.haml
@@ -1,27 +1,17 @@
 %h2 Check your .gitlab-ci.yml
 %hr
 
-= form_tag ci_lint_path, method: :post, remote: true do
-  .control-group
-    = label_tag :content, "Content of .gitlab-ci.yml", class: 'control-label'
-    .controls
-      = text_area_tag :content, nil, class: 'form-control span1', rows: 7, require: true
+.row
+  = form_tag ci_lint_path, method: :post do
+    .form-group
+      = label_tag :content, 'Content of .gitlab-ci.yml', class: 'control-label text-nowrap'
+      .col-sm-12
+        = text_area_tag :content, nil, class: 'form-control span1', rows: 7, require: true
+    .col-sm-12
+      .pull-left.prepend-top-10
+        = submit_tag 'Validate', class: 'btn btn-success submit-yml'
 
-  .control-group.clearfix
-    .controls.pull-left.prepend-top-10
-      = submit_tag "Validate", class: 'btn btn-success submit-yml'
-
-
-%p.text-center.loading
-  %i.fa.fa-refresh.fa-spin
-
-.results.prepend-top-20
-
-:javascript
-  $(".loading").hide();
-  $('form').bind('ajax:beforeSend', function() {
-    $(".loading").show();
-  });
-  $('form').bind('ajax:complete', function() {
-    $(".loading").hide();
-  });
+.row.prepend-top-20
+  .col-sm-12
+    .results
+      = render partial: 'create' if defined?(@status)
diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml
index 2e77afb7525923d48e085aaaf47d61cc39c1e781..f4a3e3162bf5da1eeaecc7d4b6b56f290a94f427 100644
--- a/app/views/dashboard/_projects_head.html.haml
+++ b/app/views/dashboard/_projects_head.html.haml
@@ -1,13 +1,20 @@
 = content_for :flash_message do
   = render 'shared/project_limit'
+.top-area
+  %ul.left-top-menu
+    = nav_link(page: [dashboard_projects_path, root_path]) do
+      = link_to dashboard_projects_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
+        Your Projects
+    = nav_link(page: starred_dashboard_projects_path) do
+      = link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do
+        Starred Projects
+    = nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path], html_options: { class: 'hidden-xs' }) do
+      = link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do
+        Explore Projects
 
-%ul.center-top-menu
-  = nav_link(page: [dashboard_projects_path, root_path]) do
-    = link_to dashboard_projects_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do
-      Your Projects
-  = nav_link(page: starred_dashboard_projects_path) do
-    = link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do
-      Starred Projects
-  = nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path], html_options: { class: 'hidden-xs' }) do
-    = link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do
-      Explore Projects
+  .projects-search-form  
+    = search_field_tag :filter_projects, nil, placeholder: 'Filter by name...', class: 'projects-list-filter form-control hidden-xs', spellcheck: false
+    - if current_user.can_create_project?
+      = link_to new_project_path, class: 'btn btn-green' do
+        %i.fa.fa-plus
+        New Project
diff --git a/app/views/dashboard/projects/_projects.html.haml b/app/views/dashboard/projects/_projects.html.haml
index 81a5909e2d2ac5f01430f000bf0512306320cedd..cea9ffcc748ad866e87d924b1785da19b94f10e4 100644
--- a/app/views/dashboard/projects/_projects.html.haml
+++ b/app/views/dashboard/projects/_projects.html.haml
@@ -1,11 +1,3 @@
 .projects-list-holder
-  .projects-search-form
-    .input-group
-      = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
-      - if current_user.can_create_project?
-        %span.input-group-btn
-          = link_to new_project_path, class: 'btn btn-green' do
-            %i.fa.fa-plus
-            New Project
 
   = render 'shared/projects/list', projects: @projects, ci: true
diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb
deleted file mode 100644
index 79d6c761d8fce48f4bf9e757392c13cff3ecf16d..0000000000000000000000000000000000000000
--- a/app/views/devise/mailer/unlock_instructions.html.erb
+++ /dev/null
@@ -1,7 +0,0 @@
-<p>Hello <%= @resource.email %>!</p>
-
-<p>Your account has been locked due to an excessive amount of unsuccessful sign in attempts.</p>
-
-<p>Click the link below to unlock your account:</p>
-
-<p><%= link_to 'Unlock your account', unlock_url(@resource, unlock_token: @token) %></p>
diff --git a/app/views/devise/mailer/unlock_instructions.html.haml b/app/views/devise/mailer/unlock_instructions.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..52b327e20c5f71dec4a876fa2585ebfc921066c1
--- /dev/null
+++ b/app/views/devise/mailer/unlock_instructions.html.haml
@@ -0,0 +1,10 @@
+%p
+Hello #{@resource.name}!
+
+%p
+  Your GitLab account has been locked due to an excessive amount of unsuccessful
+  sign in attempts. Your account will automatically unlock in
+  = time_ago_in_words(Devise.unlock_in.from_now)
+  or you may click the link below to unlock now.
+
+%p= link_to 'Unlock your account', unlock_url(@resource, unlock_token: @token)
diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb
deleted file mode 100644
index f9277d1673fe35c0ab7a80339cb20c1159871823..0000000000000000000000000000000000000000
--- a/app/views/devise/unlocks/new.html.erb
+++ /dev/null
@@ -1,12 +0,0 @@
-<h2>Resend unlock instructions</h2>
-
-<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
-  <%= devise_error_messages! %>
-
-  <div><%= f.label :email %><br />
-  <%= f.email_field :email %></div>
-
-  <div><%= f.submit "Resend unlock instructions" %></div>
-<% end %>
-
-<%= render partial: "devise/shared/links" %>
diff --git a/app/views/devise/unlocks/new.html.haml b/app/views/devise/unlocks/new.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..49c087c0646e42112a6266225eb0ecf0aa225039
--- /dev/null
+++ b/app/views/devise/unlocks/new.html.haml
@@ -0,0 +1,14 @@
+.login-box
+  .login-heading
+    %h3 Resend unlock email
+  .login-body
+    = form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f|
+      .devise-errors
+        = devise_error_messages!
+      .clearfix.append-bottom-20
+        = f.email_field :email, class: 'form-control', placeholder: 'Email', autofocus: 'autofocus', autocapitalize: 'off', autocorrect: 'off'
+      .clearfix
+        = f.submit 'Resend unlock instructions', class: 'btn btn-success'
+
+.clearfix.prepend-top-20
+  = render 'devise/shared/sign_in_link'
diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml
index 11d69977ef9e03b87fd2c5bb113cd131651fb1d7..bbafc08435af438ca1f99bd3948208d73138910f 100644
--- a/app/views/groups/_projects.html.haml
+++ b/app/views/groups/_projects.html.haml
@@ -1,5 +1,5 @@
-.panel.panel-default.projects-list-holder
-  .panel-heading.clearfix
+.projects-list-holder
+  .projects-search-form
     .input-group
       = search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
       - if can? current_user, :create_projects, @group
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index dc8e81323a63daf43f7e527162142042b3a37111..c2c7c581b3eff57c5ad3d522f86bc77544a72709 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -5,37 +5,47 @@
   - if current_user
     = auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity")
 
-.dashboard
-  .header-with-avatar.clearfix
-    = image_tag group_icon(@group), class: "avatar group-avatar s90"
-    %h3
-      = @group.name
-    .username
-      @#{@group.path}
-    - if @group.description.present?
-      .description
-        = markdown(@group.description, pipeline: :description)
-  %hr
-
-  = render 'shared/show_aside'
-
-  - if can?(current_user, :read_group, @group)
-    .row
-      %section.activities.col-md-7
-        .hidden-xs
-          - if current_user
-            = render "events/event_last_push", event: @last_push
-            .pull-right
-              = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn' do
-                %i.fa.fa-rss
-
-            = render 'shared/event_filter'
-            %hr
-
-        .content_list
-        = spinner
-      %aside.side.col-md-5
-        = render "projects", projects: @projects
-  - else
-    %p
-      This group does not have public projects
+.cover-block
+  .avatar-holder
+    = link_to group_icon(@group), target: '_blank' do
+      = image_tag group_icon(@group), class: "avatar group-avatar s90"
+  .cover-title
+    = @group.name
+
+  .cover-desc.username
+    @#{@group.path}
+
+  - if @group.description.present?
+    .cover-desc.description
+      = markdown(@group.description, pipeline: :description)
+
+- if can?(current_user, :read_group, @group)
+  %ul.center-top-menu.no-top
+    %li.active
+      = link_to "#activity", 'data-toggle' => 'tab' do
+        Activity
+    - if @projects.present?
+      %li
+        = link_to "#projects", 'data-toggle' => 'tab' do
+          Projects
+
+  .tab-content
+    .tab-pane.active#activity
+      .gray-content-block.activity-filter-block
+        - if current_user
+          = render "events/event_last_push", event: @last_push
+          .pull-right
+            = link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed", class: 'btn rss-btn' do
+              %i.fa.fa-rss
+
+          = render 'shared/event_filter'
+
+      .content_list
+      = spinner
+
+    .tab-pane#projects
+      = render "projects", projects: @projects
+
+- else
+  %p
+    This group does not have public projects
diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml
index 20a5b6a66e7038d573028777ec9c4c3a457ad9fb..5b7ecce86ab2b9041019e526650a50e45eb124a0 100644
--- a/app/views/projects/builds/show.html.haml
+++ b/app/views/projects/builds/show.html.haml
@@ -7,6 +7,10 @@
     %strong.monospace= link_to @build.commit.short_sha, ci_status_path(@build.commit)
     from
     = link_to @build.ref, namespace_project_commits_path(@project.namespace, @project, @build.ref)
+    - merge_request = @build.merge_request
+    - if merge_request
+      via
+      = link_to "merge request ##{merge_request.iid}", merge_request_path(merge_request)
 
   #up-build-trace
   - if @commit.matrix_for_ref?(@build.ref)
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index 86d3dc546ba879b825c9873d82600b7fbd42a961..dc434cf38c4ab006432903456cfd5dace77a4865 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -1,9 +1,9 @@
 - content_for :note_actions do
   - if can?(current_user, :update_issue, @issue)
     - if @issue.closed?
-      = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-grouped btn-reopen js-note-target-reopen', title: 'Reopen Issue'
+      = link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-reopen js-note-target-reopen', title: 'Reopen Issue'
     - else
-      = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-grouped btn-close js-note-target-close', title: 'Close Issue'
+      = link_to 'Close Issue', issue_path(@issue, issue: {state_event: :close}, status_only: true), method: :put, class: 'btn btn-nr btn-grouped btn-close js-note-target-close', title: 'Close Issue'
 
 #notes
   = render 'projects/notes/notes_with_form'
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 4ca122ba55f7b5acdeb967510f33662463cf768e..99c2970bac74f790a6fbb5b24a259a926278afdb 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -20,14 +20,14 @@
 
     .pull-right
       - if can?(current_user, :create_issue, @project)
-        = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'btn btn-grouped new-issue-link', title: 'New Issue', id: 'new_issue_link' do
+        = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'btn btn-nr btn-grouped new-issue-link btn-success', title: 'New Issue', id: 'new_issue_link' do
           = icon('plus')
           New Issue
       - if can?(current_user, :update_issue, @issue)
-        = link_to 'Reopen', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen Issue'
-        = link_to 'Close', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close Issue'
+        = link_to 'Reopen', issue_path(@issue, issue: {state_event: :reopen}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen Issue'
+        = link_to 'Close', issue_path(@issue, issue: {state_event: :close}, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "btn btn-nr btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close Issue'
 
-        = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'btn btn-grouped issuable-edit' do
+        = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'btn btn-nr btn-grouped issuable-edit' do
           = icon('pencil-square-o')
           Edit
 
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
index 399e9cc1e1b33bb16d5a1eda771935e48bffedc4..bff3c3b283ddf33a3fee9104980120eb62136021 100644
--- a/app/views/projects/merge_requests/_discussion.html.haml
+++ b/app/views/projects/merge_requests/_discussion.html.haml
@@ -1,8 +1,8 @@
 - content_for :note_actions do
   - if can?(current_user, :update_merge_request, @merge_request)
     - if @merge_request.open?
-      = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
+      = link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
     - if @merge_request.closed?
-      = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
+      = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-grouped btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request"
 
 #notes= render "projects/notes/notes_with_form"
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index 473124480ac7c7e75aa03206df02a5536819db10..fc6fb2a0d42f56b243870a06a83d27d722a7d6ee 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -17,9 +17,9 @@
   .issue-btn-group.pull-right
     - if can?(current_user, :update_merge_request, @merge_request)
       - if @merge_request.open?
-        = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: 'btn btn-grouped btn-close', title: 'Close merge request'
-        = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn btn-grouped issuable-edit', id: 'edit_merge_request' do
+        = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: 'btn btn-nr btn-grouped btn-close', title: 'Close merge request'
+        = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn btn-nr btn-grouped issuable-edit', id: 'edit_merge_request' do
           %i.fa.fa-pencil-square-o
           Edit
       - if @merge_request.closed?
-        = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'btn btn-grouped btn-reopen reopen-mr-link', title: 'Reopen merge request'
+        = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'btn btn-nr btn-grouped btn-reopen reopen-mr-link', title: 'Reopen merge request'
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index 88e711ab5341d848e3e76270338819d32e970fab..acb6dc52a8e204f7fecfc7d2f70eeabe844041dc 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -13,6 +13,6 @@
     .error-alert
 
   .note-form-actions.clearfix
-    = f.submit 'Add Comment', class: "btn btn-create comment-btn btn-grouped js-comment-button"
+    = f.submit 'Add Comment', class: "btn btn-nr btn-create comment-btn btn-grouped js-comment-button"
     = yield(:note_actions)
     %a.btn.btn-cancel.js-close-discussion-note-form Cancel
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 9c7a5584da9a1122a09121c940dc26c29da46461..7466a098e24d0ba1e735d307ffc41c17c7a458b2 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -71,7 +71,7 @@
   = render default_project_view
 
 - if current_user
-  - access = user_max_access_in_project(current_user, @project)
+  - access = user_max_access_in_project(current_user.id, @project)
   - if access
     .prepend-top-20.project-footer
       .gray-content-block.footer-block.center
diff --git a/app/views/votes/_votes_block.html.haml b/app/views/votes/_votes_block.html.haml
index 6071f1484c621f05b316a8b23555d66f1835e276..8c660ba16cc67618d1e0e59c80b71cafbbff090c 100644
--- a/app/views/votes/_votes_block.html.haml
+++ b/app/views/votes/_votes_block.html.haml
@@ -1,18 +1,22 @@
 .awards.votes-block
   - votable.notes.awards.grouped_awards.each do |emoji, notes|
     .award{class: (note_active_class(notes, current_user)), title: emoji_author_list(notes, current_user)}
-      .icon{"data-emoji" => "#{emoji}"}
-        = image_tag url_to_emoji(emoji), height: "20px", width: "20px"
+      = emoji_icon(emoji)
       .counter
         = notes.count
 
   - if current_user
-    .dropdown.awards-controls
+    .awards-controls
       %a.add-award{"data-toggle" => "dropdown", "data-target" => "#", "href" => "#"}
         = icon('smile-o')
-      %ul.dropdown-menu.awards-menu
-        - emoji_list.each do |emoji|
-          %li{"data-emoji" => "#{emoji}"}= image_tag url_to_emoji(emoji), height: "20px", width: "20px"
+      .emoji-menu
+        .emoji-menu-content
+          - AwardEmoji.emoji_by_category.each do |category, emojis|
+            %h5= AwardEmoji::CATEGORIES[category]
+            %ul
+              - emojis.each do |emoji|
+                %li
+                  = emoji_icon(emoji["name"], emoji["unicode"])
 
 - if current_user
   :coffeescript
@@ -20,10 +24,16 @@
     noteable_type = "#{votable.class.name.underscore}"
     noteable_id = "#{votable.id}"
     aliases = #{AwardEmoji::ALIASES.to_json}
-    window.awards_handler = new AwardsHandler(post_emoji_url, noteable_type, noteable_id, aliases)
 
-    $(".awards-menu li").click (e)->
-      emoji = $(this).data("emoji")
+    window.awards_handler = new AwardsHandler(
+      post_emoji_url,
+      noteable_type,
+      noteable_id,
+      aliases
+    )
+
+    $(".emoji-menu-content li").click (e)->
+      emoji = $(this).find(".emoji-icon").data("emoji")
       awards_handler.addAward(emoji)
 
     $(".awards").on "click", ".award", (e)->
@@ -31,3 +41,5 @@
       awards_handler.addAward(emoji)
 
     $(".award").tooltip()
+
+    $(".emoji-menu-content").niceScroll({cursorwidth: "7px", autohidemode: false})
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index db378118f8550d9e0589a4f70717f5e3d38b3f1d..db68b5512b8a79e7ec8c8b9cc3f96f0c2df29be7 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -144,6 +144,15 @@ production: &base
     # plain_url: "http://..."     # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon
     # ssl_url:   "https://..."    # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon
 
+  ## Auxiliary jobs
+  # Periodically executed jobs, to self-heal Gitlab, do external synchronizations, etc.
+  # Please read here for more information: https://github.com/ondrejbartas/sidekiq-cron#adding-cron-job
+  cron_jobs:
+    # Flag stuck CI builds as failed
+    stuck_ci_builds_worker:
+      cron: "0 0 * * *"
+
+
   #
   # 2. GitLab CI settings
   # ==========================
@@ -287,6 +296,15 @@ production: &base
     # arguments, followed by optional 'args' which can be either a hash or an array.
     # Documentation for this is available at http://doc.gitlab.com/ce/integration/omniauth.html
     providers:
+      # See omniauth-cas3 for more configuration details
+      # - { name: 'cas3',
+      #     label: 'cas3',
+      #     args: {
+      #             url: 'https://sso.example.com',
+      #             disable_ssl_verification: false,
+      #             login_url: '/cas/login',
+      #             service_validate_url: '/cas/p3/serviceValidate',
+      #             logout_url: '/cas/logout'} }
       # - { name: 'github',
       #     app_id: 'YOUR_APP_ID',
       #     app_secret: 'YOUR_APP_SECRET',
@@ -324,6 +342,10 @@ production: &base
       #       application_name: 'YOUR_APP_NAME',
       #       application_password: 'YOUR_APP_PASSWORD' } }
 
+    # SSO maximum session duration in seconds. Defaults to CAS default of 8 hours.
+    # cas3:
+    #   session_duration: 28800
+
   # Shared file storage settings
   shared:
     # path: /mnt/gitlab # Default: shared
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 63d8ae174365bc7f6613a109a42671745b573191..816cb0c02a91e99756fc1c4d87015fa6dd312589 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -126,6 +126,10 @@ Settings.omniauth['block_auto_created_users'] = true if Settings.omniauth['block
 Settings.omniauth['auto_link_ldap_user'] = false if Settings.omniauth['auto_link_ldap_user'].nil?
 
 Settings.omniauth['providers']  ||= []
+Settings.omniauth['cas3'] ||= Settingslogic.new({})
+Settings.omniauth.cas3['session_duration'] ||= 8.hours
+Settings.omniauth['session_tickets'] ||= Settingslogic.new({})
+Settings.omniauth.session_tickets['cas3'] = 'ticket'
 
 Settings['shared'] ||= Settingslogic.new({})
 Settings.shared['path'] = File.expand_path(Settings.shared['path'] || "shared", Rails.root)
@@ -164,7 +168,7 @@ Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].
 Settings.gitlab['twitter_sharing_enabled'] ||= true if Settings.gitlab['twitter_sharing_enabled'].nil?
 Settings.gitlab['restricted_visibility_levels'] = Settings.send(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
 Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
-Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?))+)' if Settings.gitlab['issue_closing_pattern'].nil?
+Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z]*-\d*))+)' if Settings.gitlab['issue_closing_pattern'].nil?
 Settings.gitlab['default_projects_features'] ||= {}
 Settings.gitlab['webhook_timeout'] ||= 10
 Settings.gitlab['max_attachment_size'] ||= 10
@@ -224,6 +228,15 @@ Settings.gravatar['plain_url']  ||= 'http://www.gravatar.com/avatar/%{hash}?s=%{
 Settings.gravatar['ssl_url']    ||= 'https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=identicon'
 Settings.gravatar['host']         = Settings.get_host_without_www(Settings.gravatar['plain_url'])
 
+#
+# Cron Jobs
+#
+Settings['cron_jobs'] ||= Settingslogic.new({})
+Settings.cron_jobs['stuck_ci_builds_worker'] ||= Settingslogic.new({})
+Settings.cron_jobs['stuck_ci_builds_worker']['cron'] ||= '0 0 * * *'
+Settings.cron_jobs['stuck_ci_builds_worker']['job_class'] = 'StuckCiBuildsWorker'
+
+
 #
 # GitLab Shell
 #
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 5fb43a86e13d385f5831108859636a28bce56384..d82cfb3ec0c787022f6b61fcab2f5104f0fee8f0 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -121,14 +121,14 @@ Devise.setup do |config|
   config.lock_strategy = :failed_attempts
 
   # Defines which key will be used when locking and unlocking an account
-  # config.unlock_keys = [ :email ]
+  config.unlock_keys = [ :email ]
 
   # Defines which strategy will be used to unlock an account.
   # :email = Sends an unlock link to the user email
   # :time  = Re-enables login after a certain amount of time (see :unlock_in below)
   # :both  = Enables both strategies
   # :none  = No unlock strategy. You should handle unlocking by yourself.
-  config.unlock_strategy = :time
+  config.unlock_strategy = :both
 
   # Number of authentication tries before locking an account if lock_strategy
   # is failed attempts.
@@ -241,6 +241,16 @@ Devise.setup do |config|
       # An Array from the configuration will be expanded.
       provider_arguments.concat provider['args']
     when Hash
+      # Add procs for handling SLO
+      if provider['name'] == 'cas3'
+        provider['args'][:on_single_sign_out]  = lambda do |request|
+          ticket = request.params[:session_index]
+          raise "Service Ticket not found." unless Gitlab::OAuth::Session.valid?(:cas3, ticket)
+          Gitlab::OAuth::Session.destroy(:cas3, ticket)
+          true
+        end
+      end
+
       # A Hash from the configuration will be passed as is.
       provider_arguments << provider['args'].symbolize_keys
     end
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index 2e3a71912ef6b26600838c8a35c4e142c648f614..dcf6ce74d96bbd1dc546a6d0934e5a611d7b8cd7 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -18,11 +18,12 @@ Sidekiq.configure_server do |config|
     chain.add Gitlab::SidekiqMiddleware::MemoryKiller if ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS']
   end
 
-  # Sidekiq-cron: load recurring jobs from schedule.yml
-  schedule_file = 'config/schedule.yml'
-  if File.exists?(schedule_file)
-    Sidekiq::Cron::Job.load_from_hash YAML.load_file(schedule_file)
-  end
+  # Sidekiq-cron: load recurring jobs from gitlab.yml
+  # UGLY Hack to get nested hash from settingslogic
+  cron_jobs = JSON.parse(Gitlab.config.cron_jobs.to_json)
+  # UGLY hack: Settingslogic doesn't allow 'class' key
+  cron_jobs.each { |k,v| cron_jobs[k]['class'] = cron_jobs[k].delete('job_class') }
+  Sidekiq::Cron::Job.load_from_hash! cron_jobs
 
   # Database pool should be at least `sidekiq_concurrency` + 2
   # For more info, see: https://github.com/mperham/sidekiq/blob/master/4.0-Upgrade.md
diff --git a/config/routes.rb b/config/routes.rb
index 57be57e3251719ee573f36804f126d96b6552eec..b9242327de1b0ba98ea869accadebd47ba30238f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -188,7 +188,7 @@ Rails.application.routes.draw do
   namespace :admin do
     resources :users, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } do
       resources :keys, only: [:show, :destroy]
-      resources :identities, only: [:index, :edit, :update, :destroy]
+      resources :identities, except: [:show]
 
       delete 'stop_impersonation' => 'impersonation#destroy', on: :collection
 
diff --git a/config/schedule.yml b/config/schedule.yml
deleted file mode 100644
index 993a95fef565b87d049e4d6e15e3e0ed7c33ee2e..0000000000000000000000000000000000000000
--- a/config/schedule.yml
+++ /dev/null
@@ -1,10 +0,0 @@
-# Here is a list of jobs that are scheduled to run periodically.
-# We use a UNIX cron notation to specify execution schedule.
-#
-# Please read here for more information:
-# https://github.com/ondrejbartas/sidekiq-cron#adding-cron-job
-
-stuck_ci_builds_worker:
-  cron: "0 0 * * *"
-  class: "StuckCiBuildsWorker"
-  queue: "default"
diff --git a/db/migrate/20151012173029_set_jira_service_api_url.rb b/db/migrate/20151012173029_set_jira_service_api_url.rb
new file mode 100644
index 0000000000000000000000000000000000000000..2af99e0db0b3f3624b7ef7866609a247357addc3
--- /dev/null
+++ b/db/migrate/20151012173029_set_jira_service_api_url.rb
@@ -0,0 +1,50 @@
+class SetJiraServiceApiUrl < ActiveRecord::Migration
+  # This migration can be performed online without errors, but some Jira API calls may be missed
+  # when doing so because api_url is not yet available.
+
+  def build_api_url_from_project_url(project_url, api_version)
+    # this is the exact logic previously used to build the Jira API URL from project_url
+    server = URI(project_url)
+    default_ports = [80, 443].include?(server.port)
+    server_url = "#{server.scheme}://#{server.host}"
+    server_url.concat(":#{server.port}") unless default_ports
+    "#{server_url}/rest/api/#{api_version}"
+  end
+
+  def get_api_version_from_api_url(api_url)
+    match = /\/rest\/api\/(?<api_version>\w+)$/.match(api_url)
+    match && match['api_version']
+  end
+
+  def change
+    reversible do |dir|
+      select_all("SELECT id, properties FROM services WHERE services.type IN ('JiraService')").each do |jira_service|
+        id = jira_service["id"]
+        properties = JSON.parse(jira_service["properties"])
+        properties_was = properties.clone
+
+        dir.up do
+          # remove api_version and set api_url
+          if properties['api_version'].present? && properties['project_url'].present?
+            begin
+              properties['api_url'] ||= build_api_url_from_project_url(properties['project_url'], properties['api_version'])
+            rescue
+              # looks like project_url was not a valid URL. Do nothing.
+            end
+          end
+          properties.delete('api_version') if properties.include?('api_version')
+        end
+
+        dir.down do
+          # remove api_url and set api_version (default to '2')
+          properties['api_version'] ||= get_api_version_from_api_url(properties['api_url']) || '2'
+          properties.delete('api_url') if properties.include?('api_url')
+        end
+
+        if properties != properties_was
+          execute("UPDATE services SET properties = '#{quote_string(properties.to_json)}' WHERE id = #{id}")
+        end
+      end
+    end
+  end
+end
diff --git a/db/migrate/20151203162134_add_build_events_to_services.rb b/db/migrate/20151203162134_add_build_events_to_services.rb
index a84be7db3f15ba2d87f54bdd52560df34021c2af..c5542cb864da8ca5198f8d76dd8ff6fe61d991b5 100644
--- a/db/migrate/20151203162134_add_build_events_to_services.rb
+++ b/db/migrate/20151203162134_add_build_events_to_services.rb
@@ -1,5 +1,5 @@
 class AddBuildEventsToServices < ActiveRecord::Migration
-  def up
+  def change
     add_column :services, :build_events, :boolean, default: false, null: false
     add_column :web_hooks, :build_events, :boolean, default: false, null: false
   end
diff --git a/db/migrate/20151209144329_migrate_ci_web_hooks.rb b/db/migrate/20151209144329_migrate_ci_web_hooks.rb
index 825ba1973ff85a67a7d88fee7a416a94221d2f3e..d7e196e6763d442f4e650584f0378cb770d75c57 100644
--- a/db/migrate/20151209144329_migrate_ci_web_hooks.rb
+++ b/db/migrate/20151209144329_migrate_ci_web_hooks.rb
@@ -10,4 +10,7 @@ class MigrateCiWebHooks < ActiveRecord::Migration
       'JOIN projects ON ci_projects.gitlab_id = projects.id'
     )
   end
+
+  def down
+  end
 end
diff --git a/db/migrate/20151210030143_add_unlock_token_to_user.rb b/db/migrate/20151210030143_add_unlock_token_to_user.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0ea66ba65dfa6df8896b219dcedbb9aac460b9cd
--- /dev/null
+++ b/db/migrate/20151210030143_add_unlock_token_to_user.rb
@@ -0,0 +1,5 @@
+class AddUnlockTokenToUser < ActiveRecord::Migration
+  def change
+    add_column :users, :unlock_token, :string
+  end
+end
diff --git a/db/migrate/20151210125928_add_ci_to_project.rb b/db/migrate/20151210125928_add_ci_to_project.rb
index 8a65abab636bd9895cb93e913414275517326c08..8c167f64a2b59444c94a5b8a1f914a252e44aec1 100644
--- a/db/migrate/20151210125928_add_ci_to_project.rb
+++ b/db/migrate/20151210125928_add_ci_to_project.rb
@@ -1,5 +1,5 @@
 class AddCiToProject < ActiveRecord::Migration
-  def up
+  def change
     add_column :projects, :ci_id, :integer
     add_column :projects, :builds_enabled, :boolean, default: true, null: false
     add_column :projects, :shared_runners_enabled, :boolean, default: true, null: false
diff --git a/db/migrate/20151210125929_add_project_id_to_ci.rb b/db/migrate/20151210125929_add_project_id_to_ci.rb
index 5d1cf54357673f65f3c0d084bc39d8127453e2db..84273591fa2ede4f606e2ab9cae2418330e00cf1 100644
--- a/db/migrate/20151210125929_add_project_id_to_ci.rb
+++ b/db/migrate/20151210125929_add_project_id_to_ci.rb
@@ -1,5 +1,5 @@
 class AddProjectIdToCi < ActiveRecord::Migration
-  def up
+  def change
     add_column :ci_builds, :gl_project_id, :integer
     add_column :ci_runner_projects, :gl_project_id, :integer
     add_column :ci_triggers, :gl_project_id, :integer
diff --git a/db/migrate/20151210125930_migrate_ci_to_project.rb b/db/migrate/20151210125930_migrate_ci_to_project.rb
index 7527899786227161b404102d9e7a97990551027d..c32c7feb1931443f5e28b1ee0d56eae5cbe71674 100644
--- a/db/migrate/20151210125930_migrate_ci_to_project.rb
+++ b/db/migrate/20151210125930_migrate_ci_to_project.rb
@@ -14,6 +14,10 @@ class MigrateCiToProject < ActiveRecord::Migration
     migrate_ci_service
   end
 
+  def down
+    # We can't reverse the data
+  end
+
   def migrate_project_id_for_table(table)
     subquery = "SELECT gitlab_id FROM ci_projects WHERE ci_projects.id = #{table}.project_id"
     execute("UPDATE #{table} SET gl_project_id=(#{subquery}) WHERE gl_project_id IS NULL")
diff --git a/db/migrate/20151210125931_add_index_to_ci_tables.rb b/db/migrate/20151210125931_add_index_to_ci_tables.rb
index 9fedb5d612ce3c801487b761de65207336a0af4f..5e129c9303d9b0bece0d8fc36100682f8a8a969f 100644
--- a/db/migrate/20151210125931_add_index_to_ci_tables.rb
+++ b/db/migrate/20151210125931_add_index_to_ci_tables.rb
@@ -1,5 +1,5 @@
 class AddIndexToCiTables < ActiveRecord::Migration
-  def up
+  def change
     add_index :ci_builds, :gl_project_id
     add_index :ci_runner_projects, :gl_project_id
     add_index :ci_triggers, :gl_project_id
diff --git a/db/migrate/20151210125932_drop_null_for_ci_tables.rb b/db/migrate/20151210125932_drop_null_for_ci_tables.rb
index 0b007430b0c17168447bc51f80059779f501764c..c520c2ed56f67e2f08d91fa29174d12bcb413ece 100644
--- a/db/migrate/20151210125932_drop_null_for_ci_tables.rb
+++ b/db/migrate/20151210125932_drop_null_for_ci_tables.rb
@@ -1,5 +1,5 @@
 class DropNullForCiTables < ActiveRecord::Migration
-  def up
+  def change
     remove_index :ci_variables, :project_id
     remove_index :ci_runner_projects, :project_id
     change_column_null :ci_triggers, :project_id, true
diff --git a/db/schema.rb b/db/schema.rb
index 0167e30ff8b90658ddd9a0796d3c5720a3be376a..60b42f7a4733c085400280b3ea2504f5ceda2cd0 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -837,6 +837,7 @@ ActiveRecord::Schema.define(version: 20151210125932) do
     t.integer  "consumed_timestep"
     t.integer  "layout",                     default: 0
     t.boolean  "hide_project_limit",         default: false
+    t.string   "unlock_token"
   end
 
   add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 658e65c6f01c91ba4e61e8ca1269c931f94653f7..0ca81ffd49ee1b39636a9d9045d2e6d8022523b6 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -118,6 +118,16 @@ Parameters:
       "path": "brightbox",
       "updated_at": "2013-09-30T13:46:02Z"
     },
+    "permissions": {
+      "project_access": {
+        "access_level": 10,
+        "notification_level": 3
+      },
+      "group_access": {
+        "access_level": 50,
+        "notification_level": 3
+      }
+    },
     "archived": false,
     "avatar_url": null
   }
diff --git a/doc/ci/README.md b/doc/ci/README.md
index 5d9d7a81db349d197491dfafc9675841cddd67cb..965b007bedb40cc46748266d65dc469817161c9a 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -24,6 +24,7 @@
 
 ### Examples
 
++ [The .gitlab-ci.yml file for GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml)
 + [Test and deploy Ruby applications to Heroku](examples/test-and-deploy-ruby-application-to-heroku.md)
 + [Test and deploy Python applications to Heroku](examples/test-and-deploy-python-application-to-heroku.md)
 + [Test Clojure applications](examples/test-clojure-application.md)
diff --git a/doc/integration/README.md b/doc/integration/README.md
index eff39a626ae6205a122558fd5f8990882d930b04..6263353851f3cc5312105afd5bedbc6e16e42be9 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -4,10 +4,12 @@ GitLab integrates with multiple third-party services to allow external issue tra
 
 See the documentation below for details on how to configure these services.
 
+- [Jira](jira.md) Integrate with the JIRA issue tracker
 - [External issue tracker](external-issue-tracker.md) Redmine, JIRA, etc.
 - [LDAP](ldap.md) Set up sign in via LDAP
 - [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab, and Google via OAuth.
 - [SAML](saml.md) Configure GitLab as a SAML 2.0 Service Provider
+- [CAS](cas.md) Configure GitLab to sign in using CAS
 - [Slack](slack.md) Integrate with the Slack chat service
 - [OAuth2 provider](oauth_provider.md) OAuth2 application creation
 - [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages
diff --git a/doc/integration/cas.md b/doc/integration/cas.md
new file mode 100644
index 0000000000000000000000000000000000000000..e6b2071f193cd5ca5e424960f4ac9a198de7fbcd
--- /dev/null
+++ b/doc/integration/cas.md
@@ -0,0 +1,62 @@
+# CAS OmniAuth Provider
+
+To enable the CAS OmniAuth provider you must register your application with your CAS instance. This requires the service URL GitLab will supply to CAS. It should be something like: `https://gitlab.example.com:443/users/auth/cas3/callback?url`. By default handling for SLO is enabled, you only need to configure CAS for backchannel logout.
+
+1.  On your GitLab server, open the configuration file.
+
+    For omnibus package:
+
+    ```sh
+      sudo editor /etc/gitlab/gitlab.rb
+    ```
+
+    For installations from source:
+
+    ```sh
+      cd /home/git/gitlab
+
+      sudo -u git -H editor config/gitlab.yml
+    ```
+
+1.  See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+
+1.  Add the provider configuration:
+
+    For omnibus package:
+
+    ```ruby
+      gitlab_rails['omniauth_providers'] = [
+        {
+          name: "cas3",
+          label: "cas",
+          args: {
+                  url: 'CAS_SERVER',
+                  login_url: '/CAS_PATH/login',
+                  service_validate_url: '/CAS_PATH/p3/serviceValidate',
+                  logout_url: '/CAS_PATH/logout'} }
+          }
+        }
+      ]
+    ```
+
+    For installations from source:
+
+    ```
+      - { name: 'cas3',
+          label: 'cas',
+          args: {
+                  url: 'CAS_SERVER',
+                  login_url: '/CAS_PATH/login',
+                  service_validate_url: '/CAS_PATH/p3/serviceValidate',
+                  logout_url: '/CAS_PATH/logout'} }
+    ```
+
+1.  Change 'CAS_PATH' to the root of your CAS instance (ie. `cas`).
+
+1.  If your CAS instance does not use default TGC lifetimes, update the `cas3.session_duration` to at least the current TGC maximum lifetime. To explicitly disable SLO, regardless of CAS settings, set this to 0.
+
+1.  Save the configuration file.
+
+1.  Restart GitLab for the changes to take effect.
+
+On the sign in page there should now be a CAS tab in the sign in form.
diff --git a/doc/integration/jira.md b/doc/integration/jira.md
new file mode 100644
index 0000000000000000000000000000000000000000..624601d0faccb8e0192d7d7865168a9da0798255
--- /dev/null
+++ b/doc/integration/jira.md
@@ -0,0 +1,113 @@
+# GitLab Jira integration
+
+GitLab can be configured to interact with Jira.
+Configuration happens via username and password.
+Connecting to a Jira server via CAS is not possible.
+
+Each project can be configured to connect to a different Jira instance, configuration is explained [here](#configuration).
+If you have one Jira instance you can pre-fill the settings page with a default template. To configure the template [see external issue tracker document](external-issue-tracker.md#service-template)).
+
+Once the project is connected to Jira, you can reference and close the issues in Jira directly from GitLab.
+
+
+## Table of Contents
+
+* [Referencing Jira Issues from GitLab](#referencing-jira-issues)
+* [Closing Jira Issues from GitLab](#closing-jira-issues)
+* [Configuration](#configuration)
+
+### Referencing Jira Issues
+
+When GitLab project has Jira issue tracker configured and enabled, mentioning Jira issue in GitLab will automatically add a comment in Jira issue with the link back to GitLab. This means that in comments in merge requests and commits referencing an issue, eg. `PROJECT-7`, will add a comment in Jira issue in the format:
+
+
+```
+ USER mentioned this issue in LINK_TO_THE_MENTION
+```
+
+* `USER` A user that mentioned the issue. This is the link to the user profile in GitLab.
+* `LINK_TO_THE_MENTION` Link to the origin of mention with a name of the entity where Jira issue was mentioned.
+Can be commit or merge request.
+
+
+![example of mentioning or closing the Jira issue](jira_issue_reference.png)
+
+
+### Closing Jira Issues
+
+Jira issues can be closed directly from GitLab by using trigger words, eg. `Resolves PROJECT-1`, `Closes PROJECT-1` or `Fixes PROJECT-1`, in commits and merge requests.
+When a commit which contains the trigger word in the commit message is pushed, GitLab will add a comment in the mentioned Jira issue.
+
+For example, for project named PROJECT in Jira, we implemented a new feature and created a merge request in GitLab.
+
+This feature was requested in Jira issue PROJECT-7. Merge request in GitLab contains the improvement and in merge request description we say that this merge request `Closes PROJECT-7` issue.
+
+Once this merge request is merged, Jira issue will be automatically closed with a link to the commit that resolved the issue.
+
+![A Git commit that causes the Jira issue to be closed](merge_request_close_jira.png)
+
+
+![The GitLab integration user leaves a comment on Jira](jira_service_close_issue.png)
+
+
+## Configuration
+
+### Configuring JIRA
+
+We need to create a user in JIRA which will have access to all projects that need to integrate with GitLab.
+Login to your JIRA instance as admin and under Administration go to User Management and create a new user.
+As an example, we'll create a user named `gitlab` and add it to `jira-developers` group.
+
+**It is important that the user `gitlab` has write-access to projects in JIRA**
+
+### Configuring GitLab
+
+### GitLab 7.8 EE and up with JIRA v6.x
+
+To enable JIRA integration in a project, navigate to the project Settings page and go to Services. Here you will find JIRA.
+
+Fill in the required details on the page:
+
+![Jira service page](jira_service_page.png)
+
+* `description` A name for the issue tracker (to differentiate between instances, for instance).
+* `project url` The URL to the JIRA project which is being linked to this GitLab project.
+* `issues url` The URL to the JIRA project issues overview for the project that is linked to this GitLab project.
+* `new issue url` This is the URL to create a new issue in JIRA for the project linked to this GitLab project.
+* `api url` The base URL of the JIRA API. It may be omitted, in which case GitLab will automatically use API version `2` based on the `project url`, i.e. `https://jira.example.com/rest/api/2`.
+* `username` The username of the user created in [configuring JIRA step](#configuring-jira).
+* `password` The password of the user created in [configuring JIRA step](#configuring-jira).
+* `Jira issue transition` This is the id of a transition that moves issues to a closed state. You can find this number under [JIRA workflow administration, see screenshot](jira_workflow_screenshot.png).  By default, this id is `2`. (In the example image, this is `2` as well)
+
+After saving the configuration, your GitLab project will be able to interact with the linked JIRA project.
+
+
+### GitLab 6.x-7.7 with JIRA v6.x
+
+**Note: GitLab 7.8 and up contain various integration improvements. We strongly recommend upgrading.**
+
+
+In `gitlab.yml` enable [JIRA issue tracker section by uncommenting the lines](https://gitlab.com/subscribers/gitlab-ee/blob/6-8-stable-ee/config/gitlab.yml.example#L111-115).
+This will make sure that all issues within GitLab are pointing to the JIRA issue tracker.
+
+We can also enable JIRA service that will allow us to interact with JIRA issues.
+
+For example, we can close issues in JIRA by a commit in GitLab.
+
+Go to project settings page and fill in the project name for the JIRA project:
+
+![Set the JIRA project name in GitLab to 'NEW'](jira_project_name.png)
+
+Next, go to the services page and find JIRA.
+
+![Jira services page](jira_service.png)
+
+1. Tick the active check box to enable the service.
+1. Supply the url to JIRA server, for example http://jira.sample
+1. Supply the username of a user we created under `Configuring JIRA` section, for example `gitlab`
+1. Supply the password of the user
+1. Optional: supply the JIRA api version, default is version
+1. Optional: supply the JIRA issue transition ID (issue transition to closed). This is dependant on JIRA settings, default is 2
+1. Save
+
+Now we should be able to interact with JIRA issues.
diff --git a/doc/integration/jira_issue_reference.png b/doc/integration/jira_issue_reference.png
new file mode 100644
index 0000000000000000000000000000000000000000..15739a22dc7151af663316c1d44e8fcda704ce29
Binary files /dev/null and b/doc/integration/jira_issue_reference.png differ
diff --git a/doc/integration/jira_project_name.png b/doc/integration/jira_project_name.png
new file mode 100644
index 0000000000000000000000000000000000000000..5986fdb63fb8727b339b69d7fa6b64d3ef5f4b17
Binary files /dev/null and b/doc/integration/jira_project_name.png differ
diff --git a/doc/integration/jira_service.png b/doc/integration/jira_service.png
new file mode 100644
index 0000000000000000000000000000000000000000..1f6628c43719edd55d415f80d28d8d4423002586
Binary files /dev/null and b/doc/integration/jira_service.png differ
diff --git a/doc/integration/jira_service_close_issue.png b/doc/integration/jira_service_close_issue.png
new file mode 100644
index 0000000000000000000000000000000000000000..67dfc6144c44f0643e1373bef9961bf0c3a458fb
Binary files /dev/null and b/doc/integration/jira_service_close_issue.png differ
diff --git a/doc/integration/jira_service_page.png b/doc/integration/jira_service_page.png
new file mode 100644
index 0000000000000000000000000000000000000000..69ec44e826fb82702103f7cf1fd4299084e24151
Binary files /dev/null and b/doc/integration/jira_service_page.png differ
diff --git a/doc/integration/jira_workflow_screenshot.png b/doc/integration/jira_workflow_screenshot.png
new file mode 100644
index 0000000000000000000000000000000000000000..8635a32eb6874fa64bc53ba671794c20e9df2f00
Binary files /dev/null and b/doc/integration/jira_workflow_screenshot.png differ
diff --git a/features/project/issues/award_emoji.feature b/features/project/issues/award_emoji.feature
index 0ce99e855c6f91b0c8d0c16af8f065963647146e..cbf2e7104ab527bd6c2b676c2d0e64152ded42a8 100644
--- a/features/project/issues/award_emoji.feature
+++ b/features/project/issues/award_emoji.feature
@@ -13,6 +13,11 @@ Feature: Award Emoji
     Then I have award added
     And I can remove it by clicking to icon
 
+  @javascript
+  Scenario: I can see the list of emoji categories
+    Given I click to emoji-picker
+    Then I can see the activity and food categories
+
   @javascript
   Scenario: I add award emoji using regular comment
   Given I leave comment with a single emoji
diff --git a/features/project/service.feature b/features/project/service.feature
index ff3e7a0b38e6bd063878f3246d9806c8aa876275..3a7b830852489d2560619a4aabc6203023827cff 100644
--- a/features/project/service.feature
+++ b/features/project/service.feature
@@ -55,6 +55,12 @@ Feature: Project Services
     And I fill email on push settings
     Then I should see email on push service settings saved
 
+  Scenario: Activate JIRA service
+    When I visit project "Shop" services page
+    And I click jira service link
+    And I fill jira settings
+    Then I should see jira service settings saved
+
   Scenario: Activate Irker (IRC Gateway) service
     When I visit project "Shop" services page
     And I click Irker service link
diff --git a/features/steps/project/issues/award_emoji.rb b/features/steps/project/issues/award_emoji.rb
index 325eaf2ea6a5834ea388eed6e1244e152b372a88..c94d0ba7306efa39e140255a9b19c8709f5161b0 100644
--- a/features/steps/project/issues/award_emoji.rb
+++ b/features/steps/project/issues/award_emoji.rb
@@ -15,8 +15,8 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
   end
 
   step 'I click to emoji in the picker' do
-    page.within '.awards-menu' do
-      page.first('img').click
+    page.within '.emoji-menu' do
+      page.first('.emoji-icon').click
     end
   end
 
@@ -27,6 +27,13 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
     end
   end
 
+  step 'I can see the activity and food categories' do
+    page.within '.emoji-menu' do
+      expect(page).to_not have_selector 'Activity'
+      expect(page).to_not have_selector 'Food'
+    end
+  end
+
   step 'I have award added' do
     page.within '.awards' do
       expect(page).to have_selector '.award'
diff --git a/features/steps/project/services.rb b/features/steps/project/services.rb
index ed3957ca87364b9b3cbd75b1f62b3ca2d10333b0..536199ddb4fd7c25f766b7a93b5a74dd992490e0 100644
--- a/features/steps/project/services.rb
+++ b/features/steps/project/services.rb
@@ -173,6 +173,24 @@ class Spinach::Features::ProjectServices < Spinach::FeatureSteps
     expect(find_field('Sound').find('option[selected]').value).to eq 'bike'
   end
 
+  step 'I click jira service link' do
+    click_link 'JIRA'
+  end
+
+  step 'I fill jira settings' do
+    fill_in 'Project url', with: 'http://jira.example'
+    fill_in 'Username', with: 'gitlab'
+    fill_in 'Password', with: 'gitlab'
+    fill_in 'Api url', with: 'http://jira.example/rest/api/2'
+    click_button 'Save'
+  end
+
+  step 'I should see jira service settings saved' do
+    expect(find_field('Project url').value).to eq 'http://jira.example'
+    expect(find_field('Username').value).to eq 'gitlab'
+    expect(find_field('Api url').value).to eq 'http://jira.example/rest/api/2'
+  end
+
   step 'I click Atlassian Bamboo CI service link' do
     click_link 'Atlassian Bamboo CI'
   end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 5e75cd35c56c6945eddb65c461d8050a3d0b4100..a9e0960872a08cb1b455a448b8458364acd95e8d 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -25,7 +25,7 @@ module API
         @projects = current_user.authorized_projects
         @projects = filter_projects(@projects)
         @projects = paginate @projects
-        present @projects, with: Entities::Project
+        present @projects, with: Entities::ProjectWithAccess, user: current_user
       end
 
       # Get an owned projects list for authenticated user
@@ -36,7 +36,7 @@ module API
         @projects = current_user.owned_projects
         @projects = filter_projects(@projects)
         @projects = paginate @projects
-        present @projects, with: Entities::Project
+        present @projects, with: Entities::ProjectWithAccess, user: current_user
       end
 
       # Gets starred project for the authenticated user
@@ -59,7 +59,7 @@ module API
         @projects = Project.all
         @projects = filter_projects(@projects)
         @projects = paginate @projects
-        present @projects, with: Entities::Project
+        present @projects, with: Entities::ProjectWithAccess, user: current_user
       end
 
       # Get a single project
diff --git a/lib/award_emoji.rb b/lib/award_emoji.rb
index 4d99164bc3319e8fc1dc241627d8735da93d1115..3825f4650be4814994b82809a80fbba5b169cc94 100644
--- a/lib/award_emoji.rb
+++ b/lib/award_emoji.rb
@@ -1,11 +1,4 @@
 class AwardEmoji
-  EMOJI_LIST = [
-    "+1", "-1", "100", "blush", "heart", "smile", "rage",
-    "beers", "disappointed", "ok_hand",
-    "helicopter", "shit", "airplane", "alarm_clock",
-    "ambulance", "anguished", "two_hearts", "wink"
-  ]
-
   ALIASES = {
     pout: "rage",
     satisfied: "laughing",
@@ -37,11 +30,41 @@ class AwardEmoji
     squirrel: "shipit"
   }.with_indifferent_access
 
-  def self.path_to_emoji_image(name)
-    "emoji/#{Emoji.emoji_filename(name)}.png"
-  end
+  CATEGORIES = {
+    other: "Other",
+    objects: "Objects",
+    places: "Places",
+    travel_places: "Travel",
+    emoticons: "Emoticons",
+    objects_symbols: "Symbols",
+    nature: "Nature",
+    celebration: "Celebration",
+    people: "People",
+    activity: "Activity",
+    flags: "Flags",
+    food_drink: "Food"
+  }.with_indifferent_access
 
   def self.normilize_emoji_name(name)
     ALIASES[name] || name
   end
+
+  def self.emoji_by_category
+    unless @emoji_by_category
+      @emoji_by_category = {}
+      emojis_added = []
+
+      Emoji.emojis.each do |emoji_name, data|
+        next if emojis_added.include?(data["name"])
+        emojis_added << data["name"]
+
+        @emoji_by_category[data["category"]] ||= []
+        @emoji_by_category[data["category"]] << data
+      end
+
+      @emoji_by_category = @emoji_by_category.sort.to_h
+    end
+
+    @emoji_by_category
+  end
 end
diff --git a/lib/banzai/filter/external_issue_reference_filter.rb b/lib/banzai/filter/external_issue_reference_filter.rb
index f5737a7ac193afb9d40d96e7838371adefd72154..f5942740cd63ca7c0082c62969bf22597641634b 100644
--- a/lib/banzai/filter/external_issue_reference_filter.rb
+++ b/lib/banzai/filter/external_issue_reference_filter.rb
@@ -23,6 +23,18 @@ module Banzai
         end
       end
 
+      def self.referenced_by(node)
+        project = Project.find(node.attr("data-project")) rescue nil
+        return unless project
+
+        id = node.attr("data-external-issue")
+        external_issue = ExternalIssue.new(id, project)
+
+        return unless external_issue
+
+        { external_issue: external_issue }
+      end
+
       def call
         # Early return if the project isn't using an external tracker
         return doc if project.nil? || project.default_issues_tracker?
@@ -46,12 +58,14 @@ module Banzai
       def issue_link_filter(text, link_text: nil)
         project = context[:project]
 
-        self.class.references_in(text) do |match, issue|
-          url = url_for_issue(issue, project, only_path: context[:only_path])
+        self.class.references_in(text) do |match, id|
+          ExternalIssue.new(id, project)
+
+          url = url_for_issue(id, project, only_path: context[:only_path])
 
           title = escape_once("Issue in #{project.external_issue_tracker.title}")
           klass = reference_class(:issue)
-          data  = data_attribute(project: project.id)
+          data  = data_attribute(project: project.id, external_issue: id)
 
           text = link_text || match
 
diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb
index 443563c2e4a4c8b1cb48af76ff093c891ad25fd0..1c91204e98ca1c9331f0c597d4e8bb5933b3c7cd 100644
--- a/lib/ci/api/helpers.rb
+++ b/lib/ci/api/helpers.rb
@@ -19,7 +19,7 @@ module Ci
       end
 
       def runner_registration_token_valid?
-        params[:token] == current_application_settings.ensure_runners_registration_token
+        params[:token] == current_application_settings.runners_registration_token
       end
 
       def update_runner_last_contact
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index 0c350d7c675e1977077944a7c1eff2f5a355c93b..f065cc5e9e9962c70407370403881452dab5c795 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -20,6 +20,10 @@ module Gitlab
       def blank_ref?(ref)
         ref == BLANK_SHA
       end
+
+      def version
+        Gitlab::VersionInfo.parse(Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} --version)).first)
+      end
     end
   end
 end
diff --git a/lib/gitlab/o_auth/session.rb b/lib/gitlab/o_auth/session.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f33bfd0bd0e684e6ca8ba31796b1878889b2c8f1
--- /dev/null
+++ b/lib/gitlab/o_auth/session.rb
@@ -0,0 +1,17 @@
+module Gitlab
+  module OAuth
+    module Session
+      def self.create(provider, ticket)
+        Rails.cache.write("gitlab:#{provider}:#{ticket}", ticket, expires_in: Gitlab.config.omniauth.cas3.session_duration)
+      end
+
+      def self.destroy(provider, ticket)
+        Rails.cache.delete("gitlab:#{provider}:#{ticket}")
+      end
+
+      def self.valid?(provider, ticket)
+        Rails.cache.read("gitlab:#{provider}:#{ticket}").present?
+      end
+    end
+  end
+end
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index 42f7c26f3c4a10a8d0b0834c81daa2beab2f2bd5..0a70d21b1cea210f40ee5159b4d004c2e6d8d3ac 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -18,10 +18,20 @@ module Gitlab
       super(text, context.merge(project: project))
     end
 
-    %i(user label issue merge_request snippet commit commit_range).each do |type|
+    %i(user label merge_request snippet commit commit_range).each do |type|
       define_method("#{type}s") do
         @references[type] ||= references(type, project: project, current_user: current_user)
       end
     end
+
+    def issues
+      options = { project: project, current_user: current_user }
+
+      if project && project.jira_tracker?
+        @references[:external_issue] ||= references(:external_issue, options)
+      else
+        @references[:issue] ||= references(:issue, options)
+      end
+    end
   end
 end
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 66a2cc0c157a90737ab32cdb29055552d926079e..26d03944b8a24dd811e1a6da96f05b73118ae215 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -63,7 +63,7 @@ describe "Admin Runners" do
   end
 
   describe 'runners registration token' do
-    let!(:token) { current_application_settings.ensure_runners_registration_token }
+    let!(:token) { current_application_settings.runners_registration_token }
     before { visit admin_runners_path }
 
     it 'has a registration token' do
diff --git a/spec/features/ci_lint_spec.rb b/spec/features/ci_lint_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..e6e73e5e67ca34dd3ea2734fc30842bdf0d9c6a2
--- /dev/null
+++ b/spec/features/ci_lint_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe 'CI Lint' do
+  before do
+    login_as :user
+  end
+
+  describe 'YAML parsing' do
+    before do
+      visit ci_lint_path
+      fill_in 'content', with: yaml_content
+      click_on 'Validate'
+    end
+
+    context 'YAML is correct' do
+      let(:yaml_content) do
+        File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+      end
+
+      it 'Yaml parsing' do
+        within "table" do
+          expect(page).to have_content('Job - rspec')
+          expect(page).to have_content('Job - spinach')
+          expect(page).to have_content('Deploy Job - staging')
+          expect(page).to have_content('Deploy Job - production')
+        end
+      end
+    end
+
+    context 'YAML is incorrect' do
+      let(:yaml_content) { '' }
+
+      it 'displays information about an error' do
+        expect(page).to have_content('Status: syntax is incorrect')
+        expect(page).to have_content('Error: Please provide content of .gitlab-ci.yml')
+      end
+    end
+  end
+end
diff --git a/spec/features/lint_spec.rb b/spec/features/lint_spec.rb
deleted file mode 100644
index 5d8f56e2cfb160bac8f81f0e6a41e276d0a7713a..0000000000000000000000000000000000000000
--- a/spec/features/lint_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require 'spec_helper'
-
-describe "Lint" do
-  before do
-    login_as :user
-  end
-
-  it "Yaml parsing", js: true do
-    content = File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
-    visit ci_lint_path 
-    fill_in "content", with: content
-    click_on "Validate"
-    within "table" do
-      expect(page).to have_content("Job - rspec")
-      expect(page).to have_content("Job - spinach")
-      expect(page).to have_content("Deploy Job - staging")
-      expect(page).to have_content("Deploy Job - production")
-    end
-  end
-
-  it "Yaml parsing with error", js: true do
-    visit ci_lint_path
-    fill_in "content", with: ""
-    click_on "Validate"
-    expect(page).to have_content("Status: syntax is incorrect")
-    expect(page).to have_content("Error: Please provide content of .gitlab-ci.yml")
-  end
-end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 09fcff2444ac83771442c68f0935fd591fdd4305..74b148f5d178b44fb55aa3340cbca7f4fefc5180 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -70,6 +70,20 @@ feature 'Project', feature: true do
     end
   end
 
+  describe 'leave project link' do
+    let(:user)    { create(:user) }
+    let(:project) { create(:project, namespace: user.namespace) }
+
+    before do
+      login_with(user)
+      project.team.add_user(user, Gitlab::Access::MASTER)
+      visit namespace_project_path(project.namespace, project)
+    end
+
+    it { expect(page).to have_content('You have Master access to this project.') }
+    it { expect(page).to have_link('Leave this project') }
+  end
+
   def remove_with_confirm(button_text, confirm_with)
     click_button button_text
     fill_in 'confirm_name_input', with: confirm_with
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index 1f2c4ee77b59fdf79c94f5295f3c68048f5136c3..04e795025d20912cf7166f8d219a377d02bc120c 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -127,18 +127,6 @@ describe IssuesHelper do
     it { is_expected.to eq("!1, !2, or !3") }
   end
 
-  describe "#url_to_emoji" do
-    it "returns url" do
-      expect(url_to_emoji("smile")).to include("emoji/1F604.png")
-    end
-  end
-
-  describe "#emoji_list" do
-    it "returns url" do
-      expect(emoji_list).to be_kind_of(Array)
-    end
-  end
-
   describe "#note_active_class" do
     before do
       @note = create :note
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
index 0ef1efb8bce1ee6c01105aab7be74fd62b8af73a..600e1c4e9ecf1727403f68d7cca18bb270be25d7 100644
--- a/spec/helpers/merge_requests_helper_spec.rb
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -1,24 +1,57 @@
 require 'spec_helper'
 
 describe MergeRequestsHelper do
-  describe "#issues_sentence" do
+  describe 'ci_build_details_path' do
+    let(:project) { create :project }
+    let(:merge_request) { MergeRequest.new }
+    let(:ci_service) { CiService.new }
+    let(:last_commit) { Ci::Commit.new({}) }
+
+    before do
+      allow(merge_request).to receive(:source_project).and_return(project)
+      allow(merge_request).to receive(:last_commit).and_return(last_commit)
+      allow(project).to receive(:ci_service).and_return(ci_service)
+      allow(last_commit).to receive(:sha).and_return('12d65c')
+    end
+
+    it 'does not include api credentials in a link' do
+      allow(ci_service).
+        to receive(:build_page).and_return("http://secretuser:secretpass@jenkins.example.com:8888/job/test1/scm/bySHA1/12d65c")
+      expect(helper.ci_build_details_path(merge_request)).to_not match("secret")
+    end
+  end
+
+  describe '#issues_sentence' do
     subject { issues_sentence(issues) }
     let(:issues) do
       [build(:issue, iid: 1), build(:issue, iid: 2), build(:issue, iid: 3)]
     end
 
     it { is_expected.to eq('#1, #2, and #3') }
+
+    context 'for JIRA issues' do
+      let(:project) { create(:project) }
+      let(:issues) do
+        [
+          JiraIssue.new('JIRA-123', project),
+          JiraIssue.new('JIRA-456', project),
+          JiraIssue.new('FOOBAR-7890', project)
+        ]
+      end
+
+      it { is_expected.to eq('FOOBAR-7890, JIRA-123, and JIRA-456') }
+    end
   end
 
-  describe "#format_mr_branch_names" do
-    describe "within the same project" do
+  describe '#format_mr_branch_names' do
+    describe 'within the same project' do
       let(:merge_request) { create(:merge_request) }
       subject { format_mr_branch_names(merge_request) }
 
       it { is_expected.to eq([merge_request.source_branch, merge_request.target_branch]) }
     end
 
-    describe "within different projects" do
+    describe 'within different projects' do
       let(:project) { create(:project) }
       let(:fork_project) { create(:project, forked_from_project: project) }
       let(:merge_request) { create(:merge_request, source_project: fork_project, target_project: project) }
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index f2efb528aeb6cc1c9397e7a5c9a8676286f4085d..53207767581e906005768c4e3313ea0beca51b35 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -53,6 +53,16 @@ describe ProjectsHelper do
     end
   end
 
+  describe 'user_max_access_in_project' do
+    let(:project) { create(:project) }
+    let(:user) { create(:user) }
+    before do
+      project.team.add_user(user, Gitlab::Access::MASTER)
+    end
+
+    it { expect(helper.user_max_access_in_project(user.id, project)).to eq('Master') }
+  end
+
   describe "readme_cache_key" do
     let(:project) { create(:project) }
 
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 66dc5d4911d8cd064e455e03ff3099c1646b71d5..7d963795e17b48265d15c55ac92d4b4598716409 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -97,6 +97,16 @@ describe Gitlab::ReferenceExtractor, lib: true do
     expect(extracted.first.commit_to).to eq commit
   end
 
+  context 'with an external issue tracker' do
+    let(:project) { create(:jira_project) }
+    subject { described_class.new(project, project.creator) }
+
+    it 'returns JIRA issues for a JIRA-integrated project' do
+      subject.analyze('JIRA-123 and FOOBAR-4567')
+      expect(subject.issues).to eq [JiraIssue.new('JIRA-123', project), JiraIssue.new('FOOBAR-4567', project)]
+    end
+  end
+
   context 'with a project with an underscore' do
     let(:other_project) { create(:project, path: 'test_project') }
     let(:issue) { create(:issue, project: other_project) }
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index 96b6f1dbca6b24e365a367bdef7acfc0e8cb03d4..1c22e3cb7c405363d30a575ce90178341f345da8 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -189,6 +189,12 @@ describe Ci::Build, models: true do
 
       it { is_expected.to eq(98.29) }
     end
+
+    context 'using a regex capture' do
+      subject { build.extract_coverage('TOTAL      9926   3489    65%', 'TOTAL\s+\d+\s+\d+\s+(\d{1,3}\%)') }
+
+      it { is_expected.to eq(65) }
+    end
   end
 
   describe :variables do
@@ -390,4 +396,68 @@ describe Ci::Build, models: true do
     it { is_expected.to include('gitlab-ci-token') }
     it { is_expected.to include(project.web_url[7..-1]) }
   end
+
+  def create_mr(build, commit, factory: :merge_request, created_at: Time.now)
+    FactoryGirl.create(factory,
+                       source_project_id: commit.gl_project_id,
+                       target_project_id: commit.gl_project_id,
+                       source_branch: build.ref,
+                       created_at: created_at)
+  end
+
+  describe :merge_request do
+    context 'when a MR has a reference to the commit' do
+      before do
+        @merge_request = create_mr(build, commit, factory: :merge_request)
+
+        commits = [double(id: commit.sha)]
+        allow(@merge_request).to receive(:commits).and_return(commits)
+        allow(MergeRequest).to receive_message_chain(:includes, :where, :reorder).and_return([@merge_request])
+      end
+
+      it 'returns the single associated MR' do
+        expect(build.merge_request.id).to eq(@merge_request.id)
+      end
+    end
+
+    context 'when there is not a MR referencing the commit' do
+      it 'returns nil' do
+        expect(build.merge_request).to be_nil
+      end
+    end
+
+    context 'when more than one MR have a reference to the commit' do
+      before do
+        @merge_request = create_mr(build, commit, factory: :merge_request)
+        @merge_request.close!
+        @merge_request2 = create_mr(build, commit, factory: :merge_request)
+
+        commits = [double(id: commit.sha)]
+        allow(@merge_request).to receive(:commits).and_return(commits)
+        allow(@merge_request2).to receive(:commits).and_return(commits)
+        allow(MergeRequest).to receive_message_chain(:includes, :where, :reorder).and_return([@merge_request, @merge_request2])
+      end
+
+      it 'returns the first MR' do
+        expect(build.merge_request.id).to eq(@merge_request.id)
+      end
+    end
+
+    context 'when a Build is created after the MR' do
+      before do
+        @merge_request = create_mr(build, commit, factory: :merge_request_with_diffs)
+        commit2 = FactoryGirl.create :ci_commit, project: project
+        @build2 = FactoryGirl.create :ci_build, commit: commit2
+
+        commits = [double(id: commit.sha), double(id: commit2.sha)]
+        allow(@merge_request).to receive(:commits).and_return(commits)
+        allow(MergeRequest).to receive_message_chain(:includes, :where, :reorder).and_return([@merge_request])
+      end
+
+      it 'returns the current MR' do
+        expect(@build2.merge_request.id).to eq(@merge_request.id)
+      end
+    end
+
+  end
 end
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index 6179882e93591f4556ddc9062b5c3ebba2dd14c0..6653621a83ed88e479963a448ad882e48ac40117 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -1,5 +1,18 @@
 require 'spec_helper'
 
+describe Mentionable do
+  include Mentionable
+
+  describe :references do
+    let(:project) { create(:project) }
+
+    it 'excludes JIRA references' do
+      allow(project).to receive_messages(jira_tracker?: true)
+      expect(referenced_mentionables(project, 'JIRA-123')).to be_empty
+    end
+  end
+end
+
 describe Issue, "Mentionable" do
   describe '#mentioned_users' do
     let!(:user) { create(:user, username: 'stranger') }
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
index a9b0b64e5deccaa9663f8a701936de37133f70a1..30c0a04b84045b315094c1fb9a9b380de70f4a53 100644
--- a/spec/models/concerns/token_authenticatable_spec.rb
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -2,7 +2,8 @@ require 'spec_helper'
 
 shared_examples 'TokenAuthenticatable' do
   describe 'dynamically defined methods' do
-    it { expect(described_class).to be_private_method_defined(:generate_token_for) }
+    it { expect(described_class).to be_private_method_defined(:generate_token) }
+    it { expect(described_class).to be_private_method_defined(:write_new_token) }
     it { expect(described_class).to respond_to("find_by_#{token_field}") }
     it { is_expected.to respond_to("ensure_#{token_field}") }
     it { is_expected.to respond_to("reset_#{token_field}!") }
@@ -24,11 +25,11 @@ describe ApplicationSetting, 'TokenAuthenticatable' do
   it_behaves_like 'TokenAuthenticatable'
 
   describe 'generating new token' do
-    subject { described_class.new }
-    let(:token) { subject.send(token_field) }
-
     context 'token is not generated yet' do
-      it { expect(token).to be nil }
+      describe 'token field accessor' do
+        subject { described_class.new.send(token_field) }
+        it { is_expected.to_not be_blank }
+      end
 
       describe 'ensured token' do
         subject { described_class.new.send("ensure_#{token_field}") }
@@ -36,11 +37,21 @@ describe ApplicationSetting, 'TokenAuthenticatable' do
         it { is_expected.to be_a String }
         it { is_expected.to_not be_blank }
       end
+
+      describe 'ensured! token' do
+        subject { described_class.new.send("ensure_#{token_field}!") }
+
+        it 'should persist new token' do
+          expect(subject).to eq described_class.current[token_field]
+        end
+      end
     end
 
     context 'token is generated' do
       before { subject.send("reset_#{token_field}!") }
-      it { expect(token).to be_a String }
+      it 'persists a new token 'do
+        expect(subject.send(:read_attribute, token_field)).to be_a String
+      end
     end
   end
 
diff --git a/spec/models/jira_issue_spec.rb b/spec/models/jira_issue_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..1634265b439d1c18e8fd5ae4f010aa91cdc83cf1
--- /dev/null
+++ b/spec/models/jira_issue_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+describe JiraIssue do
+  let(:project) { create(:project) }
+  subject { JiraIssue.new('JIRA-123', project) }
+
+  describe 'id' do
+    subject { super().id }
+    it { is_expected.to eq('JIRA-123') }
+  end
+
+  describe 'iid' do
+    subject { super().iid }
+    it { is_expected.to eq('JIRA-123') }
+  end
+
+  describe 'to_s' do
+    subject { super().to_s }
+    it { is_expected.to eq('JIRA-123') }
+  end
+
+  describe :== do
+    specify { expect(subject).to eq(JiraIssue.new('JIRA-123', project)) }
+    specify { expect(subject).not_to eq(JiraIssue.new('JIRA-124', project)) }
+
+    it 'only compares with JiraIssues' do
+      expect(subject).not_to eq('JIRA-123')
+    end
+  end
+end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 1aeba9b2b3bcef80dbdf80053ac632b34be003af..e0653a8327d61ac6de3dfdac0c8090bbbfb1ac2f 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -164,6 +164,17 @@ describe MergeRequest, models: true do
 
       expect(subject.closes_issues).to include(issue2)
     end
+
+    context 'for a project with JIRA integration' do
+      let(:issue0) { JiraIssue.new('JIRA-123', subject.project) }
+      let(:issue1) { JiraIssue.new('FOOBAR-4567', subject.project) }
+
+      it 'returns sorted JiraIssues' do
+        allow(subject.project).to receive_messages(default_branch: subject.target_branch)
+
+        expect(subject.closes_issues).to eq([issue0, issue1])
+      end
+    end
   end
 
   describe "#work_in_progress?" do
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index 7d91ebe9ce652cd3f28befb0e0623271990f99fd..2f8193170aedf3009a9377879a2b4da0c7c11c08 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -26,6 +26,113 @@ describe JiraService, models: true do
     it { is_expected.to have_one :service_hook }
   end
 
+  describe "Execute" do
+    let(:user)    { create(:user) }
+    let(:project) { create(:project) }
+    let(:merge_request) { create(:merge_request) }
+
+    before do
+      @jira_service = JiraService.new
+      allow(@jira_service).to receive_messages(
+        project_id: project.id,
+        project: project,
+        service_hook: true,
+        project_url: 'http://jira.example.com',
+        username: 'gitlab_jira_username',
+        password: 'gitlab_jira_password'
+      )
+      @jira_service.save # will build API URL, as api_url was not specified above
+      @sample_data = Gitlab::PushDataBuilder.build_sample(project, user)
+      # https://github.com/bblimke/webmock#request-with-basic-authentication
+      @api_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123/transitions'
+      @comment_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123/comment'
+
+      WebMock.stub_request(:post, @api_url)
+      WebMock.stub_request(:post, @comment_url)
+    end
+
+    it "should call JIRA API" do
+      @jira_service.execute(merge_request, JiraIssue.new("JIRA-123", project))
+      expect(WebMock).to have_requested(:post, @comment_url).with(
+        body: /Issue solved with/
+      ).once
+    end
+
+    it "calls the api with jira_issue_transition_id" do
+      @jira_service.jira_issue_transition_id = 'this-is-a-custom-id'
+      @jira_service.execute(merge_request, JiraIssue.new("JIRA-123", project))
+      expect(WebMock).to have_requested(:post, @api_url).with(
+        body: /this-is-a-custom-id/
+      ).once
+    end
+  end
+
+  describe "Stored password invalidation" do
+    let(:project) { create(:project) }
+
+    context "when a password was previously set" do
+      before do
+        @jira_service = JiraService.create(
+          project: create(:project),
+          properties: {
+            api_url: 'http://jira.example.com/rest/api/2',
+            username: 'mic',
+            password: "password"
+          }
+        )
+      end
+
+      it "reset password if url changed" do
+        @jira_service.api_url = 'http://jira_edited.example.com/rest/api/2'
+        @jira_service.save
+        expect(@jira_service.password).to be_nil
+      end
+
+      it "does not reset password if username changed" do
+        @jira_service.username = "some_name"
+        @jira_service.save
+        expect(@jira_service.password).to eq("password")
+      end
+
+      it "does not reset password if new url is set together with password, even if it's the same password" do
+        @jira_service.api_url = 'http://jira_edited.example.com/rest/api/2'
+        @jira_service.password = 'password'
+        @jira_service.save
+        expect(@jira_service.password).to eq("password")
+        expect(@jira_service.api_url).to eq("http://jira_edited.example.com/rest/api/2")
+      end
+
+      it "should reset password if url changed, even if setter called multiple times" do
+        @jira_service.api_url = 'http://jira1.example.com/rest/api/2'
+        @jira_service.api_url = 'http://jira1.example.com/rest/api/2'
+        @jira_service.save
+        expect(@jira_service.password).to be_nil
+      end
+    end
+
+    context "when no password was previously set" do
+      before do
+        @jira_service = JiraService.create(
+          project: create(:project),
+          properties: {
+            api_url: 'http://jira.example.com/rest/api/2',
+            username: 'mic'
+          }
+        )
+      end
+
+      it "saves password if new url is set together with password" do
+        @jira_service.api_url = 'http://jira_edited.example.com/rest/api/2'
+        @jira_service.password = 'password'
+        @jira_service.save
+        expect(@jira_service.password).to eq("password")
+        expect(@jira_service.api_url).to eq("http://jira_edited.example.com/rest/api/2")
+      end
+
+    end
+  end
+
+
   describe "Validations" do
     context "active" do
       before do
@@ -78,11 +185,12 @@ describe JiraService, models: true do
 
     context 'when gitlab.yml was initialized' do
       before do
-        settings = { "jira" => {
-          "title" => "Jira",
-          "project_url" => "http://jira.sample/projects/project_a",
-          "issues_url" => "http://jira.sample/issues/:id",
-          "new_issue_url" => "http://jira.sample/projects/project_a/issues/new"
+        settings = {
+          "jira" => {
+            "title" => "Jira",
+            "project_url" => "http://jira.sample/projects/project_a",
+            "issues_url" => "http://jira.sample/issues/:id",
+            "new_issue_url" => "http://jira.sample/projects/project_a/issues/new"
           }
         }
         allow(Gitlab.config).to receive(:issues_tracker).and_return(settings)
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 376266c09559038fe1616c717d536c98b6025bc7..2f184bbaf92c50fffd79529ea173d84a89d50421 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -26,6 +26,7 @@
 #  bio                        :string(255)
 #  failed_attempts            :integer          default(0)
 #  locked_at                  :datetime
+#  unlock_token               :string(255)
 #  username                   :string(255)
 #  can_create_group           :boolean          default(TRUE), not null
 #  can_create_team            :boolean          default(TRUE), not null
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 01d2ec79482d8349b4b27f3725e435c9aac2669e..7f0f9454b1006a193e5f10470e50857973af4a4b 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -131,6 +131,7 @@ describe API::API, api: true  do
 
         expect(json_response).to satisfy do |response|
           response.one? do |entry|
+            entry.has_key?('permissions') &&
             entry['name'] == project.name &&
               entry['owner']['username'] == user.username
           end
@@ -382,6 +383,18 @@ describe API::API, api: true  do
     end
 
     describe 'permissions' do
+      context 'all projects' do
+        it 'Contains permission information' do
+          project.team << [user, :master]
+          get api("/projects", user)
+
+          expect(response.status).to eq(200)
+          expect(json_response.first['permissions']['project_access']['access_level']).
+              to eq(Gitlab::Access::MASTER)
+          expect(json_response.first['permissions']['group_access']).to be_nil
+        end
+      end
+
       context 'personal project' do
         it 'Sets project access and returns 200' do
           project.team << [user, :master]
diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb
index 567da013e6f22ac3a6872456c8b51714fe17ebc5..5942aa7a1b59f27cade4f9b0fe08018bd0a76ea4 100644
--- a/spec/requests/ci/api/runners_spec.rb
+++ b/spec/requests/ci/api/runners_spec.rb
@@ -8,7 +8,6 @@ describe Ci::API::API do
 
   before do
     stub_gitlab_calls
-    stub_application_setting(ensure_runners_registration_token: registration_token)
     stub_application_setting(runners_registration_token: registration_token)
   end
 
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index a04c242cf0e72a26069c7f4735bf74b80e81018b..c1080ef190aa2303641d110aa0d45a99b8fa805d 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -265,6 +265,75 @@ describe GitPushService, services: true do
         expect(Issue.find(issue.id)).to be_opened
       end
     end
+
+    # EE-only tests
+    context "for jira issue tracker" do
+      include JiraServiceHelper
+
+      let(:jira_tracker) { project.create_jira_service if project.jira_service.nil? }
+
+      before do
+        jira_service_settings
+
+        WebMock.stub_request(:post, jira_api_transition_url)
+        WebMock.stub_request(:post, jira_api_comment_url)
+        WebMock.stub_request(:get, jira_api_comment_url).to_return(body: jira_issue_comments)
+        WebMock.stub_request(:get, jira_api_test_url)
+
+        allow(closing_commit).to receive_messages({
+                                                    issue_closing_regex: Regexp.new(Gitlab.config.gitlab.issue_closing_pattern),
+                                                    safe_message: message,
+                                                    author_name: commit_author.name,
+                                                    author_email: commit_author.email
+                                                  })
+
+        allow(project.repository).to receive_messages(commits_between: [closing_commit])
+      end
+
+      after do
+        jira_tracker.destroy!
+      end
+
+      context "mentioning an issue" do
+        let(:message) { "this is some work.\n\nrelated to JIRA-1" }
+
+        it "should initiate one api call to jira server to mention the issue" do
+          service.execute(project, user, @oldrev, @newrev, @ref)
+
+          expect(WebMock).to have_requested(:post, jira_api_comment_url).with(
+            body: /mentioned this issue in/
+          ).once
+        end
+      end
+
+      context "closing an issue" do
+        let(:message) { "this is some work.\n\ncloses JIRA-1" }
+
+        it "should initiate one api call to jira server to close the issue" do
+          transition_body = {
+            transition: {
+              id: '2'
+            }
+          }.to_json
+
+          service.execute(project, user, @oldrev, @newrev, @ref)
+          expect(WebMock).to have_requested(:post, jira_api_transition_url).with(
+            body: transition_body
+          ).once
+        end
+
+        it "should initiate one api call to jira server to comment on the issue" do
+          comment_body = {
+            body: "Issue solved with [#{closing_commit.id}|http://localhost/#{project.path_with_namespace}/commit/#{closing_commit.id}]."
+          }.to_json
+
+          service.execute(project, user, @oldrev, @newrev, @ref)
+          expect(WebMock).to have_requested(:post, jira_api_comment_url).with(
+            body: comment_body
+          ).once
+        end
+      end
+    end
   end
 
   describe "empty project" do
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 0a4f9b230e890d6b48a528b7a931b01b6853c630..c9f828ae2f7a5e99f63a889e269885b5180e3bef 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -425,4 +425,65 @@ describe SystemNoteService, services: true do
       end
     end
   end
+
+  include JiraServiceHelper
+
+  describe 'JIRA integration' do
+    let(:project)    { create(:project) }
+    let(:author)     { create(:user) }
+    let(:issue)      { create(:issue, project: project) }
+    let(:mergereq)   { create(:merge_request, :simple, target_project: project, source_project: project) }
+    let(:jira_issue) { JiraIssue.new("JIRA-1", project)}
+    let(:jira_tracker) { project.create_jira_service if project.jira_service.nil? }
+    let(:commit)     { project.commit }
+
+    context 'in JIRA issue tracker' do
+      before do
+        jira_service_settings
+        WebMock.stub_request(:post, jira_api_comment_url)
+      end
+
+      after do
+        jira_tracker.destroy!
+      end
+
+      describe "new reference" do
+        before do
+          WebMock.stub_request(:get, jira_api_comment_url).to_return(body: jira_issue_comments)
+        end
+
+        subject { described_class.cross_reference(jira_issue, commit, author) }
+
+        it { is_expected.to eq(jira_status_message) }
+      end
+
+      describe "existing reference" do
+        before do
+          message = "[#{author.name}|http://localhost/u/#{author.username}] mentioned this issue in [a commit of #{project.path_with_namespace}|http://localhost/#{project.path_with_namespace}/commit/#{commit.id}]."
+          WebMock.stub_request(:get, jira_api_comment_url).to_return(body: "{\"comments\":[{\"body\":\"#{message}\"}]}")
+        end
+
+        subject { described_class.cross_reference(jira_issue, commit, author) }
+        it { is_expected.not_to eq(jira_status_message) }
+      end
+    end
+
+    context 'issue from an issue' do
+      context 'in JIRA issue tracker' do
+        before do
+          jira_service_settings
+          WebMock.stub_request(:post, jira_api_comment_url)
+          WebMock.stub_request(:get, jira_api_comment_url).to_return(body: jira_issue_comments)
+        end
+
+        after do
+          jira_tracker.destroy!
+        end
+
+        subject { described_class.cross_reference(jira_issue, issue, author) }
+
+        it { is_expected.to eq(jira_status_message) }
+      end
+    end
+  end
 end
diff --git a/spec/support/jira_service_helper.rb b/spec/support/jira_service_helper.rb
new file mode 100644
index 0000000000000000000000000000000000000000..a3f496359b1675f45aebf946ce24d8b1a7818f87
--- /dev/null
+++ b/spec/support/jira_service_helper.rb
@@ -0,0 +1,67 @@
+module JiraServiceHelper
+
+  def jira_service_settings
+    properties = {
+      "title"=>"JIRA tracker",
+      "project_url"=>"http://jira.example/issues/?jql=project=A",
+      "issues_url"=>"http://jira.example/browse/JIRA-1",
+      "new_issue_url"=>"http://jira.example/secure/CreateIssue.jspa",
+      "api_url"=>"http://jira.example/rest/api/2"
+    }
+
+    jira_tracker.update_attributes(properties: properties, active: true)
+  end
+
+  def jira_status_message
+    "JiraService SUCCESS 200: Successfully posted to #{jira_api_comment_url}."
+  end
+
+  def jira_issue_comments
+    "{\"startAt\":0,\"maxResults\":11,\"total\":11,
+      \"comments\":[{\"self\":\"http://0.0.0.0:4567/rest/api/2/issue/10002/comment/10609\",
+      \"id\":\"10609\",\"author\":{\"self\":\"http://0.0.0.0:4567/rest/api/2/user?username=gitlab\",
+      \"name\":\"gitlab\",\"emailAddress\":\"gitlab@example.com\",
+      \"avatarUrls\":{\"16x16\":\"http://0.0.0.0:4567/secure/useravatar?size=xsmall&avatarId=10122\",
+      \"24x24\":\"http://0.0.0.0:4567/secure/useravatar?size=small&avatarId=10122\",
+      \"32x32\":\"http://0.0.0.0:4567/secure/useravatar?size=medium&avatarId=10122\",
+      \"48x48\":\"http://0.0.0.0:4567/secure/useravatar?avatarId=10122\"},
+      \"displayName\":\"GitLab\",\"active\":true},
+      \"body\":\"[Administrator|http://localhost:3000/u/root] mentioned JIRA-1 in Merge request of [gitlab-org/gitlab-test|http://localhost:3000/gitlab-org/gitlab-test/merge_requests/2].\",
+      \"updateAuthor\":{\"self\":\"http://0.0.0.0:4567/rest/api/2/user?username=gitlab\",\"name\":\"gitlab\",\"emailAddress\":\"gitlab@example.com\",
+      \"avatarUrls\":{\"16x16\":\"http://0.0.0.0:4567/secure/useravatar?size=xsmall&avatarId=10122\",
+      \"24x24\":\"http://0.0.0.0:4567/secure/useravatar?size=small&avatarId=10122\",
+      \"32x32\":\"http://0.0.0.0:4567/secure/useravatar?size=medium&avatarId=10122\",
+      \"48x48\":\"http://0.0.0.0:4567/secure/useravatar?avatarId=10122\"},\"displayName\":\"GitLab\",\"active\":true},
+      \"created\":\"2015-02-12T22:47:07.826+0100\",
+      \"updated\":\"2015-02-12T22:47:07.826+0100\"},
+     {\"self\":\"http://0.0.0.0:4567/rest/api/2/issue/10002/comment/10700\",
+        \"id\":\"10700\",\"author\":{\"self\":\"http://0.0.0.0:4567/rest/api/2/user?username=gitlab\",
+        \"name\":\"gitlab\",\"emailAddress\":\"gitlab@example.com\",
+        \"avatarUrls\":{\"16x16\":\"http://0.0.0.0:4567/secure/useravatar?size=xsmall&avatarId=10122\",
+        \"24x24\":\"http://0.0.0.0:4567/secure/useravatar?size=small&avatarId=10122\",
+        \"32x32\":\"http://0.0.0.0:4567/secure/useravatar?size=medium&avatarId=10122\",
+        \"48x48\":\"http://0.0.0.0:4567/secure/useravatar?avatarId=10122\"},\"displayName\":\"GitLab\",\"active\":true},
+        \"body\":\"[Administrator|http://localhost:3000/u/root] mentioned this issue in [a commit of h5bp/html5-boilerplate|http://localhost:3000/h5bp/html5-boilerplate/commit/2439f77897122fbeee3bfd9bb692d3608848433e].\",
+        \"updateAuthor\":{\"self\":\"http://0.0.0.0:4567/rest/api/2/user?username=gitlab\",\"name\":\"gitlab\",\"emailAddress\":\"gitlab@example.com\",
+        \"avatarUrls\":{\"16x16\":\"http://0.0.0.0:4567/secure/useravatar?size=xsmall&avatarId=10122\",
+        \"24x24\":\"http://0.0.0.0:4567/secure/useravatar?size=small&avatarId=10122\",
+        \"32x32\":\"http://0.0.0.0:4567/secure/useravatar?size=medium&avatarId=10122\",
+        \"48x48\":\"http://0.0.0.0:4567/secure/useravatar?avatarId=10122\"},\"displayName\":\"GitLab\",\"active\":true},
+        \"created\":\"2015-04-01T03:45:55.667+0200\",
+        \"updated\":\"2015-04-01T03:45:55.667+0200\"
+      }
+      ]}"
+  end
+
+  def jira_api_comment_url
+    'http://jira.example/rest/api/2/issue/JIRA-1/comment'
+  end
+
+  def jira_api_transition_url
+    'http://jira.example/rest/api/2/issue/JIRA-1/transitions'
+  end
+
+  def jira_api_test_url
+    'http://jira.example/rest/api/2/myself'
+  end
+end