Commit 70a08ace authored by karen Carias's avatar karen Carias

fixed conflict

parents 53d40b8a 9b6f1c59
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 7.13.0 (unreleased) v 7.13.0 (unreleased)
- Only enable HSTS header for HTTPS and port 443 (Stan Hu)
- Fix user autocomplete for unauthenticated users accessing public projects (Stan Hu)
- Fix redirection to home page URL for unauthorized users (Daniel Gerhardt) - Fix redirection to home page URL for unauthorized users (Daniel Gerhardt)
- Add branch switching support for graphs (Daniel Gerhardt) - Add branch switching support for graphs (Daniel Gerhardt)
- Fix external issue tracker hook/test for HTTPS URLs (Daniel Gerhardt) - Fix external issue tracker hook/test for HTTPS URLs (Daniel Gerhardt)
- Remove link leading to a 404 error in Deploy Keys page (Stan Hu) - Remove link leading to a 404 error in Deploy Keys page (Stan Hu)
- Add support for unlocking users in admin settings (Stan Hu) - Add support for unlocking users in admin settings (Stan Hu)
- Add Irker service configuration options (Stan Hu) - Add Irker service configuration options (Stan Hu)
- Fix order of issues imported form GitHub (Hiroyuki Sato) - Fix order of issues imported from GitHub (Hiroyuki Sato)
- Bump rugments to 1.0.0beta8 to fix C prototype function highlighting (Jonathon Reinhart) - Bump rugments to 1.0.0beta8 to fix C prototype function highlighting (Jonathon Reinhart)
- Fix Merge Request webhook to properly fire "merge" action when accepted from the web UI - Fix Merge Request webhook to properly fire "merge" action when accepted from the web UI
- Add `two_factor_enabled` field to admin user API (Stan Hu) - Add `two_factor_enabled` field to admin user API (Stan Hu)
- Fix invalid timestamps in RSS feeds (Rowan Wookey) - Fix invalid timestamps in RSS feeds (Rowan Wookey)
- Fix error when deleting a user who has projects (Stan Hu)
- Fix downloading of patches on public merge requests when user logged out (Stan Hu) - Fix downloading of patches on public merge requests when user logged out (Stan Hu)
- The password for the default administrator (root) account has been changed from "5iveL!fe" to "password".
- Fix Error 500 when relative submodule resolves to a namespace that has a different name from its path (Stan Hu) - Fix Error 500 when relative submodule resolves to a namespace that has a different name from its path (Stan Hu)
- Extract the longest-matching ref from a commit path when multiple matches occur (Stan Hu) - Extract the longest-matching ref from a commit path when multiple matches occur (Stan Hu)
- Update maintenance documentation to explain no need to recompile asssets for omnibus installations (Stan Hu) - Update maintenance documentation to explain no need to recompile asssets for omnibus installations (Stan Hu)
...@@ -41,11 +41,17 @@ v 7.13.0 (unreleased) ...@@ -41,11 +41,17 @@ v 7.13.0 (unreleased)
- Allow users to be blocked and unblocked via the API - Allow users to be blocked and unblocked via the API
- Use native Postgres database cleaning during backup restore - Use native Postgres database cleaning during backup restore
- Redesign project page. Show README as default instead of activity. Move project activity to separate page - Redesign project page. Show README as default instead of activity. Move project activity to separate page
- Make left menu more hierarchical and less contextual by adding back item at top
- A fork can’t have a visibility level that is greater than the original project.
- Faster code search in repository and wiki. Fixes search page timeout for big repositories
- Allow administrators to disable 2FA for a specific user
- Add error message for SSH key linebreaks
v 7.12.2 v 7.12.2
- Correctly show anonymous authorized applications under Profile > Applications. - Correctly show anonymous authorized applications under Profile > Applications.
- Faster automerge check and merge itself when source and target branches are in same repository - Faster automerge check and merge itself when source and target branches are in same repository
- Audit log for user authentication - Audit log for user authentication
- Fix transferring of project to another group using the API.
v 7.12.1 v 7.12.1
- Fix error when deleting a user who has projects (Stan Hu) - Fix error when deleting a user who has projects (Stan Hu)
......
...@@ -231,19 +231,13 @@ group :development, :test do ...@@ -231,19 +231,13 @@ group :development, :test do
gem 'fuubar', '~> 2.0.0' gem 'fuubar', '~> 2.0.0'
gem 'pry-rails' gem 'pry-rails'
gem 'coveralls', require: false gem 'coveralls', '~> 0.8.2', require: false
gem 'database_cleaner', '~> 1.4.0' gem 'database_cleaner', '~> 1.4.0'
gem 'factory_girl_rails' gem 'factory_girl_rails'
gem 'rspec-rails', '~> 3.3.0' gem 'rspec-rails', '~> 3.3.0'
gem 'rubocop', '0.28.0', require: false gem 'rubocop', '0.28.0', require: false
gem 'spinach-rails' gem 'spinach-rails'
# rest-client is a coveralls dependency and not used directly in GitLab, but
# we specify a version here to pick up some security fixes.
# See https://github.com/rest-client/rest-client/issues/369
# and http://www.osvdb.org/show/osvdb/117461
gem 'rest-client', '~> 1.8.0'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826) # Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest', '~> 5.3.0' gem 'minitest', '~> 5.3.0'
......
...@@ -703,7 +703,7 @@ GEM ...@@ -703,7 +703,7 @@ GEM
underscore-rails (1.4.4) underscore-rails (1.4.4)
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.6) unf_ext (0.0.7.1)
unicorn (4.6.3) unicorn (4.6.3)
kgio (~> 2.6) kgio (~> 2.6)
rack rack
...@@ -759,7 +759,7 @@ DEPENDENCIES ...@@ -759,7 +759,7 @@ DEPENDENCIES
charlock_holmes charlock_holmes
coffee-rails coffee-rails
colored colored
coveralls coveralls (~> 0.8.2)
creole (~> 0.3.6) creole (~> 0.3.6)
d3_rails (~> 3.5.5) d3_rails (~> 3.5.5)
database_cleaner (~> 1.4.0) database_cleaner (~> 1.4.0)
...@@ -833,7 +833,6 @@ DEPENDENCIES ...@@ -833,7 +833,6 @@ DEPENDENCIES
redis-rails redis-rails
request_store request_store
rerun (~> 0.10.0) rerun (~> 0.10.0)
rest-client (~> 1.8.0)
rqrcode-rails3 rqrcode-rails3
rspec-rails (~> 3.3.0) rspec-rails (~> 3.3.0)
rubocop (= 0.28.0) rubocop (= 0.28.0)
......
...@@ -25,7 +25,7 @@ To use EE and get official support please [become a subscriber](https://about.gi ...@@ -25,7 +25,7 @@ To use EE and get official support please [become a subscriber](https://about.gi
## Code status ## Code status
- [![build status](https://ci.gitlab.org/projects/1/status.png?ref=master)](https://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch) - [![build status](https://ci.gitlab.com/projects/1/status.png?ref=master)](https://ci.gitlab.com/projects/1?ref=master) on ci.gitlab.com (master branch)
- [![Build Status](https://semaphoreapp.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/243338/badge.png)](https://semaphoreapp.com/gitlabhq/gitlabhq) - [![Build Status](https://semaphoreapp.com/api/v1/projects/2f1a5809-418b-4cc2-a1f4-819607579fe7/243338/badge.png)](https://semaphoreapp.com/gitlabhq/gitlabhq)
...@@ -62,7 +62,7 @@ The recommended way to install GitLab is using the provided [Omnibus packages](h ...@@ -62,7 +62,7 @@ The recommended way to install GitLab is using the provided [Omnibus packages](h
There are various other options to install GitLab, please refer to the [installation page on the GitLab website](https://about.gitlab.com/installation/) for more information. There are various other options to install GitLab, please refer to the [installation page on the GitLab website](https://about.gitlab.com/installation/) for more information.
You can access a new installation with the login **`root`** and password **`password`**, after login you are required to set a unique password. You can access a new installation with the login **`root`** and password **`5iveL!fe`**, after login you are required to set a unique password.
## Third-party applications ## Third-party applications
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#= require shortcuts_issuable #= require shortcuts_issuable
#= require shortcuts_network #= require shortcuts_network
#= require cal-heatmap #= require cal-heatmap
#= require jquery.nicescroll.min
#= require_tree . #= require_tree .
window.slugify = (text) -> window.slugify = (text) ->
...@@ -104,6 +105,8 @@ if location.hash ...@@ -104,6 +105,8 @@ if location.hash
window.addEventListener "hashchange", shiftWindow window.addEventListener "hashchange", shiftWindow
$ -> $ ->
$(".nicescroll").niceScroll(cursoropacitymax: '0.4', cursorcolor: '#FFF', cursorborder: "1px solid #FFF")
# Click a .js-select-on-focus field, select the contents # Click a .js-select-on-focus field, select the contents
$(".js-select-on-focus").on "focusin", -> $(".js-select-on-focus").on "focusin", ->
# Prevent a mouseup event from deselecting the input # Prevent a mouseup event from deselecting the input
......
...@@ -63,7 +63,6 @@ class Dispatcher ...@@ -63,7 +63,6 @@ class Dispatcher
when 'projects:commits:show' when 'projects:commits:show'
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
when 'projects:activity' when 'projects:activity'
new Activities()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
when 'projects:show' when 'projects:show'
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
......
...@@ -25,10 +25,10 @@ class @DropzoneInput ...@@ -25,10 +25,10 @@ class @DropzoneInput
form_dropzone = $(form).find('.div-dropzone') form_dropzone = $(form).find('.div-dropzone')
form_dropzone.parent().addClass "div-dropzone-wrapper" form_dropzone.parent().addClass "div-dropzone-wrapper"
form_dropzone.append divHover form_dropzone.append divHover
$(".div-dropzone-hover").append iconPaperclip form_dropzone.find(".div-dropzone-hover").append iconPaperclip
form_dropzone.append divSpinner form_dropzone.append divSpinner
$(".div-dropzone-spinner").append iconSpinner form_dropzone.find(".div-dropzone-spinner").append iconSpinner
$(".div-dropzone-spinner").css form_dropzone.find(".div-dropzone-spinner").css
"opacity": 0 "opacity": 0
"display": "none" "display": "none"
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
@loading.show() @loading.show()
$.ajax $.ajax
type: "GET" type: "GET"
url: location.href url: $(".content_list").data('href') || location.href
data: "limit=" + @limit + "&offset=" + @offset data: "limit=" + @limit + "&offset=" + @offset
complete: => complete: =>
@loading.hide() @loading.hide()
......
...@@ -109,7 +109,7 @@ ...@@ -109,7 +109,7 @@
font-size: 1.2em; font-size: 1.2em;
} }
blockquote p { blockquote {
color: #888; color: #888;
font-size: 15px; font-size: 15px;
line-height: 1.5; line-height: 1.5;
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
.sidebar-wrapper { .sidebar-wrapper {
position: fixed; position: fixed;
top: 0; top: 0;
bottom: 0;
overflow-y: auto;
overflow-x: hidden;
left: 0; left: 0;
height: 100%; height: 100%;
transition-duration: .3s; transition-duration: .3s;
...@@ -21,8 +24,9 @@ ...@@ -21,8 +24,9 @@
} }
.nav-sidebar { .nav-sidebar {
margin-top: 29 + $header-height;
margin-bottom: 50px;
transition-duration: .3s; transition-duration: .3s;
margin: 0;
list-style: none; list-style: none;
overflow: hidden; overflow: hidden;
...@@ -39,12 +43,12 @@ ...@@ -39,12 +43,12 @@
} }
a { a {
padding: 8px 15px;
font-size: 13px;
line-height: 18px;
color: $gray; color: $gray;
display: block; display: block;
text-decoration: none; text-decoration: none;
padding: 8px 15px;
font-size: 14px;
line-height: 20px;
padding-left: 16px; padding-left: 16px;
&:hover { &:hover {
...@@ -88,14 +92,17 @@ ...@@ -88,14 +92,17 @@
width: $sidebar_width; width: $sidebar_width;
.nav-sidebar { .nav-sidebar {
margin-top: 29px;
position: fixed;
top: $header-height;
width: $sidebar_width; width: $sidebar_width;
} }
.nav-sidebar li a{ .nav-sidebar li a{
width: 230px; width: 230px;
&.back-link {
i {
visibility: hidden;
}
}
} }
} }
} }
...@@ -108,15 +115,9 @@ ...@@ -108,15 +115,9 @@
width: $sidebar_collapsed_width; width: $sidebar_collapsed_width;
.nav-sidebar { .nav-sidebar {
margin-top: 29px;
position: fixed;
top: $header-height;
width: $sidebar_collapsed_width; width: $sidebar_collapsed_width;
li a { li a {
font-size: 14px;
padding: 8px 15px;
text-align: left;
padding-left: 16px; padding-left: 16px;
} }
} }
...@@ -175,7 +176,7 @@ ...@@ -175,7 +176,7 @@
} }
.sidebar-user { .sidebar-user {
position: absolute; position: fixed;
bottom: 0; bottom: 0;
width: $sidebar_width; width: $sidebar_width;
padding: 10px; padding: 10px;
......
...@@ -72,13 +72,28 @@ ul.notes { ...@@ -72,13 +72,28 @@ ul.notes {
.note { .note {
display: block; display: block;
position:relative; position:relative;
.note-body { .note-body {
overflow: auto; overflow: auto;
.note-text { .note-text {
overflow: auto; overflow: auto;
word-wrap: break-word; word-wrap: break-word;
@include md-typography; @include md-typography;
// Reset ul style types since we're nested inside a ul already
& > ul {
list-style-type: disc;
ul {
list-style-type: circle;
ul {
list-style-type: square;
}
}
}
// Reduce left padding of first task list ul element // Reduce left padding of first task list ul element
ul.task-list:first-child { ul.task-list:first-child {
padding-left: 10px; padding-left: 10px;
...@@ -94,6 +109,7 @@ ul.notes { ...@@ -94,6 +109,7 @@ ul.notes {
} }
} }
} }
.note-header { .note-header {
padding-bottom: 3px; padding-bottom: 3px;
} }
......
...@@ -35,9 +35,9 @@ ...@@ -35,9 +35,9 @@
.sidebar-wrapper { .sidebar-wrapper {
background: $color-darker; background: $color-darker;
border-right: 1px solid $color-darker;
.sidebar-user { .sidebar-user {
background: $color-darker;
color: $color-light; color: $color-light;
&:hover { &:hover {
......
...@@ -23,7 +23,8 @@ class Admin::ProjectsController < Admin::ApplicationController ...@@ -23,7 +23,8 @@ class Admin::ProjectsController < Admin::ApplicationController
end end
def transfer def transfer
::Projects::TransferService.new(@project, current_user, params.dup).execute namespace = Namespace.find_by(id: params[:new_namespace_id])
::Projects::TransferService.new(@project, current_user, params.dup).execute(namespace)
@project.reload @project.reload
redirect_to admin_namespace_project_path(@project.namespace, @project) redirect_to admin_namespace_project_path(@project.namespace, @project)
......
...@@ -55,6 +55,12 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -55,6 +55,12 @@ class Admin::UsersController < Admin::ApplicationController
end end
end end
def disable_two_factor
user.disable_two_factor!
redirect_to admin_user_path(user),
notice: 'Two-factor Authentication has been disabled for this user'
end
def create def create
opts = { opts = {
force_random_password: true, force_random_password: true,
......
...@@ -183,7 +183,10 @@ class ApplicationController < ActionController::Base ...@@ -183,7 +183,10 @@ class ApplicationController < ActionController::Base
headers['X-XSS-Protection'] = '1; mode=block' headers['X-XSS-Protection'] = '1; mode=block'
headers['X-UA-Compatible'] = 'IE=edge' headers['X-UA-Compatible'] = 'IE=edge'
headers['X-Content-Type-Options'] = 'nosniff' headers['X-Content-Type-Options'] = 'nosniff'
headers['Strict-Transport-Security'] = 'max-age=31536000' if Gitlab.config.gitlab.https # Enabling HSTS for non-standard ports would send clients to the wrong port
if Gitlab.config.gitlab.https and Gitlab.config.gitlab.port == 443
headers['Strict-Transport-Security'] = 'max-age=31536000'
end
end end
def add_gon_variables def add_gon_variables
......
class AutocompleteController < ApplicationController class AutocompleteController < ApplicationController
skip_before_action :authenticate_user!, only: [:users]
def users def users
begin
@users = @users =
if params[:project_id].present? if params[:project_id].present?
project = Project.find(params[:project_id]) project = Project.find(params[:project_id])
...@@ -13,10 +16,20 @@ class AutocompleteController < ApplicationController ...@@ -13,10 +16,20 @@ class AutocompleteController < ApplicationController
if can?(current_user, :read_group, group) if can?(current_user, :read_group, group)
group.users group.users
end end
else elsif current_user
User.all User.all
end end
rescue ActiveRecord::RecordNotFound
if current_user
return render json: {}, status: 404
end
end
if @users.nil? && current_user.nil?
authenticate_user!
end
@users ||= User.none
@users = @users.search(params[:search]) if params[:search].present? @users = @users.search(params[:search]) if params[:search].present?
@users = @users.active @users = @users.active
@users = @users.page(params[:page]).per(PER_PAGE) @users = @users.page(params[:page]).per(PER_PAGE)
......
...@@ -32,6 +32,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController ...@@ -32,6 +32,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController
params.require(:user).permit( params.require(:user).permit(
:color_scheme_id, :color_scheme_id,
:dashboard, :dashboard,
:project_view,
:theme_id :theme_id
) )
end end
......
...@@ -29,13 +29,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController ...@@ -29,13 +29,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
end end
def destroy def destroy
current_user.update_attributes({ current_user.disable_two_factor!
two_factor_enabled: false,
encrypted_otp_secret: nil,
encrypted_otp_secret_iv: nil,
encrypted_otp_secret_salt: nil,
otp_backup_codes: nil
})
redirect_to profile_account_path redirect_to profile_account_path
end end
......
...@@ -52,10 +52,11 @@ class ProjectsController < ApplicationController ...@@ -52,10 +52,11 @@ class ProjectsController < ApplicationController
end end
def transfer def transfer
transfer_params = params.permit(:new_namespace_id) namespace = Namespace.find_by(id: params[:new_namespace_id])
::Projects::TransferService.new(project, current_user, transfer_params).execute ::Projects::TransferService.new(project, current_user).execute(namespace)
if @project.errors[:namespace_id].present?
flash[:alert] = @project.errors[:namespace_id].first if @project.errors[:new_namespace].present?
flash[:alert] = @project.errors[:new_namespace].first
end end
end end
......
...@@ -28,7 +28,7 @@ module ApplicationSettingsHelper ...@@ -28,7 +28,7 @@ module ApplicationSettingsHelper
def restricted_level_checkboxes(help_block_id) def restricted_level_checkboxes(help_block_id)
Gitlab::VisibilityLevel.options.map do |name, level| Gitlab::VisibilityLevel.options.map do |name, level|
checked = restricted_visibility_levels(true).include?(level) checked = restricted_visibility_levels(true).include?(level)
css_class = 'btn btn-primary' css_class = 'btn'
css_class += ' active' if checked css_class += ' active' if checked
checkbox_name = 'application_setting[restricted_visibility_levels][]' checkbox_name = 'application_setting[restricted_visibility_levels][]'
......
...@@ -118,7 +118,7 @@ module GitlabMarkdownHelper ...@@ -118,7 +118,7 @@ module GitlabMarkdownHelper
# Returns a random markdown tip for use as a textarea placeholder # Returns a random markdown tip for use as a textarea placeholder
def random_markdown_tip def random_markdown_tip
"Tip: #{MARKDOWN_TIPS.sample}" MARKDOWN_TIPS.sample
end end
private private
......
...@@ -42,6 +42,13 @@ module PreferencesHelper ...@@ -42,6 +42,13 @@ module PreferencesHelper
end end
end end
def project_view_choices
[
['Readme (default)', :readme],
['Activity view', :activity]
]
end
def user_application_theme def user_application_theme
theme = Gitlab::Themes.by_id(current_user.try(:theme_id)) theme = Gitlab::Themes.by_id(current_user.try(:theme_id))
theme.css_class theme.css_class
...@@ -50,4 +57,9 @@ module PreferencesHelper ...@@ -50,4 +57,9 @@ module PreferencesHelper
def user_color_scheme_class def user_color_scheme_class
COLOR_SCHEMES[current_user.try(:color_scheme_id)] if defined?(current_user) COLOR_SCHEMES[current_user.try(:color_scheme_id)] if defined?(current_user)
end end
def prefer_readme?
!current_user ||
current_user.project_view == 'readme'
end
end end
...@@ -92,6 +92,16 @@ module ProjectsHelper ...@@ -92,6 +92,16 @@ module ProjectsHelper
end end
end end
def can_change_visibility_level?(project, current_user)
return false unless can?(current_user, :change_visibility_level, project)
if project.forked?
project.forked_from_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE
else
true
end
end
private private
def get_project_nav_tabs(project, current_user) def get_project_nav_tabs(project, current_user)
...@@ -238,16 +248,6 @@ module ProjectsHelper ...@@ -238,16 +248,6 @@ module ProjectsHelper
end end
end end
def service_field_value(type, value)
return value unless type == 'password'
if value.present?
"***********"
else
nil
end
end
def user_max_access_in_project(user, project) def user_max_access_in_project(user, project)
level = project.team.max_member_access(user) level = project.team.max_member_access(user)
......
...@@ -86,4 +86,10 @@ module VisibilityLevelHelper ...@@ -86,4 +86,10 @@ module VisibilityLevelHelper
def default_snippet_visibility def default_snippet_visibility
current_application_settings.default_snippet_visibility current_application_settings.default_snippet_visibility
end end
def skip_level?(form_model, level)
form_model.is_a?(Project) &&
form_model.forked? &&
!Gitlab::VisibilityLevel.allowed_fork_levels(form_model.forked_from_project.visibility_level).include?(level)
end
end end
...@@ -79,22 +79,36 @@ module Mentionable ...@@ -79,22 +79,36 @@ module Mentionable
end end
end end
# If the mentionable_text field is about to change, locate any *added* references and create cross references for # When a mentionable field is changed, creates cross-reference notes that
# them. Invoke from an observer's #before_save implementation. # don't already exist
def notice_added_references(p = project, a = author) def create_new_cross_references!(p = project, a = author)
ch = changed_attributes changes = detect_mentionable_changes
original, mentionable_changed = "", false
self.class.mentionable_attrs.each do |attr| return if changes.empty?
if ch[attr]
original << ch[attr]
mentionable_changed = true
end
end
# Only proceed if the saved changes actually include a chance to an attr_mentionable field. original_text = changes.collect { |_, vals| vals.first }.join(' ')
return unless mentionable_changed
preexisting = references(p, self.author, original) preexisting = references(p, self.author, original_text)
create_cross_references!(p, a, preexisting) create_cross_references!(p, a, preexisting)
end end
private
# Returns a Hash of changed mentionable fields
#
# Preference is given to the `changes` Hash, but falls back to
# `previous_changes` if it's empty (i.e., the changes have already been
# persisted).
#
# See ActiveModel::Dirty.
#
# Returns a Hash.
def detect_mentionable_changes
source = (changes.present? ? changes : previous_changes).dup
mentionable = self.class.mentionable_attrs
# Only include changed fields that are mentionable
source.select { |key, val| mentionable.include?(key) }
end
end end
...@@ -24,6 +24,7 @@ class Key < ActiveRecord::Base ...@@ -24,6 +24,7 @@ class Key < ActiveRecord::Base
validates :title, presence: true, length: { within: 0..255 } validates :title, presence: true, length: { within: 0..255 }
validates :key, presence: true, length: { within: 0..5000 }, format: { with: /\A(ssh|ecdsa)-.*\Z/ }, uniqueness: true validates :key, presence: true, length: { within: 0..5000 }, format: { with: /\A(ssh|ecdsa)-.*\Z/ }, uniqueness: true
validates :key, format: { without: /\n|\r/, message: 'should be a single line' }
validates :fingerprint, uniqueness: true, presence: { message: 'cannot be generated' } validates :fingerprint, uniqueness: true, presence: { message: 'cannot be generated' }
delegate :name, :email, to: :user, prefix: true delegate :name, :email, to: :user, prefix: true
......
...@@ -356,7 +356,7 @@ class Note < ActiveRecord::Base ...@@ -356,7 +356,7 @@ class Note < ActiveRecord::Base
end end
def set_references def set_references
notice_added_references(project, author) create_new_cross_references!(project, author)
end end
def editable? def editable?
......
...@@ -431,6 +431,40 @@ class Repository ...@@ -431,6 +431,40 @@ class Repository
end end
end end
def search_files(query, ref)
offset = 2
args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} #{query} #{ref || root_ref})
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end
def parse_search_result(result)
ref = nil
filename = nil
startline = 0
lines = result.lines
lines.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/
ref, filename, startline = line.split(':')
startline = startline.to_i - index
break
end
end
data = lines.map do |line|
line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '')
end
data = data.join("")
OpenStruct.new(
filename: filename,
ref: ref,
startline: startline,
data: data
)
end
private private
def cache def cache
......
...@@ -177,6 +177,10 @@ class User < ActiveRecord::Base ...@@ -177,6 +177,10 @@ class User < ActiveRecord::Base
# Note: When adding an option, it MUST go on the end of the array. # Note: When adding an option, it MUST go on the end of the array.
enum dashboard: [:projects, :stars] enum dashboard: [:projects, :stars]
# User's Project preference
# Note: When adding an option, it MUST go on the end of the array.
enum project_view: [:readme, :activity]
alias_attribute :private_token, :authentication_token alias_attribute :private_token, :authentication_token
delegate :path, to: :namespace, allow_nil: true, prefix: true delegate :path, to: :namespace, allow_nil: true, prefix: true
...@@ -322,6 +326,16 @@ class User < ActiveRecord::Base ...@@ -322,6 +326,16 @@ class User < ActiveRecord::Base
@reset_token @reset_token
end end
def disable_two_factor!
update_attributes(
two_factor_enabled: false,
encrypted_otp_secret: nil,
encrypted_otp_secret_iv: nil,
encrypted_otp_secret_salt: nil,
otp_backup_codes: nil
)
end
def namespace_uniq def namespace_uniq
namespace_name = self.username namespace_name = self.username
existing_namespace = Namespace.by_path(namespace_name) existing_namespace = Namespace.by_path(namespace_name)
......
...@@ -35,7 +35,7 @@ module Issues ...@@ -35,7 +35,7 @@ module Issues
create_title_change_note(issue, issue.previous_changes['title'].first) create_title_change_note(issue, issue.previous_changes['title'].first)
end end
issue.notice_added_references(issue.project, current_user) issue.create_new_cross_references!(issue.project, current_user)
execute_hooks(issue, 'update') execute_hooks(issue, 'update')
end end
......
...@@ -59,7 +59,7 @@ module MergeRequests ...@@ -59,7 +59,7 @@ module MergeRequests
merge_request.mark_as_unchecked merge_request.mark_as_unchecked
end end
merge_request.notice_added_references(merge_request.project, current_user) merge_request.create_new_cross_references!(merge_request.project, current_user)
execute_hooks(merge_request, 'update') execute_hooks(merge_request, 'update')
end end
......
...@@ -11,19 +11,16 @@ module Projects ...@@ -11,19 +11,16 @@ module Projects
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
class TransferError < StandardError; end class TransferError < StandardError; end
def execute def execute(new_namespace)
namespace_id = params[:new_namespace_id] if allowed_transfer?(current_user, project, new_namespace)
namespace = Namespace.find_by(id: namespace_id) transfer(project, new_namespace)
if allowed_transfer?(current_user, project, namespace)
transfer(project, namespace)
else else
project.errors.add(:namespace, 'is invalid') project.errors.add(:new_namespace, 'is invalid')
false false
end end
rescue Projects::TransferService::TransferError => ex rescue Projects::TransferService::TransferError => ex
project.reload project.reload
project.errors.add(:namespace_id, ex.message) project.errors.add(:new_namespace, ex.message)
false false
end end
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
%strong{class: @user.two_factor_enabled? ? 'cgreen' : 'cred'} %strong{class: @user.two_factor_enabled? ? 'cgreen' : 'cred'}
- if @user.two_factor_enabled? - if @user.two_factor_enabled?
Enabled Enabled
= link_to 'Disable', disable_two_factor_admin_user_path(@user), data: {confirm: 'Are you sure?'}, method: :patch, class: 'btn btn-xs btn-remove pull-right', title: 'Disable Two-factor Authentication'
- else - else
Disabled Disabled
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
- if event.created_project? - if event.created_project?
= cache [event, current_user] do = cache [event, current_user] do
= image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
= render "events/event/created_project", event: event = render "events/event/created_project", event: event
- else - else
= cache event do = cache event do
......
...@@ -7,14 +7,29 @@ ...@@ -7,14 +7,29 @@
%title= page_title %title= page_title
= favicon_link_tag 'favicon.ico' = favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application", :media => "all"
= stylesheet_link_tag "print", :media => "print" = stylesheet_link_tag "application", media: "all"
= stylesheet_link_tag "print", media: "print"
= javascript_include_tag "application" = javascript_include_tag "application"
= csrf_meta_tags = csrf_meta_tags
= include_gon = include_gon
%meta{name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1'} %meta{name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1'}
%meta{name: 'theme-color', content: '#474D57'} %meta{name: 'theme-color', content: '#474D57'}
-# Apple Safari/iOS home screen icons
= favicon_link_tag 'touch-icon-iphone.png', rel: 'apple-touch-icon'
= favicon_link_tag 'touch-icon-ipad.png', rel: 'apple-touch-icon', sizes: '76x76'
= favicon_link_tag 'touch-icon-iphone-retina.png', rel: 'apple-touch-icon', sizes: '120x120'
= favicon_link_tag 'touch-icon-ipad-retina.png', rel: 'apple-touch-icon', sizes: '152x152'
-# Windows 8 pinned site tile
%meta{name: 'msapplication-TileImage', content: image_url('msapplication-tile.png')}
%meta{name: 'msapplication-TileColor', content: '#30353E'}
= yield :meta_tags = yield :meta_tags
= render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id') = render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id')
......
.page-with-sidebar{ class: nav_sidebar_class } .page-with-sidebar{ class: nav_sidebar_class }
= render "layouts/broadcast" = render "layouts/broadcast"
.sidebar-wrapper .sidebar-wrapper.nicescroll
- if defined?(sidebar) && sidebar - if defined?(sidebar) && sidebar
= render "layouts/nav/#{sidebar}" = render "layouts/nav/#{sidebar}"
- elsif current_user - elsif current_user
......
%ul.nav.nav-sidebar %ul.nav.nav-sidebar
= nav_link do
= link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to Dashboard
%li.separate-item
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do = nav_link(path: 'groups#show', html_options: {class: 'home'}) do
= link_to group_path(@group), title: 'Home', data: {placement: 'right'} do = link_to group_path(@group), title: 'Home', data: {placement: 'right'} do
= icon('dashboard fw') = icon('dashboard fw')
%span %span
Activity Group
- if current_user - if current_user
= nav_link(controller: [:group, :milestones]) do = nav_link(controller: [:group, :milestones]) do
= link_to group_milestones_path(@group), title: 'Milestones', data: {placement: 'right'} do = link_to group_milestones_path(@group), title: 'Milestones', data: {placement: 'right'} do
......
%ul.nav.nav-sidebar %ul.nav.nav-sidebar
= nav_link do = nav_link do
= link_to group_path(@group), title: 'Back to group', data: {placement: 'right'} do = link_to group_path(@group), title: 'Back to group', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw') = icon('caret-square-o-left fw')
%span %span
Back to group Back to group
......
%ul.nav.nav-sidebar %ul.nav.nav-sidebar
= nav_link do
= link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to Dashboard
%li.separate-item
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
= link_to profile_path, title: 'Profile', data: {placement: 'right'} do = link_to profile_path, title: 'Profile', data: {placement: 'right'} do
= icon('user fw') = icon('user fw')
......
%ul.nav.nav-sidebar %ul.nav.nav-sidebar
- if @project.group
= nav_link do
= link_to group_path(@project.group), title: 'Back to group', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to Group
- else
= nav_link do
= link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to Dashboard
%li.separate-item
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do = nav_link(path: 'projects#show', html_options: {class: 'home'}) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project', data: {placement: 'right'} do = link_to project_path(@project), title: 'Project', class: 'shortcuts-project', data: {placement: 'right'} do
= icon('home fw') = icon('home fw')
......
%ul.nav.nav-sidebar %ul.nav.nav-sidebar
= nav_link do = nav_link do
= link_to project_path(@project), title: 'Back to project', data: {placement: 'right'} do = link_to project_path(@project), title: 'Back to project', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw') = icon('caret-square-o-left fw')
%span %span
Back to project Back to project
......
...@@ -38,5 +38,13 @@ ...@@ -38,5 +38,13 @@
= link_to('(?)', help_page_path('profile', 'preferences') + '#default-dashboard', target: '_blank') = link_to('(?)', help_page_path('profile', 'preferences') + '#default-dashboard', target: '_blank')
.col-sm-10 .col-sm-10
= f.select :dashboard, dashboard_choices, {}, class: 'form-control' = f.select :dashboard, dashboard_choices, {}, class: 'form-control'
.form-group
= f.label :project_view, class: 'control-label' do
Project view
= link_to('(?)', help_page_path('profile', 'preferences') + '#default-project-view', target: '_blank')
.col-sm-10
= f.select :project_view, project_view_choices, {}, class: 'form-control'
.help-block
Choose what content you want to see when visit project page
.panel-footer .panel-footer
= f.submit 'Save', class: 'btn btn-save' = f.submit 'Save', class: 'btn btn-save'
= render 'projects/last_push'
.hidden-xs
- if current_user
%ul.nav.nav-pills.event_filter.pull-right
%li
= link_to namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "Feed", class: 'rss-btn' do
%i.fa.fa-rss
= render 'shared/event_filter'
%hr
.content_list{:"data-href" => activity_project_path(@project)}
= spinner
:coffeescript
new Activities()
...@@ -23,4 +23,6 @@ ...@@ -23,4 +23,6 @@
= link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: @ref, format: 'zip'), class: 'btn', rel: 'nofollow' do = link_to archive_namespace_project_repository_path(@project.namespace, @project, ref: @ref, format: 'zip'), class: 'btn', rel: 'nofollow' do
%i.fa.fa-download %i.fa.fa-download
= render 'projects/buttons/dropdown'
= render "shared/clone_panel" = render "shared/clone_panel"
- if readme = @repository.readme
%article.readme-holder#README
.clearfix
.pull-right
&nbsp;
- if can?(current_user, :push_code, @project)
= link_to namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light' do
%i.fa.fa-pencil
.wiki
= cache(readme_cache_key) do
= render_readme(readme)
- else
%h3.page-title
This project does not have README yet
- if can?(current_user, :push_code, @project)
%p.slead
A
%code README
file contains information about other files in a repository and is commonly
distributed with computer software, forming part of its documentation.
%br
We recommend you to
= link_to "add README", new_readme_path, class: 'underlined-link'
file to the repository and GitLab will render it here instead of this message.
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
%input#zen-toggle-comment.zen-toggle-comment{ tabindex: '-1', type: 'checkbox' } %input#zen-toggle-comment.zen-toggle-comment{ tabindex: '-1', type: 'checkbox' }
.zen-backdrop .zen-backdrop
- classes << ' js-gfm-input markdown-area' - classes << ' js-gfm-input markdown-area'
= f.text_area attr, class: classes, placeholder: random_markdown_tip = f.text_area attr, class: classes, placeholder: ''
= link_to nil, class: 'zen-enter-link', tabindex: '-1' do = link_to nil, class: 'zen-enter-link', tabindex: '-1' do
%i.fa.fa-expand %i.fa.fa-expand
Edit in fullscreen Edit in fullscreen
......
= render 'projects/last_push' = render 'projects/activity'
.hidden-xs
- if current_user
%ul.nav.nav-pills.event_filter.pull-right
%li
= link_to namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "Feed", class: 'rss-btn' do
%i.fa.fa-rss
= render 'shared/event_filter'
%hr
.content_list
= spinner
- if current_user
%span.dropdown
%a.dropdown-toggle.btn.btn-new{href: '#', "data-toggle" => "dropdown"}
%i.fa.fa-plus
%ul.dropdown-menu
- if @project.issues_enabled && can?(current_user, :create_issue, @project)
%li
= link_to url_for_new_issue, title: "New Issue" do
New issue
- if @project.merge_requests_enabled && can?(current_user, :create_merge_request, @project)
%li
= link_to new_namespace_project_merge_request_path(@project.namespace, @project), title: "New Merge Request" do
New merge request
- if @project.snippets_enabled && can?(current_user, :create_snippet, @project)
%li
= link_to new_namespace_project_snippet_path(@project.namespace, @project), title: "New Snippet" do
New snippet
- if can?(current_user, :admin_project_member, @project)
%li
= link_to namespace_project_project_members_path(@project.namespace, @project), title: "New project member" do
New project member
- if can? current_user, :push_code, @project
%li.divider
%li
= link_to new_namespace_project_branch_path(@project.namespace, @project) do
New git branch
%li
= link_to new_namespace_project_tag_path(@project.namespace, @project) do
New git tag
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
.col-sm-10= f.select(:default_branch, @repository.branch_names, {}, {class: 'select2 select-wide'}) .col-sm-10= f.select(:default_branch, @repository.branch_names, {}, {class: 'select2 select-wide'})
= render 'shared/visibility_level', f: f, visibility_level: @project.visibility_level, can_change_visibility_level: can?(current_user, :change_visibility_level, @project), form_model: @project = render 'shared/visibility_level', f: f, visibility_level: @project.visibility_level, can_change_visibility_level: can_change_visibility_level?(@project, current_user), form_model: @project
.form-group .form-group
= f.label :tag_list, "Tags", class: 'control-label' = f.label :tag_list, "Tags", class: 'control-label'
......
...@@ -6,5 +6,5 @@ ...@@ -6,5 +6,5 @@
= pluralize label.open_issues_count, 'open issue' = pluralize label.open_issues_count, 'open issue'
- if can? current_user, :admin_label, @project - if can? current_user, :admin_label, @project
= link_to 'Edit', edit_namespace_project_label_path(@project.namespace, @project, label), class: 'btn' = link_to 'Edit', edit_namespace_project_label_path(@project.namespace, @project, label), class: 'btn btn-sm'
= link_to 'Remove', namespace_project_label_path(@project.namespace, @project, label), class: 'btn btn-remove remove-row', method: :delete, remote: true, data: {confirm: "Remove this label? Are you sure?"} = link_to 'Remove', namespace_project_label_path(@project.namespace, @project, label), class: 'btn btn-sm btn-remove remove-row', method: :delete, remote: true, data: {confirm: "Remove this label? Are you sure?"}
:plain :plain
$(".mr_source_commit").html("#{commit_to_html(@commit, @source_project, false)}"); $(".mr_source_commit").html("#{commit_to_html(@commit, @source_project, false)}");
$('.js-timeago').timeago()
:plain :plain
$(".mr_target_commit").html("#{commit_to_html(@commit, @target_project, false)}"); $(".mr_target_commit").html("#{commit_to_html(@commit, @target_project, false)}");
$('.js-timeago').timeago()
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
%li %li
The import will time out after 4 minutes. For big repositories, use a clone/push combination. The import will time out after 4 minutes. For big repositories, use a clone/push combination.
%li %li
To migrate an SVN repository, check out #{link_to "this document", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}. To migrate an SVN repository, check out #{link_to "this document", "http://doc.gitlab.com/ce/workflow/importing/migrating_from_svn.html"}.
%hr.prepend-botton-10 %hr.prepend-botton-10
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
= render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text js-task-list-field' = render 'projects/zen', f: f, attr: :note, classes: 'note_text js-note-text js-task-list-field'
.comment-hints.clearfix .comment-hints.clearfix
.pull-left Comments are parsed with #{link_to 'GitLab Flavored Markdown', help_page_path('markdown', 'markdown'),{ target: '_blank', tabindex: -1 }} .pull-left #{link_to 'Markdown ', help_page_path('markdown', 'markdown'),{ target: '_blank', tabindex: -1 }}
.pull-right Attach files by dragging &amp; dropping or #{link_to 'selecting them', '#', class: 'markdown-selector', tabindex: -1 }. .pull-right #{link_to 'Attach a file', '#', class: 'markdown-selector', tabindex: -1 }
.note-form-actions .note-form-actions
.buttons .buttons
......
...@@ -12,8 +12,14 @@ ...@@ -12,8 +12,14 @@
classes: 'note_text js-note-text' classes: 'note_text js-note-text'
.comment-hints.clearfix .comment-hints.clearfix
.pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }} .pull-left
.pull-right Attach files by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }. = link_to "Markdown ", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }
tip:
= random_markdown_tip
.pull-right
= link_to '#', class: 'markdown-selector', tabindex: -1 do
Attach a file
= icon('paperclip')
.error-alert .error-alert
.note-form-actions .note-form-actions
......
...@@ -41,31 +41,10 @@ ...@@ -41,31 +41,10 @@
%hr %hr
%section %section
- if readme = @repository.readme - if prefer_readme?
%article.readme-holder#README = render 'projects/readme'
.clearfix
.pull-right
&nbsp;
- if can?(current_user, :push_code, @project)
= link_to namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light' do
%i.fa.fa-pencil
.wiki
= cache(readme_cache_key) do
= render_readme(readme)
- else - else
%h3.page-title = render 'projects/activity'
This project does not have README yet
- if can?(current_user, :push_code, @project)
%p.slead
A
%code README
file contains information about other files in a repository and is commonly
distributed with computer software, forming part of its documentation.
%br
We recommend you to
= link_to "add README", new_readme_path, class: 'underlined-link'
file to the repository and GitLab will render it here instead of this message.
- if current_user - if current_user
......
- blob = @project.repository.parse_search_result(blob)
.blob-result .blob-result
.file-holder .file-holder
.file-title .file-title
......
- wiki_blob = @project.repository.parse_search_result(wiki_blob)
.blob-result .blob-result
.file-holder .file-holder
.file-title .file-title
......
- name = field[:name] - name = field[:name]
- title = field[:title] || name.humanize - title = field[:title] || name.humanize
- value = service_field_value(field[:type], @service.send(name)) - value = @service.send(name)
- type = field[:type] - type = field[:type]
- placeholder = field[:placeholder] - placeholder = field[:placeholder]
- choices = field[:choices] - choices = field[:choices]
...@@ -19,6 +19,6 @@ ...@@ -19,6 +19,6 @@
- elsif type == 'select' - elsif type == 'select'
= form.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" } = form.select name, options_for_select(choices, value ? value : default_choice), {}, { class: "form-control" }
- elsif type == 'password' - elsif type == 'password'
= form.password_field name, placeholder: value, class: 'form-control' = form.password_field name, value: value, class: 'form-control'
- if help - if help
%span.help-block= help %span.help-block= help
- Gitlab::VisibilityLevel.values.each do |level| - Gitlab::VisibilityLevel.values.each do |level|
- next if skip_level?(form_model, level)
.radio .radio
- restricted = restricted_visibility_levels.include?(level) - restricted = restricted_visibility_levels.include?(level)
= form.label "#{model_method}_#{level}" do = form.label "#{model_method}_#{level}" do
......
...@@ -159,6 +159,7 @@ Gitlab::Application.routes.draw do ...@@ -159,6 +159,7 @@ Gitlab::Application.routes.draw do
put :block put :block
put :unblock put :unblock
put :unlock put :unlock
patch :disable_two_factor
delete 'remove/:email_id', action: 'remove_email', as: 'remove_email' delete 'remove/:email_id', action: 'remove_email', as: 'remove_email'
end end
end end
......
...@@ -5,7 +5,7 @@ Gitlab::Seeder.quiet do ...@@ -5,7 +5,7 @@ Gitlab::Seeder.quiet do
s.email = 'admin@example.com' s.email = 'admin@example.com'
s.notification_email = 'admin@example.com' s.notification_email = 'admin@example.com'
s.username = 'root' s.username = 'root'
s.password = 'password' s.password = '5iveL!fe'
s.admin = true s.admin = true
s.projects_limit = 100 s.projects_limit = 100
s.confirmed_at = DateTime.now s.confirmed_at = DateTime.now
......
if ENV['GITLAB_ROOT_PASSWORD'].blank? if ENV['GITLAB_ROOT_PASSWORD'].blank?
password = 'password' password = '5iveL!fe'
expire_time = Time.now expire_time = Time.now
else else
password = ENV['GITLAB_ROOT_PASSWORD'] password = ENV['GITLAB_ROOT_PASSWORD']
......
class AddProjectViewToUsers < ActiveRecord::Migration
def change
add_column :users, :project_view, :integer, default: 0
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20150620233230) do ActiveRecord::Schema.define(version: 20150713160110) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -517,6 +517,7 @@ ActiveRecord::Schema.define(version: 20150620233230) do ...@@ -517,6 +517,7 @@ ActiveRecord::Schema.define(version: 20150620233230) do
t.text "otp_backup_codes" t.text "otp_backup_codes"
t.string "public_email", default: "", null: false t.string "public_email", default: "", null: false
t.integer "dashboard", default: 0 t.integer "dashboard", default: 0
t.integer "project_view", default: 0
end end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
......
...@@ -49,7 +49,8 @@ Parameters: ...@@ -49,7 +49,8 @@ Parameters:
"state": "active", "state": "active",
"created_at": "2012-04-29T08:46:00Z" "created_at": "2012-04-29T08:46:00Z"
}, },
"description":"fixed login page css paddings" "description":"fixed login page css paddings",
"work_in_progress": false
} }
] ]
``` ```
...@@ -94,7 +95,8 @@ Parameters: ...@@ -94,7 +95,8 @@ Parameters:
"state": "active", "state": "active",
"created_at": "2012-04-29T08:46:00Z" "created_at": "2012-04-29T08:46:00Z"
}, },
"description":"fixed login page css paddings" "description":"fixed login page css paddings",
"work_in_progress": false
} }
``` ```
...@@ -118,6 +120,7 @@ Parameters: ...@@ -118,6 +120,7 @@ Parameters:
"project_id": 4, "project_id": 4,
"title": "Blanditiis beatae suscipit hic assumenda et molestias nisi asperiores repellat et.", "title": "Blanditiis beatae suscipit hic assumenda et molestias nisi asperiores repellat et.",
"description": "Qui voluptatibus placeat ipsa alias quasi. Deleniti rem ut sint. Optio velit qui distinctio.", "description": "Qui voluptatibus placeat ipsa alias quasi. Deleniti rem ut sint. Optio velit qui distinctio.",
"work_in_progress": false,
"state": "reopened", "state": "reopened",
"created_at": "2015-02-02T19:49:39.159Z", "created_at": "2015-02-02T19:49:39.159Z",
"updated_at": "2015-02-02T20:08:49.959Z", "updated_at": "2015-02-02T20:08:49.959Z",
...@@ -336,14 +339,6 @@ Parameters: ...@@ -336,14 +339,6 @@ Parameters:
```json ```json
{ {
"author": {
"id": 1,
"username": "admin",
"email": "admin@example.com",
"name": "Administrator",
"blocked": false,
"created_at": "2012-04-29T08:46:00Z"
},
"note": "text1" "note": "text1"
} }
``` ```
......
...@@ -31,10 +31,7 @@ Parameters: ...@@ -31,10 +31,7 @@ Parameters:
"state": "active", "state": "active",
"created_at": "2013-09-30T13:46:01Z" "created_at": "2013-09-30T13:46:01Z"
}, },
"created_at": "2013-10-02T09:22:45Z", "created_at": "2013-10-02T09:22:45Z"
"system": true,
"upvote": false,
"downvote": false
}, },
{ {
"id": 305, "id": 305,
...@@ -48,10 +45,7 @@ Parameters: ...@@ -48,10 +45,7 @@ Parameters:
"state": "active", "state": "active",
"created_at": "2013-09-30T13:46:01Z" "created_at": "2013-09-30T13:46:01Z"
}, },
"created_at": "2013-10-02T09:56:03Z", "created_at": "2013-10-02T09:56:03Z"
"system": false,
"upvote": false,
"downvote": false
} }
] ]
``` ```
......
...@@ -404,7 +404,7 @@ NOTE: Supply `SANITIZE=true` environment variable to `gitlab:check` to omit proj ...@@ -404,7 +404,7 @@ NOTE: Supply `SANITIZE=true` environment variable to `gitlab:check` to omit proj
Visit YOUR_SERVER in your web browser for your first GitLab login. The setup has created a default admin account for you. You can use it to log in: Visit YOUR_SERVER in your web browser for your first GitLab login. The setup has created a default admin account for you. You can use it to log in:
root root
password 5iveL!fe
**Important Note:** On login you'll be prompted to change the password. **Important Note:** On login you'll be prompted to change the password.
......
...@@ -30,3 +30,9 @@ will be. Setting it to **Starred Projects** will make that Dashboard view the ...@@ -30,3 +30,9 @@ will be. Setting it to **Starred Projects** will make that Dashboard view the
default when signing in or clicking the application logo in the upper left. default when signing in or clicking the application logo in the upper left.
The default is **Your Projects**. The default is **Your Projects**.
### Default Project view
It allows user to choose what content he or she want to see on project page.
The default is **Readme**.
# From 6.x or 7.x to 7.12 # From 6.x or 7.x to 7.13
*Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.x-or-7.x-to-7.12.md) for the most up to date instructions.* *Make sure you view this [upgrade guide from the `master` branch](../../../master/doc/update/6.x-or-7.x-to-7.13.md) for the most up to date instructions.*
This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.12. This allows you to upgrade any version of GitLab from 6.0 and up (including 7.0 and up) to 7.13.
## Global issue numbers ## Global issue numbers
...@@ -71,7 +71,7 @@ sudo -u git -H git checkout -- db/schema.rb # local changes will be restored aut ...@@ -71,7 +71,7 @@ sudo -u git -H git checkout -- db/schema.rb # local changes will be restored aut
For GitLab Community Edition: For GitLab Community Edition:
```bash ```bash
sudo -u git -H git checkout 7-12-stable sudo -u git -H git checkout 7-13-stable
``` ```
OR OR
...@@ -79,7 +79,7 @@ OR ...@@ -79,7 +79,7 @@ OR
For GitLab Enterprise Edition: For GitLab Enterprise Edition:
```bash ```bash
sudo -u git -H git checkout 7-12-stable-ee sudo -u git -H git checkout 7-13-stable-ee
``` ```
## 4. Install additional packages ## 4. Install additional packages
...@@ -162,11 +162,11 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab ...@@ -162,11 +162,11 @@ sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
TIP: to see what changed in `gitlab.yml.example` in this release use next command: TIP: to see what changed in `gitlab.yml.example` in this release use next command:
``` ```
git diff 6-0-stable:config/gitlab.yml.example 7-12-stable:config/gitlab.yml.example git diff 6-0-stable:config/gitlab.yml.example 7-13-stable:config/gitlab.yml.example
``` ```
* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-12-stable/config/gitlab.yml.example but with your settings. * Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-13-stable/config/gitlab.yml.example but with your settings.
* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-12-stable/config/unicorn.rb.example but with your settings. * Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-13-stable/config/unicorn.rb.example but with your settings.
* Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.6.0/config.yml.example but with your settings. * Make `/home/git/gitlab-shell/config.yml` the same as https://gitlab.com/gitlab-org/gitlab-shell/blob/v2.6.0/config.yml.example but with your settings.
* Copy rack attack middleware config * Copy rack attack middleware config
...@@ -182,14 +182,14 @@ sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab ...@@ -182,14 +182,14 @@ sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab
### Change Nginx settings ### Change Nginx settings
* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-12-stable/lib/support/nginx/gitlab but with your settings. * HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-13-stable/lib/support/nginx/gitlab but with your settings.
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-12-stable/lib/support/nginx/gitlab-ssl but with your settings. * HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/7-13-stable/lib/support/nginx/gitlab-ssl but with your settings.
* A new `location /uploads/` section has been added that needs to have the same content as the existing `location @gitlab` section. * A new `location /uploads/` section has been added that needs to have the same content as the existing `location @gitlab` section.
### Check the version of /usr/local/bin/git ### Check the version of /usr/local/bin/git
If you installed Git from source into /usr/local/bin/git then please [check If you installed Git from source into /usr/local/bin/git then please [check
your version](7.11-to-7.12.md). your version](7.12-to-7.13.md).
## 9. Start application ## 9. Start application
......
# From 7.12 to 7.13
### 0. Double-check your Git version
**This notice applies only to /usr/local/bin/git**
If you compiled Git from source on your GitLab server then please double-check
that you are using a version that protects against CVE-2014-9390. For six
months after this vulnerability became known the GitLab installation guide
still contained instructions that would install the outdated, 'vulnerable' Git
version 2.1.2.
Run the following command to get your current Git version.
```
/usr/local/bin/git --version
```
If you see 'No such file or directory' then you did not install Git according
to the outdated instructions from the GitLab installation guide and you can go
to the next step 'Stop server' below.
If you see a version string then it should be v1.8.5.6, v1.9.5, v2.0.5, v2.1.4,
v2.2.1 or newer. You can use the [instructions in the GitLab source
installation
guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies)
to install a newer version of Git.
### 1. Stop server
sudo service gitlab stop
### 2. Backup
```bash
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
```
### 3. Get latest code
```bash
sudo -u git -H git fetch --all
sudo -u git -H git checkout -- db/schema.rb # local changes will be restored automatically
```
For GitLab Community Edition:
```bash
sudo -u git -H git checkout 7-13-stable
```
OR
For GitLab Enterprise Edition:
```bash
sudo -u git -H git checkout 7-13-stable-ee
```
### 4. Update gitlab-shell
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
sudo -u git -H git checkout v2.6.3
```
### 5. Install libs, migrations, etc.
```bash
cd /home/git/gitlab
# MySQL installations (note: the line below states '--without ... postgres')
sudo -u git -H bundle install --without development test postgres --deployment
# PostgreSQL installations (note: the line below states '--without ... mysql')
sudo -u git -H bundle install --without development test mysql --deployment
# Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
# Clean up assets and cache
sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
# Update init.d script
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
```
### 6. Update config files
#### New configuration options for `gitlab.yml`
There are new configuration options available for [`gitlab.yml`](config/gitlab.yml.example). View them with the command below and apply them to your current `gitlab.yml`.
```
git diff origin/7-12-stable:config/gitlab.yml.example origin/7-13-stable:config/gitlab.yml.example
``````
### 7. Start application
sudo service gitlab start
sudo service nginx restart
### 8. Check application status
Check if GitLab and its environment are configured correctly:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
To make sure you didn't miss anything run a more thorough check with:
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
If all items are green, then congratulations, the upgrade is complete!
## Things went south? Revert to previous version (7.12)
### 1. Revert the code to the previous version
Follow the [upgrade guide from 7.11 to 7.12](7.11-to-7.12.md), except for the database migration
(The backup is already migrated to the previous version)
### 2. Restore from the backup:
```bash
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
```
If you have more than one backup *.tar file(s) please add `BACKUP=timestamp_of_backup` to the command above.
...@@ -16,6 +16,7 @@ git clone https://github.com/gitlabhq/mysql-postgresql-converter.git -b gitlab ...@@ -16,6 +16,7 @@ git clone https://github.com/gitlabhq/mysql-postgresql-converter.git -b gitlab
cd mysql-postgresql-converter cd mysql-postgresql-converter
mysqldump --compatible=postgresql --default-character-set=utf8 -r gitlabhq_production.mysql -u root gitlabhq_production -p mysqldump --compatible=postgresql --default-character-set=utf8 -r gitlabhq_production.mysql -u root gitlabhq_production -p
python db_converter.py gitlabhq_production.mysql gitlabhq_production.psql python db_converter.py gitlabhq_production.mysql gitlabhq_production.psql
ed -s gitlabhq_production.psql < move_drop_indexes.ed
# Import the database dump as the application database user # Import the database dump as the application database user
sudo -u git psql -f gitlabhq_production.psql -d gitlabhq_production sudo -u git psql -f gitlabhq_production.psql -d gitlabhq_production
...@@ -56,6 +57,7 @@ sudo -u git -H git clone https://github.com/gitlabhq/mysql-postgresql-converter. ...@@ -56,6 +57,7 @@ sudo -u git -H git clone https://github.com/gitlabhq/mysql-postgresql-converter.
# Convert gitlabhq_production.mysql # Convert gitlabhq_production.mysql
sudo -u git -H mkdir db sudo -u git -H mkdir db
sudo -u git -H python mysql-postgresql-converter/db_converter.py gitlabhq_production.mysql db/database.sql sudo -u git -H python mysql-postgresql-converter/db_converter.py gitlabhq_production.mysql db/database.sql
sudo -u git -H ed -s db/database.sql < mysql-postgresql-converter/move_drop_indexes.ed
# Compress database backup # Compress database backup
sudo -u git -H gzip db/database.sql sudo -u git -H gzip db/database.sql
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
- [Groups](groups.md) - [Groups](groups.md)
- [Keyboard shortcuts](shortcuts.md) - [Keyboard shortcuts](shortcuts.md)
- [Labels](labels.md) - [Labels](labels.md)
- [Notifications](notifications.md) - [Notification emails](notifications.md)
- [Project Features](project_features.md) - [Project Features](project_features.md)
- [Project forking workflow](forking_workflow.md) - [Project forking workflow](forking_workflow.md)
- [Protected branches](protected_branches.md) - [Protected branches](protected_branches.md)
......
# GitLab Notifications # GitLab Notification Emails
GitLab has notifications system in place to notify a user of events important for the workflow. GitLab has a notification system in place to notify a user of events that are important for the workflow.
## Notification settings ## Notification settings
...@@ -67,5 +67,3 @@ Below is the table of events users can be notified of: ...@@ -67,5 +67,3 @@ Below is the table of events users can be notified of:
| Reopen merge request | Project members [1] | [1] higher than participating | | Reopen merge request | Project members [1] | [1] higher than participating |
| Merge merge request | MR author [1], MR assignee [2], project members [3] | [1] [2] not disabled, [3] higher than participating | | Merge merge request | MR author [1], MR assignee [2], project members [3] | [1] [2] not disabled, [3] higher than participating |
| New comment | Mentioned users [1], users participating [2], project members [3] | [1] [2] not disabled, [3] higher than participating | | New comment | Mentioned users [1], users participating [2], project members [3] | [1] [2] not disabled, [3] higher than participating |
...@@ -30,7 +30,9 @@ RUN ( \ ...@@ -30,7 +30,9 @@ RUN ( \
echo "" && \ echo "" && \
echo "# Docker options" && \ echo "# Docker options" && \
echo "# Prevent Postgres from trying to allocate 25% of total memory" && \ echo "# Prevent Postgres from trying to allocate 25% of total memory" && \
echo "postgresql['shared_buffers'] = '1MB'" ) >> /etc/gitlab/gitlab.rb echo "postgresql['shared_buffers'] = '1MB'" ) >> /etc/gitlab/gitlab.rb && \
mkdir -p /assets/ && \
cp /etc/gitlab/gitlab.rb /assets/gitlab.rb
# Expose web & ssh # Expose web & ssh
EXPOSE 443 80 22 EXPOSE 443 80 22
......
# GitLab Docker images # GitLab Docker images
## What is GitLab? The GitLab docker image is [available on Docker Hub](https://registry.hub.docker.com/u/gitlab/gitlab-ce/).
GitLab offers git repository management, code reviews, issue tracking, activity feeds, wikis. It has LDAP/AD integration, handles 25,000 users on a single server but can also run on a highly available active/active cluster.
Learn more on [https://about.gitlab.com](https://about.gitlab.com)
## After starting a container ## After starting a container
...@@ -13,7 +10,7 @@ It might take a while before the docker container is responding to queries. ...@@ -13,7 +10,7 @@ It might take a while before the docker container is responding to queries.
You can check the status with something like `sudo docker logs -f gitlab`. You can check the status with something like `sudo docker logs -f gitlab`.
You can login to the web interface with username `root` and password `password`. You can login to the web interface with username `root` and password `5iveL!fe`.
Next time, you can just use docker start and stop to run the container. Next time, you can just use docker start and stop to run the container.
...@@ -166,3 +163,5 @@ sudo docker push gitlab/gitlab-ce:latest ...@@ -166,3 +163,5 @@ sudo docker push gitlab/gitlab-ce:latest
## Troubleshooting ## Troubleshooting
Please see the [troubleshooting](troubleshooting.md) file in this directory. Please see the [troubleshooting](troubleshooting.md) file in this directory.
Note: We use `fig.yml` to have compatibility with fig and because docker-compose also supports it.
...@@ -13,4 +13,9 @@ function entrypoint() { ...@@ -13,4 +13,9 @@ function entrypoint() {
gitlab-ctl tail # tail all logs gitlab-ctl tail # tail all logs
} }
if [[ ! -e /etc/gitlab/gitlab.rb ]]; then
cp /assets/gitlab.rb /etc/gitlab/gitlab.rb
chmod 0600 /etc/gitlab/gitlab.rb
fi
entrypoint entrypoint
...@@ -8,7 +8,24 @@ ...@@ -8,7 +8,24 @@
"type": "DOCKER", "type": "DOCKER",
"docker": { "docker": {
"network": "HOST", "network": "HOST",
"image": "sytse/gitlab-ce:7.10.1" "image": "gitlab/gitlab-ce:latest"
},
"volumes": [
{
"containerPath": "/etc/gitlab",
"hostPath": "/var/data/etc/gitlab",
"mode": "RW"
},
{
"containerPath": "/var/opt/gitlab",
"hostPath": "/var/data/opt/gitlab",
"mode": "RW"
},
{
"containerPath": "/var/log/gitlab",
"hostPath": "/var/data/log/gitlab",
"mode": "RW"
} }
]
} }
} }
\ No newline at end of file
...@@ -4,6 +4,10 @@ Feature: Groups ...@@ -4,6 +4,10 @@ Feature: Groups
And "John Doe" is owner of group "Owned" And "John Doe" is owner of group "Owned"
And "John Doe" is guest of group "Guest" And "John Doe" is guest of group "Guest"
Scenario: I should have back to group button
When I visit group "Owned" page
Then I should see back to dashboard button
@javascript @javascript
Scenario: I should see group "Owned" dashboard list Scenario: I should see group "Owned" dashboard list
When I visit group "Owned" page When I visit group "Owned" page
......
...@@ -18,6 +18,15 @@ Feature: Project ...@@ -18,6 +18,15 @@ Feature: Project
Then I should see the default project avatar Then I should see the default project avatar
And I should not see the "Remove avatar" button And I should not see the "Remove avatar" button
Scenario: I should have back to group button
And project "Shop" belongs to group
And I visit project "Shop" page
Then I should see back to group button
Scenario: I should have back to group button
And I visit project "Shop" page
Then I should see back to dashboard button
Scenario: I should have readme on page Scenario: I should have readme on page
And I visit project "Shop" page And I visit project "Shop" page
Then I should see project "Shop" README Then I should see project "Shop" README
......
...@@ -5,6 +5,10 @@ class Spinach::Features::Groups < Spinach::FeatureSteps ...@@ -5,6 +5,10 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
include SharedUser include SharedUser
include Select2Helper include Select2Helper
step 'I should see back to dashboard button' do
expect(page).to have_content 'Back to Dashboard'
end
step 'gitlab user "Mike"' do step 'gitlab user "Mike"' do
create(:user, name: "Mike") create(:user, name: "Mike")
end end
......
...@@ -116,4 +116,18 @@ class Spinach::Features::Project < Spinach::FeatureSteps ...@@ -116,4 +116,18 @@ class Spinach::Features::Project < Spinach::FeatureSteps
step 'I should not see "Snippets" button' do step 'I should not see "Snippets" button' do
expect(page).not_to have_link 'Snippets' expect(page).not_to have_link 'Snippets'
end end
step 'project "Shop" belongs to group' do
group = create(:group)
@project.namespace = group
@project.save!
end
step 'I should see back to dashboard button' do
expect(page).to have_content 'Back to Dashboard'
end
step 'I should see back to group button' do
expect(page).to have_content 'Back to Group'
end
end end
...@@ -171,6 +171,7 @@ module API ...@@ -171,6 +171,7 @@ module API
expose :source_project_id, :target_project_id expose :source_project_id, :target_project_id
expose :label_names, as: :labels expose :label_names, as: :labels
expose :description expose :description
expose :work_in_progress?, as: :work_in_progress
expose :milestone, using: Entities::Milestone expose :milestone, using: Entities::Milestone
end end
...@@ -190,9 +191,6 @@ module API ...@@ -190,9 +191,6 @@ module API
expose :attachment_identifier, as: :attachment expose :attachment_identifier, as: :attachment
expose :author, using: Entities::UserBasic expose :author, using: Entities::UserBasic
expose :created_at expose :created_at
expose :system
expose :upvote?, as: :upvote
expose :downvote?, as: :downvote
end end
class MRNote < Grape::Entity class MRNote < Grape::Entity
......
...@@ -74,9 +74,9 @@ module API ...@@ -74,9 +74,9 @@ module API
# POST /groups/:id/projects/:project_id # POST /groups/:id/projects/:project_id
post ":id/projects/:project_id" do post ":id/projects/:project_id" do
authenticated_as_admin! authenticated_as_admin!
group = Group.find(params[:id]) group = Group.find_by(id: params[:id])
project = Project.find(params[:project_id]) project = Project.find(params[:project_id])
result = ::Projects::TransferService.new(project, current_user, namespace_id: group.id).execute result = ::Projects::TransferService.new(project, current_user).execute(group)
if result if result
present group present group
......
...@@ -47,6 +47,10 @@ module Gitlab ...@@ -47,6 +47,10 @@ module Gitlab
def valid_level?(level) def valid_level?(level)
options.has_value?(level) options.has_value?(level)
end end
def allowed_fork_levels(origin_level)
[PRIVATE, INTERNAL, PUBLIC].select{ |level| level <= origin_level }
end
end end
def private? def private?
......
...@@ -36,4 +36,32 @@ describe Admin::UsersController do ...@@ -36,4 +36,32 @@ describe Admin::UsersController do
expect(user.access_locked?).to be_falsey expect(user.access_locked?).to be_falsey
end end
end end
describe 'PATCH disable_two_factor' do
let(:user) { create(:user) }
it 'disables 2FA for the user' do
expect(user).to receive(:disable_two_factor!)
allow(subject).to receive(:user).and_return(user)
go
end
it 'redirects back' do
go
expect(response).to redirect_to(admin_user_path(user))
end
it 'displays an alert' do
go
expect(flash[:notice]).
to eq 'Two-factor Authentication has been disabled for this user'
end
def go
patch :disable_two_factor, id: user.to_param
end
end
end end
...@@ -9,34 +9,58 @@ describe AutocompleteController do ...@@ -9,34 +9,58 @@ describe AutocompleteController do
before do before do
sign_in(user) sign_in(user)
project.team << [user, :master] project.team << [user, :master]
get(:users, project_id: project.id)
end end
let(:body) { JSON.parse(response.body) } let(:body) { JSON.parse(response.body) }
describe 'GET #users with project ID' do
before do
get(:users, project_id: project.id)
end
it { expect(body).to be_kind_of(Array) } it { expect(body).to be_kind_of(Array) }
it { expect(body.size).to eq 1 } it { expect(body.size).to eq 1 }
it { expect(body.first["username"]).to eq user.username } it { expect(body.first["username"]).to eq user.username }
end end
describe 'GET #users with unknown project' do
before do
get(:users, project_id: 'unknown')
end
it { expect(response.status).to eq(404) }
end
end
context 'group members' do context 'group members' do
let(:group) { create(:group) } let(:group) { create(:group) }
before do before do
sign_in(user) sign_in(user)
group.add_owner(user) group.add_owner(user)
get(:users, group_id: group.id)
end end
let(:body) { JSON.parse(response.body) } let(:body) { JSON.parse(response.body) }
describe 'GET #users with group ID' do
before do
get(:users, group_id: group.id)
end
it { expect(body).to be_kind_of(Array) } it { expect(body).to be_kind_of(Array) }
it { expect(body.size).to eq 1 } it { expect(body.size).to eq 1 }
it { expect(body.first["username"]).to eq user.username } it { expect(body.first["username"]).to eq user.username }
end end
describe 'GET #users with unknown group ID' do
before do
get(:users, group_id: 'unknown')
end
it { expect(response.status).to eq(404) }
end
end
context 'all users' do context 'all users' do
before do before do
sign_in(user) sign_in(user)
...@@ -48,4 +72,52 @@ describe AutocompleteController do ...@@ -48,4 +72,52 @@ describe AutocompleteController do
it { expect(body).to be_kind_of(Array) } it { expect(body).to be_kind_of(Array) }
it { expect(body.size).to eq User.count } it { expect(body.size).to eq User.count }
end end
context 'unauthenticated user' do
let(:public_project) { create(:project, :public) }
let(:body) { JSON.parse(response.body) }
describe 'GET #users with public project' do
before do
public_project.team << [user, :guest]
get(:users, project_id: public_project.id)
end
it { expect(body).to be_kind_of(Array) }
it { expect(body.size).to eq 1 }
end
describe 'GET #users with project' do
before do
get(:users, project_id: project.id)
end
it { expect(response.status).to eq(302) }
end
describe 'GET #users with unknown project' do
before do
get(:users, project_id: 'unknown')
end
it { expect(response.status).to eq(302) }
end
describe 'GET #users with inaccessible group' do
before do
project.team << [user, :guest]
get(:users, group_id: user.namespace.id)
end
it { expect(response.status).to eq(302) }
end
describe 'GET #users with no project' do
before do
get(:users)
end
it { expect(response.status).to eq(302) }
end
end
end end
...@@ -106,18 +106,11 @@ describe Profiles::TwoFactorAuthsController do ...@@ -106,18 +106,11 @@ describe Profiles::TwoFactorAuthsController do
describe 'DELETE destroy' do describe 'DELETE destroy' do
let(:user) { create(:user, :two_factor) } let(:user) { create(:user, :two_factor) }
let!(:codes) { user.generate_otp_backup_codes! }
it 'clears all 2FA-related fields' do it 'disables two factor' do
expect(user).to be_two_factor_enabled expect(user).to receive(:disable_two_factor!)
expect(user.otp_backup_codes).not_to be_nil
expect(user.encrypted_otp_secret).not_to be_nil
delete :destroy delete :destroy
expect(user).not_to be_two_factor_enabled
expect(user.otp_backup_codes).to be_nil
expect(user.encrypted_otp_secret).to be_nil
end end
it 'redirects to profile_account_path' do it 'redirects to profile_account_path' do
......
...@@ -32,6 +32,7 @@ FactoryGirl.define do ...@@ -32,6 +32,7 @@ FactoryGirl.define do
before(:create) do |user| before(:create) do |user|
user.two_factor_enabled = true user.two_factor_enabled = true
user.otp_secret = User.generate_otp_secret(32) user.otp_secret = User.generate_otp_secret(32)
user.generate_otp_backup_codes!
end end
end end
......
require 'rails_helper'
feature 'Admin disables 2FA for a user', feature: true do
scenario 'successfully', js: true do
login_as(:admin)
user = create(:user, :two_factor)
edit_user(user)
page.within('.two-factor-status') do
click_link 'Disable'
end
page.within('.two-factor-status') do
expect(page).to have_content 'Disabled'
expect(page).not_to have_button 'Disable'
end
end
scenario 'for a user without 2FA enabled' do
login_as(:admin)
user = create(:user)
edit_user(user)
page.within('.two-factor-status') do
expect(page).not_to have_button 'Disable'
end
end
def edit_user(user)
visit admin_user_path(user)
end
end
...@@ -137,7 +137,7 @@ describe GitlabMarkdownHelper do ...@@ -137,7 +137,7 @@ describe GitlabMarkdownHelper do
describe 'random_markdown_tip' do describe 'random_markdown_tip' do
it 'returns a random Markdown tip' do it 'returns a random Markdown tip' do
stub_const("#{described_class}::MARKDOWN_TIPS", ['Random tip']) stub_const("#{described_class}::MARKDOWN_TIPS", ['Random tip'])
expect(random_markdown_tip).to eq 'Tip: Random tip' expect(random_markdown_tip).to eq 'Random tip'
end end
end end
end end
...@@ -8,4 +8,48 @@ describe ProjectsHelper do ...@@ -8,4 +8,48 @@ describe ProjectsHelper do
expect(project_status_css_class("finished")).to eq("success") expect(project_status_css_class("finished")).to eq("success")
end end
end end
describe "can_change_visibility_level?" do
let(:project) { create(:project) }
let(:fork_project) do
fork_project = create(:forked_project_with_submodules)
fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
fork_project.save
fork_project
end
let(:user) { create(:user) }
it "returns false if there are no approipriate permissions" do
allow(helper).to receive(:can?) { false }
expect(helper.can_change_visibility_level?(project, user)).to be_falsey
end
it "returns true if there are permissions and it is not fork" do
allow(helper).to receive(:can?) { true }
expect(helper.can_change_visibility_level?(project, user)).to be_truthy
end
context "forks" do
it "returns false if there are permissions and origin project is PRIVATE" do
allow(helper).to receive(:can?) { true }
project.update visibility_level: Gitlab::VisibilityLevel::PRIVATE
expect(helper.can_change_visibility_level?(fork_project, user)).to be_falsey
end
it "returns true if there are permissions and origin project is INTERNAL" do
allow(helper).to receive(:can?) { true }
project.update visibility_level: Gitlab::VisibilityLevel::INTERNAL
expect(helper.can_change_visibility_level?(fork_project, user)).to be_truthy
end
end
end
end end
...@@ -72,4 +72,43 @@ describe VisibilityLevelHelper do ...@@ -72,4 +72,43 @@ describe VisibilityLevelHelper do
end end
end end
end end
describe "skip_level?" do
describe "forks" do
let(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::INTERNAL) }
let(:fork_project) { create(:forked_project_with_submodules) }
before do
fork_project.build_forked_project_link(forked_to_project_id: fork_project.id, forked_from_project_id: project.id)
fork_project.save
end
it "skips levels" do
expect(skip_level?(fork_project, Gitlab::VisibilityLevel::PUBLIC)).to be_truthy
expect(skip_level?(fork_project, Gitlab::VisibilityLevel::INTERNAL)).to be_falsey
expect(skip_level?(fork_project, Gitlab::VisibilityLevel::PRIVATE)).to be_falsey
end
end
describe "non-forked project" do
let(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::INTERNAL) }
it "skips levels" do
expect(skip_level?(project, Gitlab::VisibilityLevel::PUBLIC)).to be_falsey
expect(skip_level?(project, Gitlab::VisibilityLevel::INTERNAL)).to be_falsey
expect(skip_level?(project, Gitlab::VisibilityLevel::PRIVATE)).to be_falsey
end
end
describe "Snippet" do
let(:snippet) { create(:snippet, visibility_level: Gitlab::VisibilityLevel::INTERNAL) }
it "skips levels" do
expect(skip_level?(snippet, Gitlab::VisibilityLevel::PUBLIC)).to be_falsey
expect(skip_level?(snippet, Gitlab::VisibilityLevel::INTERNAL)).to be_falsey
expect(skip_level?(snippet, Gitlab::VisibilityLevel::PRIVATE)).to be_falsey
end
end
end
end end
...@@ -28,4 +28,53 @@ describe Issue, "Mentionable" do ...@@ -28,4 +28,53 @@ describe Issue, "Mentionable" do
issue.create_cross_references!(project, author, [commit2]) issue.create_cross_references!(project, author, [commit2])
end end
end end
describe '#create_new_cross_references!' do
let(:project) { create(:project) }
let(:issues) { create_list(:issue, 2, project: project) }
context 'before changes are persisted' do
it 'ignores pre-existing references' do
issue = create_issue(description: issues[0].to_reference)
expect(SystemNoteService).not_to receive(:cross_reference)
issue.description = 'New description'
issue.create_new_cross_references!
end
it 'notifies new references' do
issue = create_issue(description: issues[0].to_reference)
expect(SystemNoteService).to receive(:cross_reference).with(issues[1], any_args)
issue.description = issues[1].to_reference
issue.create_new_cross_references!
end
end
context 'after changes are persisted' do
it 'ignores pre-existing references' do
issue = create_issue(description: issues[0].to_reference)
expect(SystemNoteService).not_to receive(:cross_reference)
issue.update_attributes(description: 'New description')
issue.create_new_cross_references!
end
it 'notifies new references' do
issue = create_issue(description: issues[0].to_reference)
expect(SystemNoteService).to receive(:cross_reference).with(issues[1], any_args)
issue.update_attributes(description: issues[1].to_reference)
issue.create_new_cross_references!
end
end
def create_issue(description:)
create(:issue, project: project, description: description)
end
end
end end
...@@ -63,7 +63,7 @@ describe Key do ...@@ -63,7 +63,7 @@ describe Key do
key = build(:key) key = build(:key)
# Not always the middle, but close enough # Not always the middle, but close enough
key.key = key.key[0..100] + ' ' + key.key[100..-1] key.key = key.key[0..100] + ' ' + key.key[101..-1]
expect(key).not_to be_valid expect(key).not_to be_valid
end end
...@@ -71,6 +71,12 @@ describe Key do ...@@ -71,6 +71,12 @@ describe Key do
it 'rejects the unfingerprintable key (not a key)' do it 'rejects the unfingerprintable key (not a key)' do
expect(build(:key, key: 'ssh-rsa an-invalid-key==')).not_to be_valid expect(build(:key, key: 'ssh-rsa an-invalid-key==')).not_to be_valid
end end
it 'rejects the multiple line key' do
key = build(:key)
key.key.gsub!(' ', "\n")
expect(key).not_to be_valid
end
end end
context 'callbacks' do context 'callbacks' do
......
...@@ -47,4 +47,28 @@ describe Repository do ...@@ -47,4 +47,28 @@ describe Repository do
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
end end
end end
describe "search_files" do
let(:results) { repository.search_files('feature', 'master') }
subject { results }
it { is_expected.to be_an Array }
describe 'result' do
subject { results.first }
it { is_expected.to be_an String }
it { expect(subject.lines[2]).to eq("master:CHANGELOG:188: - Feature: Replace teams with group membership\n") }
end
describe 'parsing result' do
subject { repository.parse_search_result(results.first) }
it { is_expected.to be_an OpenStruct }
it { expect(subject.filename).to eq('CHANGELOG') }
it { expect(subject.ref).to eq('master') }
it { expect(subject.startline).to eq(186) }
it { expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n") }
end
end
end end
...@@ -217,6 +217,24 @@ describe User do ...@@ -217,6 +217,24 @@ describe User do
end end
end end
describe '#disable_two_factor!' do
it 'clears all 2FA-related fields' do
user = create(:user, :two_factor)
expect(user).to be_two_factor_enabled
expect(user.encrypted_otp_secret).not_to be_nil
expect(user.otp_backup_codes).not_to be_nil
user.disable_two_factor!
expect(user).not_to be_two_factor_enabled
expect(user.encrypted_otp_secret).to be_nil
expect(user.encrypted_otp_secret_iv).to be_nil
expect(user.encrypted_otp_secret_salt).to be_nil
expect(user.otp_backup_codes).to be_nil
end
end
describe 'projects' do describe 'projects' do
before do before do
@user = create :user @user = create :user
......
...@@ -8,7 +8,7 @@ describe Projects::TransferService do ...@@ -8,7 +8,7 @@ describe Projects::TransferService do
context 'namespace -> namespace' do context 'namespace -> namespace' do
before do before do
group.add_owner(user) group.add_owner(user)
@result = transfer_project(project, user, new_namespace_id: group.id) @result = transfer_project(project, user, group)
end end
it { expect(@result).to be_truthy } it { expect(@result).to be_truthy }
...@@ -17,7 +17,7 @@ describe Projects::TransferService do ...@@ -17,7 +17,7 @@ describe Projects::TransferService do
context 'namespace -> no namespace' do context 'namespace -> no namespace' do
before do before do
@result = transfer_project(project, user, new_namespace_id: nil) @result = transfer_project(project, user, nil)
end end
it { expect(@result).to eq false } it { expect(@result).to eq false }
...@@ -26,14 +26,14 @@ describe Projects::TransferService do ...@@ -26,14 +26,14 @@ describe Projects::TransferService do
context 'namespace -> not allowed namespace' do context 'namespace -> not allowed namespace' do
before do before do
@result = transfer_project(project, user, new_namespace_id: group.id) @result = transfer_project(project, user, group)
end end
it { expect(@result).to eq false } it { expect(@result).to eq false }
it { expect(project.namespace).to eq(user.namespace) } it { expect(project.namespace).to eq(user.namespace) }
end end
def transfer_project(project, user, params) def transfer_project(project, user, new_namespace)
Projects::TransferService.new(project, user, params).execute Projects::TransferService.new(project, user).execute(new_namespace)
end end
end end
if ENV['SIMPLECOV']
require 'simplecov'
SimpleCov.start :rails
end
if ENV['COVERALLS']
require 'coveralls'
Coveralls.wear_merged!
end
ENV["RAILS_ENV"] ||= 'test' ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__) require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails' require 'rspec/rails'
require 'shoulda/matchers' require 'shoulda/matchers'
......
if ENV['SIMPLECOV']
require 'simplecov'
end
if ENV['COVERALLS']
require 'coveralls'
Coveralls.wear_merged!
end
...@@ -143,6 +143,6 @@ shared_examples 'an editable mentionable' do ...@@ -143,6 +143,6 @@ shared_examples 'an editable mentionable' do
end end
set_mentionable_text.call(new_text) set_mentionable_text.call(new_text)
subject.notice_added_references(project, author) subject.create_new_cross_references!(project, author)
end end
end end
/* jquery.nicescroll 3.6.0 InuYaksa*2014 MIT http://nicescroll.areaaperta.com */(function(f){"function"===typeof define&&define.amd?define(["jquery"],f):f(jQuery)})(function(f){var y=!1,D=!1,N=0,O=2E3,x=0,H=["webkit","ms","moz","o"],s=window.requestAnimationFrame||!1,t=window.cancelAnimationFrame||!1;if(!s)for(var P in H){var E=H[P];s||(s=window[E+"RequestAnimationFrame"]);t||(t=window[E+"CancelAnimationFrame"]||window[E+"CancelRequestAnimationFrame"])}var v=window.MutationObserver||window.WebKitMutationObserver||!1,I={zindex:"auto",cursoropacitymin:0,cursoropacitymax:1,cursorcolor:"#424242",
cursorwidth:"5px",cursorborder:"1px solid #fff",cursorborderradius:"5px",scrollspeed:60,mousescrollstep:24,touchbehavior:!1,hwacceleration:!0,usetransition:!0,boxzoom:!1,dblclickzoom:!0,gesturezoom:!0,grabcursorenabled:!0,autohidemode:!0,background:"",iframeautoresize:!0,cursorminheight:32,preservenativescrolling:!0,railoffset:!1,railhoffset:!1,bouncescroll:!0,spacebarenabled:!0,railpadding:{top:0,right:0,left:0,bottom:0},disableoutline:!0,horizrailenabled:!0,railalign:"right",railvalign:"bottom",
enabletranslate3d:!0,enablemousewheel:!0,enablekeyboard:!0,smoothscroll:!0,sensitiverail:!0,enablemouselockapi:!0,cursorfixedheight:!1,directionlockdeadzone:6,hidecursordelay:400,nativeparentscrolling:!0,enablescrollonselection:!0,overflowx:!0,overflowy:!0,cursordragspeed:.3,rtlmode:"auto",cursordragontouch:!1,oneaxismousemode:"auto",scriptpath:function(){var f=document.getElementsByTagName("script"),f=f[f.length-1].src.split("?")[0];return 0<f.split("/").length?f.split("/").slice(0,-1).join("/")+
"/":""}(),preventmultitouchscrolling:!0},F=!1,Q=function(){if(F)return F;var f=document.createElement("DIV"),c=f.style,h=navigator.userAgent,m=navigator.platform,d={haspointerlock:"pointerLockElement"in document||"webkitPointerLockElement"in document||"mozPointerLockElement"in document};d.isopera="opera"in window;d.isopera12=d.isopera&&"getUserMedia"in navigator;d.isoperamini="[object OperaMini]"===Object.prototype.toString.call(window.operamini);d.isie="all"in document&&"attachEvent"in f&&!d.isopera;
d.isieold=d.isie&&!("msInterpolationMode"in c);d.isie7=d.isie&&!d.isieold&&(!("documentMode"in document)||7==document.documentMode);d.isie8=d.isie&&"documentMode"in document&&8==document.documentMode;d.isie9=d.isie&&"performance"in window&&9<=document.documentMode;d.isie10=d.isie&&"performance"in window&&10==document.documentMode;d.isie11="msRequestFullscreen"in f&&11<=document.documentMode;d.isie9mobile=/iemobile.9/i.test(h);d.isie9mobile&&(d.isie9=!1);d.isie7mobile=!d.isie9mobile&&d.isie7&&/iemobile/i.test(h);
d.ismozilla="MozAppearance"in c;d.iswebkit="WebkitAppearance"in c;d.ischrome="chrome"in window;d.ischrome22=d.ischrome&&d.haspointerlock;d.ischrome26=d.ischrome&&"transition"in c;d.cantouch="ontouchstart"in document.documentElement||"ontouchstart"in window;d.hasmstouch=window.MSPointerEvent||!1;d.hasw3ctouch=window.PointerEvent||!1;d.ismac=/^mac$/i.test(m);d.isios=d.cantouch&&/iphone|ipad|ipod/i.test(m);d.isios4=d.isios&&!("seal"in Object);d.isios7=d.isios&&"webkitHidden"in document;d.isandroid=/android/i.test(h);
d.haseventlistener="addEventListener"in f;d.trstyle=!1;d.hastransform=!1;d.hastranslate3d=!1;d.transitionstyle=!1;d.hastransition=!1;d.transitionend=!1;m=["transform","msTransform","webkitTransform","MozTransform","OTransform"];for(h=0;h<m.length;h++)if("undefined"!=typeof c[m[h]]){d.trstyle=m[h];break}d.hastransform=!!d.trstyle;d.hastransform&&(c[d.trstyle]="translate3d(1px,2px,3px)",d.hastranslate3d=/translate3d/.test(c[d.trstyle]));d.transitionstyle=!1;d.prefixstyle="";d.transitionend=!1;for(var m=
"transition webkitTransition msTransition MozTransition OTransition OTransition KhtmlTransition".split(" "),n=" -webkit- -ms- -moz- -o- -o -khtml-".split(" "),p="transitionend webkitTransitionEnd msTransitionEnd transitionend otransitionend oTransitionEnd KhtmlTransitionEnd".split(" "),h=0;h<m.length;h++)if(m[h]in c){d.transitionstyle=m[h];d.prefixstyle=n[h];d.transitionend=p[h];break}d.ischrome26&&(d.prefixstyle=n[1]);d.hastransition=d.transitionstyle;a:{h=["-webkit-grab","-moz-grab","grab"];if(d.ischrome&&
!d.ischrome22||d.isie)h=[];for(m=0;m<h.length;m++)if(n=h[m],c.cursor=n,c.cursor==n){c=n;break a}c="url(//mail.google.com/mail/images/2/openhand.cur),n-resize"}d.cursorgrabvalue=c;d.hasmousecapture="setCapture"in f;d.hasMutationObserver=!1!==v;return F=d},R=function(k,c){function h(){var b=a.doc.css(e.trstyle);return b&&"matrix"==b.substr(0,6)?b.replace(/^.*\((.*)\)$/g,"$1").replace(/px/g,"").split(/, +/):!1}function m(){var b=a.win;if("zIndex"in b)return b.zIndex();for(;0<b.length&&9!=b[0].nodeType;){var g=
b.css("zIndex");if(!isNaN(g)&&0!=g)return parseInt(g);b=b.parent()}return!1}function d(b,g,q){g=b.css(g);b=parseFloat(g);return isNaN(b)?(b=w[g]||0,q=3==b?q?a.win.outerHeight()-a.win.innerHeight():a.win.outerWidth()-a.win.innerWidth():1,a.isie8&&b&&(b+=1),q?b:0):b}function n(b,g,q,c){a._bind(b,g,function(a){a=a?a:window.event;var c={original:a,target:a.target||a.srcElement,type:"wheel",deltaMode:"MozMousePixelScroll"==a.type?0:1,deltaX:0,deltaZ:0,preventDefault:function(){a.preventDefault?a.preventDefault():
a.returnValue=!1;return!1},stopImmediatePropagation:function(){a.stopImmediatePropagation?a.stopImmediatePropagation():a.cancelBubble=!0}};"mousewheel"==g?(c.deltaY=-.025*a.wheelDelta,a.wheelDeltaX&&(c.deltaX=-.025*a.wheelDeltaX)):c.deltaY=a.detail;return q.call(b,c)},c)}function p(b,g,c){var d,e;0==b.deltaMode?(d=-Math.floor(a.opt.mousescrollstep/54*b.deltaX),e=-Math.floor(a.opt.mousescrollstep/54*b.deltaY)):1==b.deltaMode&&(d=-Math.floor(b.deltaX*a.opt.mousescrollstep),e=-Math.floor(b.deltaY*a.opt.mousescrollstep));
g&&a.opt.oneaxismousemode&&0==d&&e&&(d=e,e=0,c&&(0>d?a.getScrollLeft()>=a.page.maxw:0>=a.getScrollLeft())&&(e=d,d=0));d&&(a.scrollmom&&a.scrollmom.stop(),a.lastdeltax+=d,a.debounced("mousewheelx",function(){var b=a.lastdeltax;a.lastdeltax=0;a.rail.drag||a.doScrollLeftBy(b)},15));if(e){if(a.opt.nativeparentscrolling&&c&&!a.ispage&&!a.zoomactive)if(0>e){if(a.getScrollTop()>=a.page.maxh)return!0}else if(0>=a.getScrollTop())return!0;a.scrollmom&&a.scrollmom.stop();a.lastdeltay+=e;a.debounced("mousewheely",
function(){var b=a.lastdeltay;a.lastdeltay=0;a.rail.drag||a.doScrollBy(b)},15)}b.stopImmediatePropagation();return b.preventDefault()}var a=this;this.version="3.6.0";this.name="nicescroll";this.me=c;this.opt={doc:f("body"),win:!1};f.extend(this.opt,I);this.opt.snapbackspeed=80;if(k)for(var G in a.opt)"undefined"!=typeof k[G]&&(a.opt[G]=k[G]);this.iddoc=(this.doc=a.opt.doc)&&this.doc[0]?this.doc[0].id||"":"";this.ispage=/^BODY|HTML/.test(a.opt.win?a.opt.win[0].nodeName:this.doc[0].nodeName);this.haswrapper=
!1!==a.opt.win;this.win=a.opt.win||(this.ispage?f(window):this.doc);this.docscroll=this.ispage&&!this.haswrapper?f(window):this.win;this.body=f("body");this.iframe=this.isfixed=this.viewport=!1;this.isiframe="IFRAME"==this.doc[0].nodeName&&"IFRAME"==this.win[0].nodeName;this.istextarea="TEXTAREA"==this.win[0].nodeName;this.forcescreen=!1;this.canshowonmouseevent="scroll"!=a.opt.autohidemode;this.page=this.view=this.onzoomout=this.onzoomin=this.onscrollcancel=this.onscrollend=this.onscrollstart=this.onclick=
this.ongesturezoom=this.onkeypress=this.onmousewheel=this.onmousemove=this.onmouseup=this.onmousedown=!1;this.scroll={x:0,y:0};this.scrollratio={x:0,y:0};this.cursorheight=20;this.scrollvaluemax=0;this.isrtlmode="auto"==this.opt.rtlmode?"rtl"==(this.win[0]==window?this.body:this.win).css("direction"):!0===this.opt.rtlmode;this.observerbody=this.observerremover=this.observer=this.scrollmom=this.scrollrunning=!1;do this.id="ascrail"+O++;while(document.getElementById(this.id));this.hasmousefocus=this.hasfocus=
this.zoomactive=this.zoom=this.selectiondrag=this.cursorfreezed=this.cursor=this.rail=!1;this.visibility=!0;this.hidden=this.locked=this.railslocked=!1;this.cursoractive=!0;this.wheelprevented=!1;this.overflowx=a.opt.overflowx;this.overflowy=a.opt.overflowy;this.nativescrollingarea=!1;this.checkarea=0;this.events=[];this.saved={};this.delaylist={};this.synclist={};this.lastdeltay=this.lastdeltax=0;this.detected=Q();var e=f.extend({},this.detected);this.ishwscroll=(this.canhwscroll=e.hastransform&&
a.opt.hwacceleration)&&a.haswrapper;this.hasreversehr=this.isrtlmode&&!e.iswebkit;this.istouchcapable=!1;!e.cantouch||e.isios||e.isandroid||!e.iswebkit&&!e.ismozilla||(this.istouchcapable=!0,e.cantouch=!1);a.opt.enablemouselockapi||(e.hasmousecapture=!1,e.haspointerlock=!1);this.debounced=function(b,g,c){var d=a.delaylist[b];a.delaylist[b]=g;d||setTimeout(function(){var g=a.delaylist[b];a.delaylist[b]=!1;g.call(a)},c)};var r=!1;this.synched=function(b,g){a.synclist[b]=g;(function(){r||(s(function(){r=
!1;for(var b in a.synclist){var g=a.synclist[b];g&&g.call(a);a.synclist[b]=!1}}),r=!0)})();return b};this.unsynched=function(b){a.synclist[b]&&(a.synclist[b]=!1)};this.css=function(b,g){for(var c in g)a.saved.css.push([b,c,b.css(c)]),b.css(c,g[c])};this.scrollTop=function(b){return"undefined"==typeof b?a.getScrollTop():a.setScrollTop(b)};this.scrollLeft=function(b){return"undefined"==typeof b?a.getScrollLeft():a.setScrollLeft(b)};var A=function(a,g,c,d,e,f,h){this.st=a;this.ed=g;this.spd=c;this.p1=
d||0;this.p2=e||1;this.p3=f||0;this.p4=h||1;this.ts=(new Date).getTime();this.df=this.ed-this.st};A.prototype={B2:function(a){return 3*a*a*(1-a)},B3:function(a){return 3*a*(1-a)*(1-a)},B4:function(a){return(1-a)*(1-a)*(1-a)},getNow:function(){var a=1-((new Date).getTime()-this.ts)/this.spd,g=this.B2(a)+this.B3(a)+this.B4(a);return 0>a?this.ed:this.st+Math.round(this.df*g)},update:function(a,g){this.st=this.getNow();this.ed=a;this.spd=g;this.ts=(new Date).getTime();this.df=this.ed-this.st;return this}};
if(this.ishwscroll){this.doc.translate={x:0,y:0,tx:"0px",ty:"0px"};e.hastranslate3d&&e.isios&&this.doc.css("-webkit-backface-visibility","hidden");this.getScrollTop=function(b){if(!b){if(b=h())return 16==b.length?-b[13]:-b[5];if(a.timerscroll&&a.timerscroll.bz)return a.timerscroll.bz.getNow()}return a.doc.translate.y};this.getScrollLeft=function(b){if(!b){if(b=h())return 16==b.length?-b[12]:-b[4];if(a.timerscroll&&a.timerscroll.bh)return a.timerscroll.bh.getNow()}return a.doc.translate.x};this.notifyScrollEvent=
function(a){var g=document.createEvent("UIEvents");g.initUIEvent("scroll",!1,!0,window,1);g.niceevent=!0;a.dispatchEvent(g)};var K=this.isrtlmode?1:-1;e.hastranslate3d&&a.opt.enabletranslate3d?(this.setScrollTop=function(b,g){a.doc.translate.y=b;a.doc.translate.ty=-1*b+"px";a.doc.css(e.trstyle,"translate3d("+a.doc.translate.tx+","+a.doc.translate.ty+",0px)");g||a.notifyScrollEvent(a.win[0])},this.setScrollLeft=function(b,g){a.doc.translate.x=b;a.doc.translate.tx=b*K+"px";a.doc.css(e.trstyle,"translate3d("+
a.doc.translate.tx+","+a.doc.translate.ty+",0px)");g||a.notifyScrollEvent(a.win[0])}):(this.setScrollTop=function(b,g){a.doc.translate.y=b;a.doc.translate.ty=-1*b+"px";a.doc.css(e.trstyle,"translate("+a.doc.translate.tx+","+a.doc.translate.ty+")");g||a.notifyScrollEvent(a.win[0])},this.setScrollLeft=function(b,g){a.doc.translate.x=b;a.doc.translate.tx=b*K+"px";a.doc.css(e.trstyle,"translate("+a.doc.translate.tx+","+a.doc.translate.ty+")");g||a.notifyScrollEvent(a.win[0])})}else this.getScrollTop=
function(){return a.docscroll.scrollTop()},this.setScrollTop=function(b){return a.docscroll.scrollTop(b)},this.getScrollLeft=function(){return a.detected.ismozilla&&a.isrtlmode?Math.abs(a.docscroll.scrollLeft()):a.docscroll.scrollLeft()},this.setScrollLeft=function(b){return a.docscroll.scrollLeft(a.detected.ismozilla&&a.isrtlmode?-b:b)};this.getTarget=function(a){return a?a.target?a.target:a.srcElement?a.srcElement:!1:!1};this.hasParent=function(a,g){if(!a)return!1;for(var c=a.target||a.srcElement||
a||!1;c&&c.id!=g;)c=c.parentNode||!1;return!1!==c};var w={thin:1,medium:3,thick:5};this.getDocumentScrollOffset=function(){return{top:window.pageYOffset||document.documentElement.scrollTop,left:window.pageXOffset||document.documentElement.scrollLeft}};this.getOffset=function(){if(a.isfixed){var b=a.win.offset(),g=a.getDocumentScrollOffset();b.top-=g.top;b.left-=g.left;return b}b=a.win.offset();if(!a.viewport)return b;g=a.viewport.offset();return{top:b.top-g.top,left:b.left-g.left}};this.updateScrollBar=
function(b){if(a.ishwscroll)a.rail.css({height:a.win.innerHeight()-(a.opt.railpadding.top+a.opt.railpadding.bottom)}),a.railh&&a.railh.css({width:a.win.innerWidth()-(a.opt.railpadding.left+a.opt.railpadding.right)});else{var g=a.getOffset(),c=g.top,e=g.left-(a.opt.railpadding.left+a.opt.railpadding.right),c=c+d(a.win,"border-top-width",!0),e=e+(a.rail.align?a.win.outerWidth()-d(a.win,"border-right-width")-a.rail.width:d(a.win,"border-left-width")),f=a.opt.railoffset;f&&(f.top&&(c+=f.top),a.rail.align&&
f.left&&(e+=f.left));a.railslocked||a.rail.css({top:c,left:e,height:(b?b.h:a.win.innerHeight())-(a.opt.railpadding.top+a.opt.railpadding.bottom)});a.zoom&&a.zoom.css({top:c+1,left:1==a.rail.align?e-20:e+a.rail.width+4});if(a.railh&&!a.railslocked){c=g.top;e=g.left;if(f=a.opt.railhoffset)f.top&&(c+=f.top),f.left&&(e+=f.left);b=a.railh.align?c+d(a.win,"border-top-width",!0)+a.win.innerHeight()-a.railh.height:c+d(a.win,"border-top-width",!0);e+=d(a.win,"border-left-width");a.railh.css({top:b-(a.opt.railpadding.top+
a.opt.railpadding.bottom),left:e,width:a.railh.width})}}};this.doRailClick=function(b,g,c){var e;a.railslocked||(a.cancelEvent(b),g?(g=c?a.doScrollLeft:a.doScrollTop,e=c?(b.pageX-a.railh.offset().left-a.cursorwidth/2)*a.scrollratio.x:(b.pageY-a.rail.offset().top-a.cursorheight/2)*a.scrollratio.y,g(e)):(g=c?a.doScrollLeftBy:a.doScrollBy,e=c?a.scroll.x:a.scroll.y,b=c?b.pageX-a.railh.offset().left:b.pageY-a.rail.offset().top,c=c?a.view.w:a.view.h,g(e>=b?c:-c)))};a.hasanimationframe=s;a.hascancelanimationframe=
t;a.hasanimationframe?a.hascancelanimationframe||(t=function(){a.cancelAnimationFrame=!0}):(s=function(a){return setTimeout(a,15-Math.floor(+new Date/1E3)%16)},t=clearInterval);this.init=function(){a.saved.css=[];if(e.isie7mobile||e.isoperamini)return!0;e.hasmstouch&&a.css(a.ispage?f("html"):a.win,{"-ms-touch-action":"none"});a.zindex="auto";a.zindex=a.ispage||"auto"!=a.opt.zindex?a.opt.zindex:m()||"auto";!a.ispage&&"auto"!=a.zindex&&a.zindex>x&&(x=a.zindex);a.isie&&0==a.zindex&&"auto"==a.opt.zindex&&
(a.zindex="auto");if(!a.ispage||!e.cantouch&&!e.isieold&&!e.isie9mobile){var b=a.docscroll;a.ispage&&(b=a.haswrapper?a.win:a.doc);e.isie9mobile||a.css(b,{"overflow-y":"hidden"});a.ispage&&e.isie7&&("BODY"==a.doc[0].nodeName?a.css(f("html"),{"overflow-y":"hidden"}):"HTML"==a.doc[0].nodeName&&a.css(f("body"),{"overflow-y":"hidden"}));!e.isios||a.ispage||a.haswrapper||a.css(f("body"),{"-webkit-overflow-scrolling":"touch"});var g=f(document.createElement("div"));g.css({position:"relative",top:0,"float":"right",
width:a.opt.cursorwidth,height:"0px","background-color":a.opt.cursorcolor,border:a.opt.cursorborder,"background-clip":"padding-box","-webkit-border-radius":a.opt.cursorborderradius,"-moz-border-radius":a.opt.cursorborderradius,"border-radius":a.opt.cursorborderradius});g.hborder=parseFloat(g.outerHeight()-g.innerHeight());g.addClass("nicescroll-cursors");a.cursor=g;var c=f(document.createElement("div"));c.attr("id",a.id);c.addClass("nicescroll-rails nicescroll-rails-vr");var d,h,k=["left","right",
"top","bottom"],J;for(J in k)h=k[J],(d=a.opt.railpadding[h])?c.css("padding-"+h,d+"px"):a.opt.railpadding[h]=0;c.append(g);c.width=Math.max(parseFloat(a.opt.cursorwidth),g.outerWidth());c.css({width:c.width+"px",zIndex:a.zindex,background:a.opt.background,cursor:"default"});c.visibility=!0;c.scrollable=!0;c.align="left"==a.opt.railalign?0:1;a.rail=c;g=a.rail.drag=!1;!a.opt.boxzoom||a.ispage||e.isieold||(g=document.createElement("div"),a.bind(g,"click",a.doZoom),a.bind(g,"mouseenter",function(){a.zoom.css("opacity",
a.opt.cursoropacitymax)}),a.bind(g,"mouseleave",function(){a.zoom.css("opacity",a.opt.cursoropacitymin)}),a.zoom=f(g),a.zoom.css({cursor:"pointer","z-index":a.zindex,backgroundImage:"url("+a.opt.scriptpath+"zoomico.png)",height:18,width:18,backgroundPosition:"0px 0px"}),a.opt.dblclickzoom&&a.bind(a.win,"dblclick",a.doZoom),e.cantouch&&a.opt.gesturezoom&&(a.ongesturezoom=function(b){1.5<b.scale&&a.doZoomIn(b);.8>b.scale&&a.doZoomOut(b);return a.cancelEvent(b)},a.bind(a.win,"gestureend",a.ongesturezoom)));
a.railh=!1;var l;a.opt.horizrailenabled&&(a.css(b,{"overflow-x":"hidden"}),g=f(document.createElement("div")),g.css({position:"absolute",top:0,height:a.opt.cursorwidth,width:"0px","background-color":a.opt.cursorcolor,border:a.opt.cursorborder,"background-clip":"padding-box","-webkit-border-radius":a.opt.cursorborderradius,"-moz-border-radius":a.opt.cursorborderradius,"border-radius":a.opt.cursorborderradius}),e.isieold&&g.css({overflow:"hidden"}),g.wborder=parseFloat(g.outerWidth()-g.innerWidth()),
g.addClass("nicescroll-cursors"),a.cursorh=g,l=f(document.createElement("div")),l.attr("id",a.id+"-hr"),l.addClass("nicescroll-rails nicescroll-rails-hr"),l.height=Math.max(parseFloat(a.opt.cursorwidth),g.outerHeight()),l.css({height:l.height+"px",zIndex:a.zindex,background:a.opt.background}),l.append(g),l.visibility=!0,l.scrollable=!0,l.align="top"==a.opt.railvalign?0:1,a.railh=l,a.railh.drag=!1);a.ispage?(c.css({position:"fixed",top:"0px",height:"100%"}),c.align?c.css({right:"0px"}):c.css({left:"0px"}),
a.body.append(c),a.railh&&(l.css({position:"fixed",left:"0px",width:"100%"}),l.align?l.css({bottom:"0px"}):l.css({top:"0px"}),a.body.append(l))):(a.ishwscroll?("static"==a.win.css("position")&&a.css(a.win,{position:"relative"}),b="HTML"==a.win[0].nodeName?a.body:a.win,f(b).scrollTop(0).scrollLeft(0),a.zoom&&(a.zoom.css({position:"absolute",top:1,right:0,"margin-right":c.width+4}),b.append(a.zoom)),c.css({position:"absolute",top:0}),c.align?c.css({right:0}):c.css({left:0}),b.append(c),l&&(l.css({position:"absolute",
left:0,bottom:0}),l.align?l.css({bottom:0}):l.css({top:0}),b.append(l))):(a.isfixed="fixed"==a.win.css("position"),b=a.isfixed?"fixed":"absolute",a.isfixed||(a.viewport=a.getViewport(a.win[0])),a.viewport&&(a.body=a.viewport,0==/fixed|absolute/.test(a.viewport.css("position"))&&a.css(a.viewport,{position:"relative"})),c.css({position:b}),a.zoom&&a.zoom.css({position:b}),a.updateScrollBar(),a.body.append(c),a.zoom&&a.body.append(a.zoom),a.railh&&(l.css({position:b}),a.body.append(l))),e.isios&&a.css(a.win,
{"-webkit-tap-highlight-color":"rgba(0,0,0,0)","-webkit-touch-callout":"none"}),e.isie&&a.opt.disableoutline&&a.win.attr("hideFocus","true"),e.iswebkit&&a.opt.disableoutline&&a.win.css({outline:"none"}));!1===a.opt.autohidemode?(a.autohidedom=!1,a.rail.css({opacity:a.opt.cursoropacitymax}),a.railh&&a.railh.css({opacity:a.opt.cursoropacitymax})):!0===a.opt.autohidemode||"leave"===a.opt.autohidemode?(a.autohidedom=f().add(a.rail),e.isie8&&(a.autohidedom=a.autohidedom.add(a.cursor)),a.railh&&(a.autohidedom=
a.autohidedom.add(a.railh)),a.railh&&e.isie8&&(a.autohidedom=a.autohidedom.add(a.cursorh))):"scroll"==a.opt.autohidemode?(a.autohidedom=f().add(a.rail),a.railh&&(a.autohidedom=a.autohidedom.add(a.railh))):"cursor"==a.opt.autohidemode?(a.autohidedom=f().add(a.cursor),a.railh&&(a.autohidedom=a.autohidedom.add(a.cursorh))):"hidden"==a.opt.autohidemode&&(a.autohidedom=!1,a.hide(),a.railslocked=!1);if(e.isie9mobile)a.scrollmom=new L(a),a.onmangotouch=function(){var b=a.getScrollTop(),c=a.getScrollLeft();
if(b==a.scrollmom.lastscrolly&&c==a.scrollmom.lastscrollx)return!0;var g=b-a.mangotouch.sy,e=c-a.mangotouch.sx;if(0!=Math.round(Math.sqrt(Math.pow(e,2)+Math.pow(g,2)))){var d=0>g?-1:1,f=0>e?-1:1,q=+new Date;a.mangotouch.lazy&&clearTimeout(a.mangotouch.lazy);80<q-a.mangotouch.tm||a.mangotouch.dry!=d||a.mangotouch.drx!=f?(a.scrollmom.stop(),a.scrollmom.reset(c,b),a.mangotouch.sy=b,a.mangotouch.ly=b,a.mangotouch.sx=c,a.mangotouch.lx=c,a.mangotouch.dry=d,a.mangotouch.drx=f,a.mangotouch.tm=q):(a.scrollmom.stop(),
a.scrollmom.update(a.mangotouch.sx-e,a.mangotouch.sy-g),a.mangotouch.tm=q,g=Math.max(Math.abs(a.mangotouch.ly-b),Math.abs(a.mangotouch.lx-c)),a.mangotouch.ly=b,a.mangotouch.lx=c,2<g&&(a.mangotouch.lazy=setTimeout(function(){a.mangotouch.lazy=!1;a.mangotouch.dry=0;a.mangotouch.drx=0;a.mangotouch.tm=0;a.scrollmom.doMomentum(30)},100)))}},c=a.getScrollTop(),l=a.getScrollLeft(),a.mangotouch={sy:c,ly:c,dry:0,sx:l,lx:l,drx:0,lazy:!1,tm:0},a.bind(a.docscroll,"scroll",a.onmangotouch);else{if(e.cantouch||
a.istouchcapable||a.opt.touchbehavior||e.hasmstouch){a.scrollmom=new L(a);a.ontouchstart=function(b){if(b.pointerType&&2!=b.pointerType&&"touch"!=b.pointerType)return!1;a.hasmoving=!1;if(!a.railslocked){var c;if(e.hasmstouch)for(c=b.target?b.target:!1;c;){var g=f(c).getNiceScroll();if(0<g.length&&g[0].me==a.me)break;if(0<g.length)return!1;if("DIV"==c.nodeName&&c.id==a.id)break;c=c.parentNode?c.parentNode:!1}a.cancelScroll();if((c=a.getTarget(b))&&/INPUT/i.test(c.nodeName)&&/range/i.test(c.type))return a.stopPropagation(b);
!("clientX"in b)&&"changedTouches"in b&&(b.clientX=b.changedTouches[0].clientX,b.clientY=b.changedTouches[0].clientY);a.forcescreen&&(g=b,b={original:b.original?b.original:b},b.clientX=g.screenX,b.clientY=g.screenY);a.rail.drag={x:b.clientX,y:b.clientY,sx:a.scroll.x,sy:a.scroll.y,st:a.getScrollTop(),sl:a.getScrollLeft(),pt:2,dl:!1};if(a.ispage||!a.opt.directionlockdeadzone)a.rail.drag.dl="f";else{var g=f(window).width(),d=f(window).height(),q=Math.max(document.body.scrollWidth,document.documentElement.scrollWidth),
h=Math.max(document.body.scrollHeight,document.documentElement.scrollHeight),d=Math.max(0,h-d),g=Math.max(0,q-g);a.rail.drag.ck=!a.rail.scrollable&&a.railh.scrollable?0<d?"v":!1:a.rail.scrollable&&!a.railh.scrollable?0<g?"h":!1:!1;a.rail.drag.ck||(a.rail.drag.dl="f")}a.opt.touchbehavior&&a.isiframe&&e.isie&&(g=a.win.position(),a.rail.drag.x+=g.left,a.rail.drag.y+=g.top);a.hasmoving=!1;a.lastmouseup=!1;a.scrollmom.reset(b.clientX,b.clientY);if(!e.cantouch&&!this.istouchcapable&&!b.pointerType){if(!c||
!/INPUT|SELECT|TEXTAREA/i.test(c.nodeName))return!a.ispage&&e.hasmousecapture&&c.setCapture(),a.opt.touchbehavior?(c.onclick&&!c._onclick&&(c._onclick=c.onclick,c.onclick=function(b){if(a.hasmoving)return!1;c._onclick.call(this,b)}),a.cancelEvent(b)):a.stopPropagation(b);/SUBMIT|CANCEL|BUTTON/i.test(f(c).attr("type"))&&(pc={tg:c,click:!1},a.preventclick=pc)}}};a.ontouchend=function(b){if(!a.rail.drag)return!0;if(2==a.rail.drag.pt){if(b.pointerType&&2!=b.pointerType&&"touch"!=b.pointerType)return!1;
a.scrollmom.doMomentum();a.rail.drag=!1;if(a.hasmoving&&(a.lastmouseup=!0,a.hideCursor(),e.hasmousecapture&&document.releaseCapture(),!e.cantouch))return a.cancelEvent(b)}else if(1==a.rail.drag.pt)return a.onmouseup(b)};var n=a.opt.touchbehavior&&a.isiframe&&!e.hasmousecapture;a.ontouchmove=function(b,c){if(!a.rail.drag||b.targetTouches&&a.opt.preventmultitouchscrolling&&1<b.targetTouches.length||b.pointerType&&2!=b.pointerType&&"touch"!=b.pointerType)return!1;if(2==a.rail.drag.pt){if(e.cantouch&&
e.isios&&"undefined"==typeof b.original)return!0;a.hasmoving=!0;a.preventclick&&!a.preventclick.click&&(a.preventclick.click=a.preventclick.tg.onclick||!1,a.preventclick.tg.onclick=a.onpreventclick);b=f.extend({original:b},b);"changedTouches"in b&&(b.clientX=b.changedTouches[0].clientX,b.clientY=b.changedTouches[0].clientY);if(a.forcescreen){var g=b;b={original:b.original?b.original:b};b.clientX=g.screenX;b.clientY=g.screenY}var d,g=d=0;n&&!c&&(d=a.win.position(),g=-d.left,d=-d.top);var q=b.clientY+
d;d=q-a.rail.drag.y;var h=b.clientX+g,u=h-a.rail.drag.x,k=a.rail.drag.st-d;a.ishwscroll&&a.opt.bouncescroll?0>k?k=Math.round(k/2):k>a.page.maxh&&(k=a.page.maxh+Math.round((k-a.page.maxh)/2)):(0>k&&(q=k=0),k>a.page.maxh&&(k=a.page.maxh,q=0));var l;a.railh&&a.railh.scrollable&&(l=a.isrtlmode?u-a.rail.drag.sl:a.rail.drag.sl-u,a.ishwscroll&&a.opt.bouncescroll?0>l?l=Math.round(l/2):l>a.page.maxw&&(l=a.page.maxw+Math.round((l-a.page.maxw)/2)):(0>l&&(h=l=0),l>a.page.maxw&&(l=a.page.maxw,h=0)));g=!1;if(a.rail.drag.dl)g=
!0,"v"==a.rail.drag.dl?l=a.rail.drag.sl:"h"==a.rail.drag.dl&&(k=a.rail.drag.st);else{d=Math.abs(d);var u=Math.abs(u),z=a.opt.directionlockdeadzone;if("v"==a.rail.drag.ck){if(d>z&&u<=.3*d)return a.rail.drag=!1,!0;u>z&&(a.rail.drag.dl="f",f("body").scrollTop(f("body").scrollTop()))}else if("h"==a.rail.drag.ck){if(u>z&&d<=.3*u)return a.rail.drag=!1,!0;d>z&&(a.rail.drag.dl="f",f("body").scrollLeft(f("body").scrollLeft()))}}a.synched("touchmove",function(){a.rail.drag&&2==a.rail.drag.pt&&(a.prepareTransition&&
a.prepareTransition(0),a.rail.scrollable&&a.setScrollTop(k),a.scrollmom.update(h,q),a.railh&&a.railh.scrollable?(a.setScrollLeft(l),a.showCursor(k,l)):a.showCursor(k),e.isie10&&document.selection.clear())});e.ischrome&&a.istouchcapable&&(g=!1);if(g)return a.cancelEvent(b)}else if(1==a.rail.drag.pt)return a.onmousemove(b)}}a.onmousedown=function(b,c){if(!a.rail.drag||1==a.rail.drag.pt){if(a.railslocked)return a.cancelEvent(b);a.cancelScroll();a.rail.drag={x:b.clientX,y:b.clientY,sx:a.scroll.x,sy:a.scroll.y,
pt:1,hr:!!c};var g=a.getTarget(b);!a.ispage&&e.hasmousecapture&&g.setCapture();a.isiframe&&!e.hasmousecapture&&(a.saved.csspointerevents=a.doc.css("pointer-events"),a.css(a.doc,{"pointer-events":"none"}));a.hasmoving=!1;return a.cancelEvent(b)}};a.onmouseup=function(b){if(a.rail.drag){if(1!=a.rail.drag.pt)return!0;e.hasmousecapture&&document.releaseCapture();a.isiframe&&!e.hasmousecapture&&a.doc.css("pointer-events",a.saved.csspointerevents);a.rail.drag=!1;a.hasmoving&&a.triggerScrollEnd();return a.cancelEvent(b)}};
a.onmousemove=function(b){if(a.rail.drag&&1==a.rail.drag.pt){if(e.ischrome&&0==b.which)return a.onmouseup(b);a.cursorfreezed=!0;a.hasmoving=!0;if(a.rail.drag.hr){a.scroll.x=a.rail.drag.sx+(b.clientX-a.rail.drag.x);0>a.scroll.x&&(a.scroll.x=0);var c=a.scrollvaluemaxw;a.scroll.x>c&&(a.scroll.x=c)}else a.scroll.y=a.rail.drag.sy+(b.clientY-a.rail.drag.y),0>a.scroll.y&&(a.scroll.y=0),c=a.scrollvaluemax,a.scroll.y>c&&(a.scroll.y=c);a.synched("mousemove",function(){a.rail.drag&&1==a.rail.drag.pt&&(a.showCursor(),
a.rail.drag.hr?a.hasreversehr?a.doScrollLeft(a.scrollvaluemaxw-Math.round(a.scroll.x*a.scrollratio.x),a.opt.cursordragspeed):a.doScrollLeft(Math.round(a.scroll.x*a.scrollratio.x),a.opt.cursordragspeed):a.doScrollTop(Math.round(a.scroll.y*a.scrollratio.y),a.opt.cursordragspeed))});return a.cancelEvent(b)}};if(e.cantouch||a.opt.touchbehavior)a.onpreventclick=function(b){if(a.preventclick)return a.preventclick.tg.onclick=a.preventclick.click,a.preventclick=!1,a.cancelEvent(b)},a.bind(a.win,"mousedown",
a.ontouchstart),a.onclick=e.isios?!1:function(b){return a.lastmouseup?(a.lastmouseup=!1,a.cancelEvent(b)):!0},a.opt.grabcursorenabled&&e.cursorgrabvalue&&(a.css(a.ispage?a.doc:a.win,{cursor:e.cursorgrabvalue}),a.css(a.rail,{cursor:e.cursorgrabvalue}));else{var p=function(b){if(a.selectiondrag){if(b){var c=a.win.outerHeight();b=b.pageY-a.selectiondrag.top;0<b&&b<c&&(b=0);b>=c&&(b-=c);a.selectiondrag.df=b}0!=a.selectiondrag.df&&(a.doScrollBy(2*-Math.floor(a.selectiondrag.df/6)),a.debounced("doselectionscroll",
function(){p()},50))}};a.hasTextSelected="getSelection"in document?function(){return 0<document.getSelection().rangeCount}:"selection"in document?function(){return"None"!=document.selection.type}:function(){return!1};a.onselectionstart=function(b){a.ispage||(a.selectiondrag=a.win.offset())};a.onselectionend=function(b){a.selectiondrag=!1};a.onselectiondrag=function(b){a.selectiondrag&&a.hasTextSelected()&&a.debounced("selectionscroll",function(){p(b)},250)}}e.hasw3ctouch?(a.css(a.rail,{"touch-action":"none"}),
a.css(a.cursor,{"touch-action":"none"}),a.bind(a.win,"pointerdown",a.ontouchstart),a.bind(document,"pointerup",a.ontouchend),a.bind(document,"pointermove",a.ontouchmove)):e.hasmstouch?(a.css(a.rail,{"-ms-touch-action":"none"}),a.css(a.cursor,{"-ms-touch-action":"none"}),a.bind(a.win,"MSPointerDown",a.ontouchstart),a.bind(document,"MSPointerUp",a.ontouchend),a.bind(document,"MSPointerMove",a.ontouchmove),a.bind(a.cursor,"MSGestureHold",function(a){a.preventDefault()}),a.bind(a.cursor,"contextmenu",
function(a){a.preventDefault()})):this.istouchcapable&&(a.bind(a.win,"touchstart",a.ontouchstart),a.bind(document,"touchend",a.ontouchend),a.bind(document,"touchcancel",a.ontouchend),a.bind(document,"touchmove",a.ontouchmove));if(a.opt.cursordragontouch||!e.cantouch&&!a.opt.touchbehavior)a.rail.css({cursor:"default"}),a.railh&&a.railh.css({cursor:"default"}),a.jqbind(a.rail,"mouseenter",function(){if(!a.ispage&&!a.win.is(":visible"))return!1;a.canshowonmouseevent&&a.showCursor();a.rail.active=!0}),
a.jqbind(a.rail,"mouseleave",function(){a.rail.active=!1;a.rail.drag||a.hideCursor()}),a.opt.sensitiverail&&(a.bind(a.rail,"click",function(b){a.doRailClick(b,!1,!1)}),a.bind(a.rail,"dblclick",function(b){a.doRailClick(b,!0,!1)}),a.bind(a.cursor,"click",function(b){a.cancelEvent(b)}),a.bind(a.cursor,"dblclick",function(b){a.cancelEvent(b)})),a.railh&&(a.jqbind(a.railh,"mouseenter",function(){if(!a.ispage&&!a.win.is(":visible"))return!1;a.canshowonmouseevent&&a.showCursor();a.rail.active=!0}),a.jqbind(a.railh,
"mouseleave",function(){a.rail.active=!1;a.rail.drag||a.hideCursor()}),a.opt.sensitiverail&&(a.bind(a.railh,"click",function(b){a.doRailClick(b,!1,!0)}),a.bind(a.railh,"dblclick",function(b){a.doRailClick(b,!0,!0)}),a.bind(a.cursorh,"click",function(b){a.cancelEvent(b)}),a.bind(a.cursorh,"dblclick",function(b){a.cancelEvent(b)})));e.cantouch||a.opt.touchbehavior?(a.bind(e.hasmousecapture?a.win:document,"mouseup",a.ontouchend),a.bind(document,"mousemove",a.ontouchmove),a.onclick&&a.bind(document,"click",
a.onclick),a.opt.cursordragontouch&&(a.bind(a.cursor,"mousedown",a.onmousedown),a.bind(a.cursor,"mouseup",a.onmouseup),a.cursorh&&a.bind(a.cursorh,"mousedown",function(b){a.onmousedown(b,!0)}),a.cursorh&&a.bind(a.cursorh,"mouseup",a.onmouseup))):(a.bind(e.hasmousecapture?a.win:document,"mouseup",a.onmouseup),a.bind(document,"mousemove",a.onmousemove),a.onclick&&a.bind(document,"click",a.onclick),a.bind(a.cursor,"mousedown",a.onmousedown),a.bind(a.cursor,"mouseup",a.onmouseup),a.railh&&(a.bind(a.cursorh,
"mousedown",function(b){a.onmousedown(b,!0)}),a.bind(a.cursorh,"mouseup",a.onmouseup)),!a.ispage&&a.opt.enablescrollonselection&&(a.bind(a.win[0],"mousedown",a.onselectionstart),a.bind(document,"mouseup",a.onselectionend),a.bind(a.cursor,"mouseup",a.onselectionend),a.cursorh&&a.bind(a.cursorh,"mouseup",a.onselectionend),a.bind(document,"mousemove",a.onselectiondrag)),a.zoom&&(a.jqbind(a.zoom,"mouseenter",function(){a.canshowonmouseevent&&a.showCursor();a.rail.active=!0}),a.jqbind(a.zoom,"mouseleave",
function(){a.rail.active=!1;a.rail.drag||a.hideCursor()})));a.opt.enablemousewheel&&(a.isiframe||a.bind(e.isie&&a.ispage?document:a.win,"mousewheel",a.onmousewheel),a.bind(a.rail,"mousewheel",a.onmousewheel),a.railh&&a.bind(a.railh,"mousewheel",a.onmousewheelhr));a.ispage||e.cantouch||/HTML|^BODY/.test(a.win[0].nodeName)||(a.win.attr("tabindex")||a.win.attr({tabindex:N++}),a.jqbind(a.win,"focus",function(b){y=a.getTarget(b).id||!0;a.hasfocus=!0;a.canshowonmouseevent&&a.noticeCursor()}),a.jqbind(a.win,
"blur",function(b){y=!1;a.hasfocus=!1}),a.jqbind(a.win,"mouseenter",function(b){D=a.getTarget(b).id||!0;a.hasmousefocus=!0;a.canshowonmouseevent&&a.noticeCursor()}),a.jqbind(a.win,"mouseleave",function(){D=!1;a.hasmousefocus=!1;a.rail.drag||a.hideCursor()}))}a.onkeypress=function(b){if(a.railslocked&&0==a.page.maxh)return!0;b=b?b:window.e;var c=a.getTarget(b);if(c&&/INPUT|TEXTAREA|SELECT|OPTION/.test(c.nodeName)&&(!c.getAttribute("type")&&!c.type||!/submit|button|cancel/i.tp)||f(c).attr("contenteditable"))return!0;
if(a.hasfocus||a.hasmousefocus&&!y||a.ispage&&!y&&!D){c=b.keyCode;if(a.railslocked&&27!=c)return a.cancelEvent(b);var g=b.ctrlKey||!1,d=b.shiftKey||!1,e=!1;switch(c){case 38:case 63233:a.doScrollBy(72);e=!0;break;case 40:case 63235:a.doScrollBy(-72);e=!0;break;case 37:case 63232:a.railh&&(g?a.doScrollLeft(0):a.doScrollLeftBy(72),e=!0);break;case 39:case 63234:a.railh&&(g?a.doScrollLeft(a.page.maxw):a.doScrollLeftBy(-72),e=!0);break;case 33:case 63276:a.doScrollBy(a.view.h);e=!0;break;case 34:case 63277:a.doScrollBy(-a.view.h);
e=!0;break;case 36:case 63273:a.railh&&g?a.doScrollPos(0,0):a.doScrollTo(0);e=!0;break;case 35:case 63275:a.railh&&g?a.doScrollPos(a.page.maxw,a.page.maxh):a.doScrollTo(a.page.maxh);e=!0;break;case 32:a.opt.spacebarenabled&&(d?a.doScrollBy(a.view.h):a.doScrollBy(-a.view.h),e=!0);break;case 27:a.zoomactive&&(a.doZoom(),e=!0)}if(e)return a.cancelEvent(b)}};a.opt.enablekeyboard&&a.bind(document,e.isopera&&!e.isopera12?"keypress":"keydown",a.onkeypress);a.bind(document,"keydown",function(b){b.ctrlKey&&
(a.wheelprevented=!0)});a.bind(document,"keyup",function(b){b.ctrlKey||(a.wheelprevented=!1)});a.bind(window,"blur",function(b){a.wheelprevented=!1});a.bind(window,"resize",a.lazyResize);a.bind(window,"orientationchange",a.lazyResize);a.bind(window,"load",a.lazyResize);if(e.ischrome&&!a.ispage&&!a.haswrapper){var r=a.win.attr("style"),c=parseFloat(a.win.css("width"))+1;a.win.css("width",c);a.synched("chromefix",function(){a.win.attr("style",r)})}a.onAttributeChange=function(b){a.lazyResize(a.isieold?
250:30)};!1!==v&&(a.observerbody=new v(function(b){b.forEach(function(b){if("attributes"==b.type)return f("body").hasClass("modal-open")?a.hide():a.show()});if(document.body.scrollHeight!=a.page.maxh)return a.lazyResize(30)}),a.observerbody.observe(document.body,{childList:!0,subtree:!0,characterData:!1,attributes:!0,attributeFilter:["class"]}));a.ispage||a.haswrapper||(!1!==v?(a.observer=new v(function(b){b.forEach(a.onAttributeChange)}),a.observer.observe(a.win[0],{childList:!0,characterData:!1,
attributes:!0,subtree:!1}),a.observerremover=new v(function(b){b.forEach(function(b){if(0<b.removedNodes.length)for(var c in b.removedNodes)if(a&&b.removedNodes[c]==a.win[0])return a.remove()})}),a.observerremover.observe(a.win[0].parentNode,{childList:!0,characterData:!1,attributes:!1,subtree:!1})):(a.bind(a.win,e.isie&&!e.isie9?"propertychange":"DOMAttrModified",a.onAttributeChange),e.isie9&&a.win[0].attachEvent("onpropertychange",a.onAttributeChange),a.bind(a.win,"DOMNodeRemoved",function(b){b.target==
a.win[0]&&a.remove()})));!a.ispage&&a.opt.boxzoom&&a.bind(window,"resize",a.resizeZoom);a.istextarea&&a.bind(a.win,"mouseup",a.lazyResize);a.lazyResize(30)}if("IFRAME"==this.doc[0].nodeName){var M=function(){a.iframexd=!1;var b;try{b="contentDocument"in this?this.contentDocument:this.contentWindow.document}catch(c){a.iframexd=!0,b=!1}if(a.iframexd)return"console"in window&&console.log("NiceScroll error: policy restriced iframe"),!0;a.forcescreen=!0;a.isiframe&&(a.iframe={doc:f(b),html:a.doc.contents().find("html")[0],
body:a.doc.contents().find("body")[0]},a.getContentSize=function(){return{w:Math.max(a.iframe.html.scrollWidth,a.iframe.body.scrollWidth),h:Math.max(a.iframe.html.scrollHeight,a.iframe.body.scrollHeight)}},a.docscroll=f(a.iframe.body));if(!e.isios&&a.opt.iframeautoresize&&!a.isiframe){a.win.scrollTop(0);a.doc.height("");var g=Math.max(b.getElementsByTagName("html")[0].scrollHeight,b.body.scrollHeight);a.doc.height(g)}a.lazyResize(30);e.isie7&&a.css(f(a.iframe.html),{"overflow-y":"hidden"});a.css(f(a.iframe.body),
{"overflow-y":"hidden"});e.isios&&a.haswrapper&&a.css(f(b.body),{"-webkit-transform":"translate3d(0,0,0)"});"contentWindow"in this?a.bind(this.contentWindow,"scroll",a.onscroll):a.bind(b,"scroll",a.onscroll);a.opt.enablemousewheel&&a.bind(b,"mousewheel",a.onmousewheel);a.opt.enablekeyboard&&a.bind(b,e.isopera?"keypress":"keydown",a.onkeypress);if(e.cantouch||a.opt.touchbehavior)a.bind(b,"mousedown",a.ontouchstart),a.bind(b,"mousemove",function(b){return a.ontouchmove(b,!0)}),a.opt.grabcursorenabled&&
e.cursorgrabvalue&&a.css(f(b.body),{cursor:e.cursorgrabvalue});a.bind(b,"mouseup",a.ontouchend);a.zoom&&(a.opt.dblclickzoom&&a.bind(b,"dblclick",a.doZoom),a.ongesturezoom&&a.bind(b,"gestureend",a.ongesturezoom))};this.doc[0].readyState&&"complete"==this.doc[0].readyState&&setTimeout(function(){M.call(a.doc[0],!1)},500);a.bind(this.doc,"load",M)}};this.showCursor=function(b,c){a.cursortimeout&&(clearTimeout(a.cursortimeout),a.cursortimeout=0);if(a.rail){a.autohidedom&&(a.autohidedom.stop().css({opacity:a.opt.cursoropacitymax}),
a.cursoractive=!0);a.rail.drag&&1==a.rail.drag.pt||("undefined"!=typeof b&&!1!==b&&(a.scroll.y=Math.round(1*b/a.scrollratio.y)),"undefined"!=typeof c&&(a.scroll.x=Math.round(1*c/a.scrollratio.x)));a.cursor.css({height:a.cursorheight,top:a.scroll.y});if(a.cursorh){var d=a.hasreversehr?a.scrollvaluemaxw-a.scroll.x:a.scroll.x;!a.rail.align&&a.rail.visibility?a.cursorh.css({width:a.cursorwidth,left:d+a.rail.width}):a.cursorh.css({width:a.cursorwidth,left:d});a.cursoractive=!0}a.zoom&&a.zoom.stop().css({opacity:a.opt.cursoropacitymax})}};
this.hideCursor=function(b){a.cursortimeout||!a.rail||!a.autohidedom||a.hasmousefocus&&"leave"==a.opt.autohidemode||(a.cursortimeout=setTimeout(function(){a.rail.active&&a.showonmouseevent||(a.autohidedom.stop().animate({opacity:a.opt.cursoropacitymin}),a.zoom&&a.zoom.stop().animate({opacity:a.opt.cursoropacitymin}),a.cursoractive=!1);a.cursortimeout=0},b||a.opt.hidecursordelay))};this.noticeCursor=function(b,c,d){a.showCursor(c,d);a.rail.active||a.hideCursor(b)};this.getContentSize=a.ispage?function(){return{w:Math.max(document.body.scrollWidth,
document.documentElement.scrollWidth),h:Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}}:a.haswrapper?function(){return{w:a.doc.outerWidth()+parseInt(a.win.css("paddingLeft"))+parseInt(a.win.css("paddingRight")),h:a.doc.outerHeight()+parseInt(a.win.css("paddingTop"))+parseInt(a.win.css("paddingBottom"))}}:function(){return{w:a.docscroll[0].scrollWidth,h:a.docscroll[0].scrollHeight}};this.onResize=function(b,c){if(!a||!a.win)return!1;if(!a.haswrapper&&!a.ispage){if("none"==
a.win.css("display"))return a.visibility&&a.hideRail().hideRailHr(),!1;a.hidden||a.visibility||a.showRail().showRailHr()}var d=a.page.maxh,e=a.page.maxw,f=a.view.h,h=a.view.w;a.view={w:a.ispage?a.win.width():parseInt(a.win[0].clientWidth),h:a.ispage?a.win.height():parseInt(a.win[0].clientHeight)};a.page=c?c:a.getContentSize();a.page.maxh=Math.max(0,a.page.h-a.view.h);a.page.maxw=Math.max(0,a.page.w-a.view.w);if(a.page.maxh==d&&a.page.maxw==e&&a.view.w==h&&a.view.h==f){if(a.ispage)return a;d=a.win.offset();
if(a.lastposition&&(e=a.lastposition,e.top==d.top&&e.left==d.left))return a;a.lastposition=d}0==a.page.maxh?(a.hideRail(),a.scrollvaluemax=0,a.scroll.y=0,a.scrollratio.y=0,a.cursorheight=0,a.setScrollTop(0),a.rail.scrollable=!1):(a.page.maxh-=a.opt.railpadding.top+a.opt.railpadding.bottom,a.rail.scrollable=!0);0==a.page.maxw?(a.hideRailHr(),a.scrollvaluemaxw=0,a.scroll.x=0,a.scrollratio.x=0,a.cursorwidth=0,a.setScrollLeft(0),a.railh.scrollable=!1):(a.page.maxw-=a.opt.railpadding.left+a.opt.railpadding.right,
a.railh.scrollable=!0);a.railslocked=a.locked||0==a.page.maxh&&0==a.page.maxw;if(a.railslocked)return a.ispage||a.updateScrollBar(a.view),!1;a.hidden||a.visibility?a.hidden||a.railh.visibility||a.showRailHr():a.showRail().showRailHr();a.istextarea&&a.win.css("resize")&&"none"!=a.win.css("resize")&&(a.view.h-=20);a.cursorheight=Math.min(a.view.h,Math.round(a.view.h/a.page.h*a.view.h));a.cursorheight=a.opt.cursorfixedheight?a.opt.cursorfixedheight:Math.max(a.opt.cursorminheight,a.cursorheight);a.cursorwidth=
Math.min(a.view.w,Math.round(a.view.w/a.page.w*a.view.w));a.cursorwidth=a.opt.cursorfixedheight?a.opt.cursorfixedheight:Math.max(a.opt.cursorminheight,a.cursorwidth);a.scrollvaluemax=a.view.h-a.cursorheight-a.cursor.hborder-(a.opt.railpadding.top+a.opt.railpadding.bottom);a.railh&&(a.railh.width=0<a.page.maxh?a.view.w-a.rail.width:a.view.w,a.scrollvaluemaxw=a.railh.width-a.cursorwidth-a.cursorh.wborder-(a.opt.railpadding.left+a.opt.railpadding.right));a.ispage||a.updateScrollBar(a.view);a.scrollratio=
{x:a.page.maxw/a.scrollvaluemaxw,y:a.page.maxh/a.scrollvaluemax};a.getScrollTop()>a.page.maxh?a.doScrollTop(a.page.maxh):(a.scroll.y=Math.round(a.getScrollTop()*(1/a.scrollratio.y)),a.scroll.x=Math.round(a.getScrollLeft()*(1/a.scrollratio.x)),a.cursoractive&&a.noticeCursor());a.scroll.y&&0==a.getScrollTop()&&a.doScrollTo(Math.floor(a.scroll.y*a.scrollratio.y));return a};this.resize=a.onResize;this.lazyResize=function(b){b=isNaN(b)?30:b;a.debounced("resize",a.resize,b);return a};this.jqbind=function(b,
c,d){a.events.push({e:b,n:c,f:d,q:!0});f(b).bind(c,d)};this.bind=function(b,c,d,f){var h="jquery"in b?b[0]:b;"mousewheel"==c?window.addEventListener||"onwheel"in document?a._bind(h,"wheel",d,f||!1):(b="undefined"!=typeof document.onmousewheel?"mousewheel":"DOMMouseScroll",n(h,b,d,f||!1),"DOMMouseScroll"==b&&n(h,"MozMousePixelScroll",d,f||!1)):h.addEventListener?(e.cantouch&&/mouseup|mousedown|mousemove/.test(c)&&a._bind(h,"mousedown"==c?"touchstart":"mouseup"==c?"touchend":"touchmove",function(a){if(a.touches){if(2>
a.touches.length){var b=a.touches.length?a.touches[0]:a;b.original=a;d.call(this,b)}}else a.changedTouches&&(b=a.changedTouches[0],b.original=a,d.call(this,b))},f||!1),a._bind(h,c,d,f||!1),e.cantouch&&"mouseup"==c&&a._bind(h,"touchcancel",d,f||!1)):a._bind(h,c,function(b){(b=b||window.event||!1)&&b.srcElement&&(b.target=b.srcElement);"pageY"in b||(b.pageX=b.clientX+document.documentElement.scrollLeft,b.pageY=b.clientY+document.documentElement.scrollTop);return!1===d.call(h,b)||!1===f?a.cancelEvent(b):
!0})};e.haseventlistener?(this._bind=function(b,c,d,e){a.events.push({e:b,n:c,f:d,b:e,q:!1});b.addEventListener(c,d,e||!1)},this.cancelEvent=function(a){if(!a)return!1;a=a.original?a.original:a;a.preventDefault();a.stopPropagation();a.preventManipulation&&a.preventManipulation();return!1},this.stopPropagation=function(a){if(!a)return!1;a=a.original?a.original:a;a.stopPropagation();return!1},this._unbind=function(a,c,d,e){a.removeEventListener(c,d,e)}):(this._bind=function(b,c,d,e){a.events.push({e:b,
n:c,f:d,b:e,q:!1});b.attachEvent?b.attachEvent("on"+c,d):b["on"+c]=d},this.cancelEvent=function(a){a=window.event||!1;if(!a)return!1;a.cancelBubble=!0;a.cancel=!0;return a.returnValue=!1},this.stopPropagation=function(a){a=window.event||!1;if(!a)return!1;a.cancelBubble=!0;return!1},this._unbind=function(a,c,d,e){a.detachEvent?a.detachEvent("on"+c,d):a["on"+c]=!1});this.unbindAll=function(){for(var b=0;b<a.events.length;b++){var c=a.events[b];c.q?c.e.unbind(c.n,c.f):a._unbind(c.e,c.n,c.f,c.b)}};this.showRail=
function(){0==a.page.maxh||!a.ispage&&"none"==a.win.css("display")||(a.visibility=!0,a.rail.visibility=!0,a.rail.css("display","block"));return a};this.showRailHr=function(){if(!a.railh)return a;0==a.page.maxw||!a.ispage&&"none"==a.win.css("display")||(a.railh.visibility=!0,a.railh.css("display","block"));return a};this.hideRail=function(){a.visibility=!1;a.rail.visibility=!1;a.rail.css("display","none");return a};this.hideRailHr=function(){if(!a.railh)return a;a.railh.visibility=!1;a.railh.css("display",
"none");return a};this.show=function(){a.hidden=!1;a.railslocked=!1;return a.showRail().showRailHr()};this.hide=function(){a.hidden=!0;a.railslocked=!0;return a.hideRail().hideRailHr()};this.toggle=function(){return a.hidden?a.show():a.hide()};this.remove=function(){a.stop();a.cursortimeout&&clearTimeout(a.cursortimeout);a.doZoomOut();a.unbindAll();e.isie9&&a.win[0].detachEvent("onpropertychange",a.onAttributeChange);!1!==a.observer&&a.observer.disconnect();!1!==a.observerremover&&a.observerremover.disconnect();
!1!==a.observerbody&&a.observerbody.disconnect();a.events=null;a.cursor&&a.cursor.remove();a.cursorh&&a.cursorh.remove();a.rail&&a.rail.remove();a.railh&&a.railh.remove();a.zoom&&a.zoom.remove();for(var b=0;b<a.saved.css.length;b++){var c=a.saved.css[b];c[0].css(c[1],"undefined"==typeof c[2]?"":c[2])}a.saved=!1;a.me.data("__nicescroll","");var d=f.nicescroll;d.each(function(b){if(this&&this.id===a.id){delete d[b];for(var c=++b;c<d.length;c++,b++)d[b]=d[c];d.length--;d.length&&delete d[d.length]}});
for(var h in a)a[h]=null,delete a[h];a=null};this.scrollstart=function(b){this.onscrollstart=b;return a};this.scrollend=function(b){this.onscrollend=b;return a};this.scrollcancel=function(b){this.onscrollcancel=b;return a};this.zoomin=function(b){this.onzoomin=b;return a};this.zoomout=function(b){this.onzoomout=b;return a};this.isScrollable=function(a){a=a.target?a.target:a;if("OPTION"==a.nodeName)return!0;for(;a&&1==a.nodeType&&!/^BODY|HTML/.test(a.nodeName);){var c=f(a),c=c.css("overflowY")||c.css("overflowX")||
c.css("overflow")||"";if(/scroll|auto/.test(c))return a.clientHeight!=a.scrollHeight;a=a.parentNode?a.parentNode:!1}return!1};this.getViewport=function(a){for(a=a&&a.parentNode?a.parentNode:!1;a&&1==a.nodeType&&!/^BODY|HTML/.test(a.nodeName);){var c=f(a);if(/fixed|absolute/.test(c.css("position")))return c;var d=c.css("overflowY")||c.css("overflowX")||c.css("overflow")||"";if(/scroll|auto/.test(d)&&a.clientHeight!=a.scrollHeight||0<c.getNiceScroll().length)return c;a=a.parentNode?a.parentNode:!1}return!1};
this.triggerScrollEnd=function(){if(a.onscrollend){var b=a.getScrollLeft(),c=a.getScrollTop();a.onscrollend.call(a,{type:"scrollend",current:{x:b,y:c},end:{x:b,y:c}})}};this.onmousewheel=function(b){if(!a.wheelprevented){if(a.railslocked)return a.debounced("checkunlock",a.resize,250),!0;if(a.rail.drag)return a.cancelEvent(b);"auto"==a.opt.oneaxismousemode&&0!=b.deltaX&&(a.opt.oneaxismousemode=!1);if(a.opt.oneaxismousemode&&0==b.deltaX&&!a.rail.scrollable)return a.railh&&a.railh.scrollable?a.onmousewheelhr(b):
!0;var c=+new Date,d=!1;a.opt.preservenativescrolling&&a.checkarea+600<c&&(a.nativescrollingarea=a.isScrollable(b),d=!0);a.checkarea=c;if(a.nativescrollingarea)return!0;if(b=p(b,!1,d))a.checkarea=0;return b}};this.onmousewheelhr=function(b){if(!a.wheelprevented){if(a.railslocked||!a.railh.scrollable)return!0;if(a.rail.drag)return a.cancelEvent(b);var c=+new Date,d=!1;a.opt.preservenativescrolling&&a.checkarea+600<c&&(a.nativescrollingarea=a.isScrollable(b),d=!0);a.checkarea=c;return a.nativescrollingarea?
!0:a.railslocked?a.cancelEvent(b):p(b,!0,d)}};this.stop=function(){a.cancelScroll();a.scrollmon&&a.scrollmon.stop();a.cursorfreezed=!1;a.scroll.y=Math.round(a.getScrollTop()*(1/a.scrollratio.y));a.noticeCursor();return a};this.getTransitionSpeed=function(b){var c=Math.round(10*a.opt.scrollspeed);b=Math.min(c,Math.round(b/20*a.opt.scrollspeed));return 20<b?b:0};a.opt.smoothscroll?a.ishwscroll&&e.hastransition&&a.opt.usetransition&&a.opt.smoothscroll?(this.prepareTransition=function(b,c){var d=c?20<
b?b:0:a.getTransitionSpeed(b),f=d?e.prefixstyle+"transform "+d+"ms ease-out":"";a.lasttransitionstyle&&a.lasttransitionstyle==f||(a.lasttransitionstyle=f,a.doc.css(e.transitionstyle,f));return d},this.doScrollLeft=function(b,c){var d=a.scrollrunning?a.newscrolly:a.getScrollTop();a.doScrollPos(b,d,c)},this.doScrollTop=function(b,c){var d=a.scrollrunning?a.newscrollx:a.getScrollLeft();a.doScrollPos(d,b,c)},this.doScrollPos=function(b,c,d){var f=a.getScrollTop(),h=a.getScrollLeft();(0>(a.newscrolly-
f)*(c-f)||0>(a.newscrollx-h)*(b-h))&&a.cancelScroll();0==a.opt.bouncescroll&&(0>c?c=0:c>a.page.maxh&&(c=a.page.maxh),0>b?b=0:b>a.page.maxw&&(b=a.page.maxw));if(a.scrollrunning&&b==a.newscrollx&&c==a.newscrolly)return!1;a.newscrolly=c;a.newscrollx=b;a.newscrollspeed=d||!1;if(a.timer)return!1;a.timer=setTimeout(function(){var d=a.getScrollTop(),f=a.getScrollLeft(),h,k;h=b-f;k=c-d;h=Math.round(Math.sqrt(Math.pow(h,2)+Math.pow(k,2)));h=a.newscrollspeed&&1<a.newscrollspeed?a.newscrollspeed:a.getTransitionSpeed(h);
a.newscrollspeed&&1>=a.newscrollspeed&&(h*=a.newscrollspeed);a.prepareTransition(h,!0);a.timerscroll&&a.timerscroll.tm&&clearInterval(a.timerscroll.tm);0<h&&(!a.scrollrunning&&a.onscrollstart&&a.onscrollstart.call(a,{type:"scrollstart",current:{x:f,y:d},request:{x:b,y:c},end:{x:a.newscrollx,y:a.newscrolly},speed:h}),e.transitionend?a.scrollendtrapped||(a.scrollendtrapped=!0,a.bind(a.doc,e.transitionend,a.onScrollTransitionEnd,!1)):(a.scrollendtrapped&&clearTimeout(a.scrollendtrapped),a.scrollendtrapped=
setTimeout(a.onScrollTransitionEnd,h)),a.timerscroll={bz:new A(d,a.newscrolly,h,0,0,.58,1),bh:new A(f,a.newscrollx,h,0,0,.58,1)},a.cursorfreezed||(a.timerscroll.tm=setInterval(function(){a.showCursor(a.getScrollTop(),a.getScrollLeft())},60)));a.synched("doScroll-set",function(){a.timer=0;a.scrollendtrapped&&(a.scrollrunning=!0);a.setScrollTop(a.newscrolly);a.setScrollLeft(a.newscrollx);if(!a.scrollendtrapped)a.onScrollTransitionEnd()})},50)},this.cancelScroll=function(){if(!a.scrollendtrapped)return!0;
var b=a.getScrollTop(),c=a.getScrollLeft();a.scrollrunning=!1;e.transitionend||clearTimeout(e.transitionend);a.scrollendtrapped=!1;a._unbind(a.doc[0],e.transitionend,a.onScrollTransitionEnd);a.prepareTransition(0);a.setScrollTop(b);a.railh&&a.setScrollLeft(c);a.timerscroll&&a.timerscroll.tm&&clearInterval(a.timerscroll.tm);a.timerscroll=!1;a.cursorfreezed=!1;a.showCursor(b,c);return a},this.onScrollTransitionEnd=function(){a.scrollendtrapped&&a._unbind(a.doc[0],e.transitionend,a.onScrollTransitionEnd);
a.scrollendtrapped=!1;a.prepareTransition(0);a.timerscroll&&a.timerscroll.tm&&clearInterval(a.timerscroll.tm);a.timerscroll=!1;var b=a.getScrollTop(),c=a.getScrollLeft();a.setScrollTop(b);a.railh&&a.setScrollLeft(c);a.noticeCursor(!1,b,c);a.cursorfreezed=!1;0>b?b=0:b>a.page.maxh&&(b=a.page.maxh);0>c?c=0:c>a.page.maxw&&(c=a.page.maxw);if(b!=a.newscrolly||c!=a.newscrollx)return a.doScrollPos(c,b,a.opt.snapbackspeed);a.onscrollend&&a.scrollrunning&&a.triggerScrollEnd();a.scrollrunning=!1}):(this.doScrollLeft=
function(b,c){var d=a.scrollrunning?a.newscrolly:a.getScrollTop();a.doScrollPos(b,d,c)},this.doScrollTop=function(b,c){var d=a.scrollrunning?a.newscrollx:a.getScrollLeft();a.doScrollPos(d,b,c)},this.doScrollPos=function(b,c,d){function e(){if(a.cancelAnimationFrame)return!0;a.scrollrunning=!0;if(n=1-n)return a.timer=s(e)||1;var b=0,c,d,g=d=a.getScrollTop();if(a.dst.ay){g=a.bzscroll?a.dst.py+a.bzscroll.getNow()*a.dst.ay:a.newscrolly;c=g-d;if(0>c&&g<a.newscrolly||0<c&&g>a.newscrolly)g=a.newscrolly;
a.setScrollTop(g);g==a.newscrolly&&(b=1)}else b=1;d=c=a.getScrollLeft();if(a.dst.ax){d=a.bzscroll?a.dst.px+a.bzscroll.getNow()*a.dst.ax:a.newscrollx;c=d-c;if(0>c&&d<a.newscrollx||0<c&&d>a.newscrollx)d=a.newscrollx;a.setScrollLeft(d);d==a.newscrollx&&(b+=1)}else b+=1;2==b?(a.timer=0,a.cursorfreezed=!1,a.bzscroll=!1,a.scrollrunning=!1,0>g?g=0:g>a.page.maxh&&(g=a.page.maxh),0>d?d=0:d>a.page.maxw&&(d=a.page.maxw),d!=a.newscrollx||g!=a.newscrolly?a.doScrollPos(d,g):a.onscrollend&&a.triggerScrollEnd()):
a.timer=s(e)||1}c="undefined"==typeof c||!1===c?a.getScrollTop(!0):c;if(a.timer&&a.newscrolly==c&&a.newscrollx==b)return!0;a.timer&&t(a.timer);a.timer=0;var f=a.getScrollTop(),h=a.getScrollLeft();(0>(a.newscrolly-f)*(c-f)||0>(a.newscrollx-h)*(b-h))&&a.cancelScroll();a.newscrolly=c;a.newscrollx=b;a.bouncescroll&&a.rail.visibility||(0>a.newscrolly?a.newscrolly=0:a.newscrolly>a.page.maxh&&(a.newscrolly=a.page.maxh));a.bouncescroll&&a.railh.visibility||(0>a.newscrollx?a.newscrollx=0:a.newscrollx>a.page.maxw&&
(a.newscrollx=a.page.maxw));a.dst={};a.dst.x=b-h;a.dst.y=c-f;a.dst.px=h;a.dst.py=f;var k=Math.round(Math.sqrt(Math.pow(a.dst.x,2)+Math.pow(a.dst.y,2)));a.dst.ax=a.dst.x/k;a.dst.ay=a.dst.y/k;var l=0,m=k;0==a.dst.x?(l=f,m=c,a.dst.ay=1,a.dst.py=0):0==a.dst.y&&(l=h,m=b,a.dst.ax=1,a.dst.px=0);k=a.getTransitionSpeed(k);d&&1>=d&&(k*=d);a.bzscroll=0<k?a.bzscroll?a.bzscroll.update(m,k):new A(l,m,k,0,1,0,1):!1;if(!a.timer){(f==a.page.maxh&&c>=a.page.maxh||h==a.page.maxw&&b>=a.page.maxw)&&a.checkContentSize();
var n=1;a.cancelAnimationFrame=!1;a.timer=1;a.onscrollstart&&!a.scrollrunning&&a.onscrollstart.call(a,{type:"scrollstart",current:{x:h,y:f},request:{x:b,y:c},end:{x:a.newscrollx,y:a.newscrolly},speed:k});e();(f==a.page.maxh&&c>=f||h==a.page.maxw&&b>=h)&&a.checkContentSize();a.noticeCursor()}},this.cancelScroll=function(){a.timer&&t(a.timer);a.timer=0;a.bzscroll=!1;a.scrollrunning=!1;return a}):(this.doScrollLeft=function(b,c){var d=a.getScrollTop();a.doScrollPos(b,d,c)},this.doScrollTop=function(b,
c){var d=a.getScrollLeft();a.doScrollPos(d,b,c)},this.doScrollPos=function(b,c,d){var e=b>a.page.maxw?a.page.maxw:b;0>e&&(e=0);var f=c>a.page.maxh?a.page.maxh:c;0>f&&(f=0);a.synched("scroll",function(){a.setScrollTop(f);a.setScrollLeft(e)})},this.cancelScroll=function(){});this.doScrollBy=function(b,c){var d=0,d=c?Math.floor((a.scroll.y-b)*a.scrollratio.y):(a.timer?a.newscrolly:a.getScrollTop(!0))-b;if(a.bouncescroll){var e=Math.round(a.view.h/2);d<-e?d=-e:d>a.page.maxh+e&&(d=a.page.maxh+e)}a.cursorfreezed=
!1;e=a.getScrollTop(!0);if(0>d&&0>=e)return a.noticeCursor();if(d>a.page.maxh&&e>=a.page.maxh)return a.checkContentSize(),a.noticeCursor();a.doScrollTop(d)};this.doScrollLeftBy=function(b,c){var d=0,d=c?Math.floor((a.scroll.x-b)*a.scrollratio.x):(a.timer?a.newscrollx:a.getScrollLeft(!0))-b;if(a.bouncescroll){var e=Math.round(a.view.w/2);d<-e?d=-e:d>a.page.maxw+e&&(d=a.page.maxw+e)}a.cursorfreezed=!1;e=a.getScrollLeft(!0);if(0>d&&0>=e||d>a.page.maxw&&e>=a.page.maxw)return a.noticeCursor();a.doScrollLeft(d)};
this.doScrollTo=function(b,c){c&&Math.round(b*a.scrollratio.y);a.cursorfreezed=!1;a.doScrollTop(b)};this.checkContentSize=function(){var b=a.getContentSize();b.h==a.page.h&&b.w==a.page.w||a.resize(!1,b)};a.onscroll=function(b){a.rail.drag||a.cursorfreezed||a.synched("scroll",function(){a.scroll.y=Math.round(a.getScrollTop()*(1/a.scrollratio.y));a.railh&&(a.scroll.x=Math.round(a.getScrollLeft()*(1/a.scrollratio.x)));a.noticeCursor()})};a.bind(a.docscroll,"scroll",a.onscroll);this.doZoomIn=function(b){if(!a.zoomactive){a.zoomactive=
!0;a.zoomrestore={style:{}};var c="position top left zIndex backgroundColor marginTop marginBottom marginLeft marginRight".split(" "),d=a.win[0].style,h;for(h in c){var k=c[h];a.zoomrestore.style[k]="undefined"!=typeof d[k]?d[k]:""}a.zoomrestore.style.width=a.win.css("width");a.zoomrestore.style.height=a.win.css("height");a.zoomrestore.padding={w:a.win.outerWidth()-a.win.width(),h:a.win.outerHeight()-a.win.height()};e.isios4&&(a.zoomrestore.scrollTop=f(window).scrollTop(),f(window).scrollTop(0));
a.win.css({position:e.isios4?"absolute":"fixed",top:0,left:0,"z-index":x+100,margin:"0px"});c=a.win.css("backgroundColor");(""==c||/transparent|rgba\(0, 0, 0, 0\)|rgba\(0,0,0,0\)/.test(c))&&a.win.css("backgroundColor","#fff");a.rail.css({"z-index":x+101});a.zoom.css({"z-index":x+102});a.zoom.css("backgroundPosition","0px -18px");a.resizeZoom();a.onzoomin&&a.onzoomin.call(a);return a.cancelEvent(b)}};this.doZoomOut=function(b){if(a.zoomactive)return a.zoomactive=!1,a.win.css("margin",""),a.win.css(a.zoomrestore.style),
e.isios4&&f(window).scrollTop(a.zoomrestore.scrollTop),a.rail.css({"z-index":a.zindex}),a.zoom.css({"z-index":a.zindex}),a.zoomrestore=!1,a.zoom.css("backgroundPosition","0px 0px"),a.onResize(),a.onzoomout&&a.onzoomout.call(a),a.cancelEvent(b)};this.doZoom=function(b){return a.zoomactive?a.doZoomOut(b):a.doZoomIn(b)};this.resizeZoom=function(){if(a.zoomactive){var b=a.getScrollTop();a.win.css({width:f(window).width()-a.zoomrestore.padding.w+"px",height:f(window).height()-a.zoomrestore.padding.h+"px"});
a.onResize();a.setScrollTop(Math.min(a.page.maxh,b))}};this.init();f.nicescroll.push(this)},L=function(f){var c=this;this.nc=f;this.steptime=this.lasttime=this.speedy=this.speedx=this.lasty=this.lastx=0;this.snapy=this.snapx=!1;this.demuly=this.demulx=0;this.lastscrolly=this.lastscrollx=-1;this.timer=this.chky=this.chkx=0;this.time=function(){return+new Date};this.reset=function(f,k){c.stop();var d=c.time();c.steptime=0;c.lasttime=d;c.speedx=0;c.speedy=0;c.lastx=f;c.lasty=k;c.lastscrollx=-1;c.lastscrolly=
-1};this.update=function(f,k){var d=c.time();c.steptime=d-c.lasttime;c.lasttime=d;var d=k-c.lasty,n=f-c.lastx,p=c.nc.getScrollTop(),a=c.nc.getScrollLeft(),p=p+d,a=a+n;c.snapx=0>a||a>c.nc.page.maxw;c.snapy=0>p||p>c.nc.page.maxh;c.speedx=n;c.speedy=d;c.lastx=f;c.lasty=k};this.stop=function(){c.nc.unsynched("domomentum2d");c.timer&&clearTimeout(c.timer);c.timer=0;c.lastscrollx=-1;c.lastscrolly=-1};this.doSnapy=function(f,k){var d=!1;0>k?(k=0,d=!0):k>c.nc.page.maxh&&(k=c.nc.page.maxh,d=!0);0>f?(f=0,d=
!0):f>c.nc.page.maxw&&(f=c.nc.page.maxw,d=!0);d?c.nc.doScrollPos(f,k,c.nc.opt.snapbackspeed):c.nc.triggerScrollEnd()};this.doMomentum=function(f){var k=c.time(),d=f?k+f:c.lasttime;f=c.nc.getScrollLeft();var n=c.nc.getScrollTop(),p=c.nc.page.maxh,a=c.nc.page.maxw;c.speedx=0<a?Math.min(60,c.speedx):0;c.speedy=0<p?Math.min(60,c.speedy):0;d=d&&60>=k-d;if(0>n||n>p||0>f||f>a)d=!1;f=c.speedx&&d?c.speedx:!1;if(c.speedy&&d&&c.speedy||f){var s=Math.max(16,c.steptime);50<s&&(f=s/50,c.speedx*=f,c.speedy*=f,s=
50);c.demulxy=0;c.lastscrollx=c.nc.getScrollLeft();c.chkx=c.lastscrollx;c.lastscrolly=c.nc.getScrollTop();c.chky=c.lastscrolly;var e=c.lastscrollx,r=c.lastscrolly,t=function(){var d=600<c.time()-k?.04:.02;c.speedx&&(e=Math.floor(c.lastscrollx-c.speedx*(1-c.demulxy)),c.lastscrollx=e,0>e||e>a)&&(d=.1);c.speedy&&(r=Math.floor(c.lastscrolly-c.speedy*(1-c.demulxy)),c.lastscrolly=r,0>r||r>p)&&(d=.1);c.demulxy=Math.min(1,c.demulxy+d);c.nc.synched("domomentum2d",function(){c.speedx&&(c.nc.getScrollLeft()!=
c.chkx&&c.stop(),c.chkx=e,c.nc.setScrollLeft(e));c.speedy&&(c.nc.getScrollTop()!=c.chky&&c.stop(),c.chky=r,c.nc.setScrollTop(r));c.timer||(c.nc.hideCursor(),c.doSnapy(e,r))});1>c.demulxy?c.timer=setTimeout(t,s):(c.stop(),c.nc.hideCursor(),c.doSnapy(e,r))};t()}else c.doSnapy(c.nc.getScrollLeft(),c.nc.getScrollTop())}},w=f.fn.scrollTop;f.cssHooks.pageYOffset={get:function(k,c,h){return(c=f.data(k,"__nicescroll")||!1)&&c.ishwscroll?c.getScrollTop():w.call(k)},set:function(k,c){var h=f.data(k,"__nicescroll")||
!1;h&&h.ishwscroll?h.setScrollTop(parseInt(c)):w.call(k,c);return this}};f.fn.scrollTop=function(k){if("undefined"==typeof k){var c=this[0]?f.data(this[0],"__nicescroll")||!1:!1;return c&&c.ishwscroll?c.getScrollTop():w.call(this)}return this.each(function(){var c=f.data(this,"__nicescroll")||!1;c&&c.ishwscroll?c.setScrollTop(parseInt(k)):w.call(f(this),k)})};var B=f.fn.scrollLeft;f.cssHooks.pageXOffset={get:function(k,c,h){return(c=f.data(k,"__nicescroll")||!1)&&c.ishwscroll?c.getScrollLeft():B.call(k)},
set:function(k,c){var h=f.data(k,"__nicescroll")||!1;h&&h.ishwscroll?h.setScrollLeft(parseInt(c)):B.call(k,c);return this}};f.fn.scrollLeft=function(k){if("undefined"==typeof k){var c=this[0]?f.data(this[0],"__nicescroll")||!1:!1;return c&&c.ishwscroll?c.getScrollLeft():B.call(this)}return this.each(function(){var c=f.data(this,"__nicescroll")||!1;c&&c.ishwscroll?c.setScrollLeft(parseInt(k)):B.call(f(this),k)})};var C=function(k){var c=this;this.length=0;this.name="nicescrollarray";this.each=function(d){for(var f=
0,h=0;f<c.length;f++)d.call(c[f],h++);return c};this.push=function(d){c[c.length]=d;c.length++};this.eq=function(d){return c[d]};if(k)for(var h=0;h<k.length;h++){var m=f.data(k[h],"__nicescroll")||!1;m&&(this[this.length]=m,this.length++)}return this};(function(f,c,h){for(var m=0;m<c.length;m++)h(f,c[m])})(C.prototype,"show hide toggle onResize resize remove stop doScrollPos".split(" "),function(f,c){f[c]=function(){var f=arguments;return this.each(function(){this[c].apply(this,f)})}});f.fn.getNiceScroll=
function(k){return"undefined"==typeof k?new C(this):this[k]&&f.data(this[k],"__nicescroll")||!1};f.extend(f.expr[":"],{nicescroll:function(k){return f.data(k,"__nicescroll")?!0:!1}});f.fn.niceScroll=function(k,c){"undefined"!=typeof c||"object"!=typeof k||"jquery"in k||(c=k,k=!1);c=f.extend({},c);var h=new C;"undefined"==typeof c&&(c={});k&&(c.doc=f(k),c.win=f(this));var m=!("doc"in c);m||"win"in c||(c.win=f(this));this.each(function(){var d=f(this).data("__nicescroll")||!1;d||(c.doc=m?f(this):c.doc,
d=new R(c,f(this)),f(this).data("__nicescroll",d));h.push(d)});return 1==h.length?h[0]:h};window.NiceScroll={getjQuery:function(){return f}};f.nicescroll||(f.nicescroll=new C,f.nicescroll.options=I)});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment