Commit fe826756 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-01-25

# Conflicts:
#	scripts/lint-rugged

[ci skip]
parents 435050de 766d3b9d
...@@ -413,7 +413,6 @@ spinach-mysql 2 3: *spinach-metadata-mysql ...@@ -413,7 +413,6 @@ spinach-mysql 2 3: *spinach-metadata-mysql
# Static analysis jobs # Static analysis jobs
.ruby-static-analysis: &ruby-static-analysis .ruby-static-analysis: &ruby-static-analysis
<<: *pull-cache
variables: variables:
SIMPLECOV: "false" SIMPLECOV: "false"
SETUP_DB: "false" SETUP_DB: "false"
...@@ -434,6 +433,12 @@ static-analysis: ...@@ -434,6 +433,12 @@ static-analysis:
stage: test stage: test
script: script:
- scripts/static-analysis - scripts/static-analysis
cache:
key: "ruby-2.3.6-with-yarn-and-rubocop"
paths:
- vendor/ruby
- .yarn-cache/
- tmp/rubocop_cache
# Documentation checks: # Documentation checks:
# - Check validity of relative links # - Check validity of relative links
...@@ -742,8 +747,6 @@ pages: ...@@ -742,8 +747,6 @@ pages:
cache gems: cache gems:
<<: *dedicated-runner <<: *dedicated-runner
<<: *pull-cache <<: *pull-cache
only:
- tags
variables: variables:
SETUP_DB: "false" SETUP_DB: "false"
script: script:
...@@ -754,6 +757,7 @@ cache gems: ...@@ -754,6 +757,7 @@ cache gems:
only: only:
- master@gitlab-org/gitlab-ce - master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee - master@gitlab-org/gitlab-ee
- tags
gitlab_git_test: gitlab_git_test:
<<: *dedicated-runner <<: *dedicated-runner
......
...@@ -18,6 +18,7 @@ AllCops: ...@@ -18,6 +18,7 @@ AllCops:
- 'bin/**/*' - 'bin/**/*'
- 'generator_templates/**/*' - 'generator_templates/**/*'
- 'builds/**/*' - 'builds/**/*'
CacheRootDirectory: tmp
# This cop checks whether some constant value isn't a # This cop checks whether some constant value isn't a
# mutable literal (e.g. array or hash). # mutable literal (e.g. array or hash).
......
...@@ -422,7 +422,7 @@ group :ed25519 do ...@@ -422,7 +422,7 @@ group :ed25519 do
end end
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly-proto', '~> 0.76.0', require: 'gitaly' gem 'gitaly-proto', '~> 0.78.0', require: 'gitaly'
gem 'toml-rb', '~> 0.3.15', require: false gem 'toml-rb', '~> 0.3.15', require: false
......
...@@ -309,7 +309,7 @@ GEM ...@@ -309,7 +309,7 @@ GEM
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gherkin-ruby (0.3.2) gherkin-ruby (0.3.2)
gitaly-proto (0.76.0) gitaly-proto (0.78.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
grpc (~> 1.0) grpc (~> 1.0)
github-linguist (4.7.6) github-linguist (4.7.6)
...@@ -1091,7 +1091,7 @@ DEPENDENCIES ...@@ -1091,7 +1091,7 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0) gettext_i18n_rails_js (~> 1.2.0)
gitaly-proto (~> 0.76.0) gitaly-proto (~> 0.78.0)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-license (~> 1.0) gitlab-license (~> 1.0)
......
...@@ -180,7 +180,7 @@ const Api = { ...@@ -180,7 +180,7 @@ const Api = {
issueTemplate(namespacePath, projectPath, key, type, callback) { issueTemplate(namespacePath, projectPath, key, type, callback) {
const url = Api.buildUrl(Api.issuableTemplatePath) const url = Api.buildUrl(Api.issuableTemplatePath)
.replace(':key', key) .replace(':key', encodeURIComponent(key))
.replace(':type', type) .replace(':type', type)
.replace(':project_path', projectPath) .replace(':project_path', projectPath)
.replace(':namespace_path', namespacePath); .replace(':namespace_path', namespacePath);
......
...@@ -18,7 +18,7 @@ function renderWithKaTeX(elements) { ...@@ -18,7 +18,7 @@ function renderWithKaTeX(elements) {
const display = $this.attr('data-math-style') === 'display'; const display = $this.attr('data-math-style') === 'display';
try { try {
katex.render($this.text(), mathNode.get(0), { displayMode: display }); katex.render($this.text(), mathNode.get(0), { displayMode: display, throwOnError: false });
mathNode.insertAfter($this); mathNode.insertAfter($this);
$this.remove(); $this.remove();
} catch (err) { } catch (err) {
......
...@@ -25,7 +25,7 @@ class Repository ...@@ -25,7 +25,7 @@ class Repository
attr_accessor :full_path, :disk_path, :project, :is_wiki attr_accessor :full_path, :disk_path, :project, :is_wiki
delegate :ref_name_for_sha, to: :raw_repository delegate :ref_name_for_sha, to: :raw_repository
delegate :bundle_to_disk, to: :raw_repository delegate :bundle_to_disk, :create_from_bundle, to: :raw_repository
CreateTreeError = Class.new(StandardError) CreateTreeError = Class.new(StandardError)
......
...@@ -9,15 +9,15 @@ ...@@ -9,15 +9,15 @@
- else - else
.row-content-block.second-block.center .row-content-block.second-block.center
%h3.page-title %h4
This project does not have a README yet This project does not have a README yet
- if can?(current_user, :push_code, @project) - if can?(current_user, :push_code, @project)
%p %p
A A
%code README %code README
file contains information about other files in a repository and is commonly file contains information about other files in a repository and is commonly
distributed with computer software, forming part of its documentation. distributed with computer software, forming part of its documentation.
GitLab will render it here instead of this message.
%p %p
We recommend you to = link_to "Add Readme", add_special_file_path(@project, file_name: 'README.md'), class: 'btn btn-new'
= link_to "add a README", add_special_file_path(@project, file_name: 'README.md')
file to the repository and GitLab will render it here instead of this message.
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
%ul.dropdown-menu.dropdown-menu-align-right.project-home-dropdown %ul.dropdown-menu.dropdown-menu-align-right.project-home-dropdown
- can_create_issue = can?(current_user, :create_issue, @project) - can_create_issue = can?(current_user, :create_issue, @project)
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project)) - merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
- can_create_snippet = can?(current_user, :create_snippet, @project) - can_create_project_snippet = can?(current_user, :create_project_snippet, @project)
- if can_create_issue || merge_project || can_create_project_snippet
%li.dropdown-header= _('This project')
- if can_create_issue - if can_create_issue
%li= link_to _('New issue'), new_project_issue_path(@project) %li= link_to _('New issue'), new_project_issue_path(@project)
...@@ -14,11 +17,11 @@ ...@@ -14,11 +17,11 @@
- if merge_project - if merge_project
%li= link_to _('New merge request'), project_new_merge_request_path(merge_project) %li= link_to _('New merge request'), project_new_merge_request_path(merge_project)
- if can_create_snippet - if can_create_project_snippet
%li= link_to _('New snippet'), new_project_snippet_path(@project) %li= link_to _('New snippet'), new_project_snippet_path(@project)
- if can_create_issue || merge_project || can_create_snippet - if can?(current_user, :push_code, @project)
%li.divider %li.dropdown-header= _('This repository')
- if can?(current_user, :push_code, @project) - if can?(current_user, :push_code, @project)
%li= link_to _('New file'), project_new_blob_path(@project, @project.default_branch || 'master') %li= link_to _('New file'), project_new_blob_path(@project, @project.default_branch || 'master')
......
...@@ -6,8 +6,9 @@ ...@@ -6,8 +6,9 @@
= render "home_panel" = render "home_panel"
.row-content-block.second-block.center .row-content-block.second-block.center
%h3.page-title %h4
The repository for this project is empty The repository for this project is empty
- if can?(current_user, :push_code, @project) - if can?(current_user, :push_code, @project)
%p %p
If you already have files you can push them using command line instructions below. If you already have files you can push them using command line instructions below.
...@@ -28,8 +29,8 @@ ...@@ -28,8 +29,8 @@
%p %p
- link = link_to(s_('AutoDevOps|Auto DevOps (Beta)'), project_settings_ci_cd_path(@project, anchor: 'js-general-pipeline-settings')) - link = link_to(s_('AutoDevOps|Auto DevOps (Beta)'), project_settings_ci_cd_path(@project, anchor: 'js-general-pipeline-settings'))
= s_('AutoDevOps|You can activate %{link_to_settings} for this project.').html_safe % { link_to_settings: link } = s_('AutoDevOps|You can activate %{link_to_settings} for this project.').html_safe % { link_to_settings: link }
%p %p= s_('AutoDevOps|It will automatically build, test, and deploy your application based on a predefined CI/CD configuration.')
= s_('AutoDevOps|It will automatically build, test, and deploy your application based on a predefined CI/CD configuration.') %p= link_to _('New file'), project_new_blob_path(@project, @project.default_branch || 'master'), class: 'btn btn-new'
- if can?(current_user, :push_code, @project) - if can?(current_user, :push_code, @project)
%div{ class: container_class } %div{ class: container_class }
...@@ -79,4 +80,4 @@ ...@@ -79,4 +80,4 @@
- if can? current_user, :remove_project, @project - if can? current_user, :remove_project, @project
.prepend-top-20 .prepend-top-20
= link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right" = link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-inverted btn-remove pull-right"
...@@ -58,15 +58,15 @@ ...@@ -58,15 +58,15 @@
= icon('skype') = icon('skype')
- unless @user.linkedin.blank? - unless @user.linkedin.blank?
.profile-link-holder.middle-dot-divider .profile-link-holder.middle-dot-divider
= link_to linkedin_url(@user), title: "LinkedIn" do = link_to linkedin_url(@user), title: "LinkedIn", target: '_blank', rel: 'noopener noreferrer nofollow' do
= icon('linkedin-square') = icon('linkedin-square')
- unless @user.twitter.blank? - unless @user.twitter.blank?
.profile-link-holder.middle-dot-divider .profile-link-holder.middle-dot-divider
= link_to twitter_url(@user), title: "Twitter" do = link_to twitter_url(@user), title: "Twitter", target: '_blank', rel: 'noopener noreferrer nofollow' do
= icon('twitter-square') = icon('twitter-square')
- unless @user.website_url.blank? - unless @user.website_url.blank?
.profile-link-holder.middle-dot-divider .profile-link-holder.middle-dot-divider
= link_to @user.short_website_url, @user.full_website_url, class: 'text-link' = link_to @user.short_website_url, @user.full_website_url, class: 'text-link', target: '_blank', rel: 'noopener noreferrer nofollow'
- unless @user.location.blank? - unless @user.location.blank?
.profile-link-holder.middle-dot-divider .profile-link-holder.middle-dot-divider
= icon('map-marker') = icon('map-marker')
......
---
title: Handle special characters on API request of issuable templates
merge_request: 15323
author: Takuya Noguchi
type: fixed
---
title: Disable throwOnError in KaTeX to reveal user where is the problem
merge_request: 16684
author: Jakub Jirutka
type: other
---
title: Improve empty project overview
merge_request: 16617
author: George Tsiolis
type: added
---
title: fix documentation about node version
merge_request: 16720
author: Tobias Gurtzick
type: other
...@@ -40,7 +40,7 @@ constraints(ProjectUrlConstrainer.new) do ...@@ -40,7 +40,7 @@ constraints(ProjectUrlConstrainer.new) do
# #
# Templates # Templates
# #
get '/templates/:template_type/:key' => 'templates#show', as: :template get '/templates/:template_type/:key' => 'templates#show', as: :template, constraints: { key: /[^\/]+/ }
resource :avatar, only: [:show, :destroy] resource :avatar, only: [:show, :destroy]
resources :commit, only: [:show], constraints: { id: /\h{7,40}/ } do resources :commit, only: [:show], constraints: { id: /\h{7,40}/ } do
......
...@@ -54,17 +54,16 @@ sudo gem install bundler --no-ri --no-rdoc ...@@ -54,17 +54,16 @@ sudo gem install bundler --no-ri --no-rdoc
### 4. Update Node ### 4. Update Node
GitLab now runs [webpack](http://webpack.js.org) to compile frontend assets and GitLab now runs [webpack](http://webpack.js.org) to compile frontend assets.
it has a minimum requirement of node v4.3.0. We require a minimum version of node v6.0.0.
You can check which version you are running with `node -v`. If you are running You can check which version you are running with `node -v`. If you are running
a version older than `v4.3.0` you will need to update to a newer version. You a version older than `v6.0.0` you will need to update to a newer version. You
can find instructions to install from community maintained packages or compile can find instructions to install from community maintained packages or compile
from source at the nodejs.org website. from source at the nodejs.org website.
<https://nodejs.org/en/download/> <https://nodejs.org/en/download/>
Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage
JavaScript dependencies. JavaScript dependencies.
......
...@@ -56,17 +56,16 @@ sudo gem install bundler --no-ri --no-rdoc ...@@ -56,17 +56,16 @@ sudo gem install bundler --no-ri --no-rdoc
### 4. Update Node ### 4. Update Node
GitLab now runs [webpack](http://webpack.js.org) to compile frontend assets and GitLab now runs [webpack](http://webpack.js.org) to compile frontend assets.
it has a minimum requirement of node v4.3.0. We require a minimum version of node v6.0.0.
You can check which version you are running with `node -v`. If you are running You can check which version you are running with `node -v`. If you are running
a version older than `v4.3.0` you will need to update to a newer version. You a version older than `v6.0.0` you will need to update to a newer version. You
can find instructions to install from community maintained packages or compile can find instructions to install from community maintained packages or compile
from source at the nodejs.org website. from source at the nodejs.org website.
<https://nodejs.org/en/download/> <https://nodejs.org/en/download/>
Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage Since 8.17, GitLab requires the use of yarn `>= v0.17.0` to manage
JavaScript dependencies. JavaScript dependencies.
......
...@@ -70,11 +70,9 @@ module Gitlab ...@@ -70,11 +70,9 @@ module Gitlab
# Returns array of Gitlab::Git::Blob # Returns array of Gitlab::Git::Blob
# Does not guarantee blob data will be set # Does not guarantee blob data will be set
def batch_lfs_pointers(repository, blob_ids) def batch_lfs_pointers(repository, blob_ids)
return [] if blob_ids.empty?
repository.gitaly_migrate(:batch_lfs_pointers) do |is_enabled| repository.gitaly_migrate(:batch_lfs_pointers) do |is_enabled|
if is_enabled if is_enabled
repository.gitaly_blob_client.batch_lfs_pointers(blob_ids) repository.gitaly_blob_client.batch_lfs_pointers(blob_ids.to_a)
else else
blob_ids.lazy blob_ids.lazy
.select { |sha| possible_lfs_blob?(repository, sha) } .select { |sha| possible_lfs_blob?(repository, sha) }
......
...@@ -1188,6 +1188,19 @@ module Gitlab ...@@ -1188,6 +1188,19 @@ module Gitlab
end end
end end
def create_from_bundle(bundle_path)
gitaly_migrate(:create_repo_from_bundle) do |is_enabled|
if is_enabled
gitaly_repository_client.create_from_bundle(bundle_path)
else
run_git!(%W(clone --bare -- #{bundle_path} #{path}), chdir: nil)
self.class.create_hooks(path, File.expand_path(Gitlab.config.gitlab_shell.hooks_path))
end
end
true
end
def rebase(user, rebase_id, branch:, branch_sha:, remote_repository:, remote_branch:) def rebase(user, rebase_id, branch:, branch_sha:, remote_repository:, remote_branch:)
gitaly_migrate(:rebase) do |is_enabled| gitaly_migrate(:rebase) do |is_enabled|
if is_enabled if is_enabled
......
...@@ -34,6 +34,8 @@ module Gitlab ...@@ -34,6 +34,8 @@ module Gitlab
end end
def batch_lfs_pointers(blob_ids) def batch_lfs_pointers(blob_ids)
return [] if blob_ids.empty?
request = Gitaly::GetLFSPointersRequest.new( request = Gitaly::GetLFSPointersRequest.new(
repository: @gitaly_repo, repository: @gitaly_repo,
blob_ids: blob_ids blob_ids: blob_ids
......
...@@ -3,6 +3,8 @@ module Gitlab ...@@ -3,6 +3,8 @@ module Gitlab
class RepositoryService class RepositoryService
include Gitlab::EncodingHelper include Gitlab::EncodingHelper
MAX_MSG_SIZE = 128.kilobytes.freeze
def initialize(repository) def initialize(repository)
@repository = repository @repository = repository
@gitaly_repo = repository.gitaly_repository @gitaly_repo = repository.gitaly_repository
...@@ -178,6 +180,29 @@ module Gitlab ...@@ -178,6 +180,29 @@ module Gitlab
end end
end end
end end
def create_from_bundle(bundle_path)
request = Gitaly::CreateRepositoryFromBundleRequest.new(repository: @gitaly_repo)
enum = Enumerator.new do |y|
File.open(bundle_path, 'rb') do |f|
while data = f.read(MAX_MSG_SIZE)
request.data = data
y.yield request
request = Gitaly::CreateRepositoryFromBundleRequest.new
end
end
end
GitalyClient.call(
@storage,
:repository_service,
:create_repository_from_bundle,
enum,
timeout: GitalyClient.default_timeout
)
end
end end
end end
end end
...@@ -11,11 +11,6 @@ module Gitlab ...@@ -11,11 +11,6 @@ module Gitlab
untar_with_options(archive: archive, dir: dir, options: 'zxf') untar_with_options(archive: archive, dir: dir, options: 'zxf')
end end
def git_clone_bundle(repo_path:, bundle_path:)
execute(%W(#{git_bin_path} clone --bare -- #{bundle_path} #{repo_path}))
Gitlab::Git::Repository.create_hooks(repo_path, File.expand_path(Gitlab.config.gitlab_shell.hooks_path))
end
def mkdir_p(path) def mkdir_p(path)
FileUtils.mkdir_p(path, mode: DEFAULT_MODE) FileUtils.mkdir_p(path, mode: DEFAULT_MODE)
FileUtils.chmod(DEFAULT_MODE, path) FileUtils.chmod(DEFAULT_MODE, path)
......
...@@ -13,7 +13,7 @@ module Gitlab ...@@ -13,7 +13,7 @@ module Gitlab
def restore def restore
return true unless File.exist?(@path_to_bundle) return true unless File.exist?(@path_to_bundle)
git_clone_bundle(repo_path: @project.repository.path_to_repo, bundle_path: @path_to_bundle) @project.repository.create_from_bundle(@path_to_bundle)
rescue => e rescue => e
@shared.error(e) @shared.error(e)
false false
......
#!/usr/bin/env ruby #!/usr/bin/env ruby
ALLOWED = [ ALLOWED = [
<<<<<<< HEAD
# https://gitlab.com/gitlab-org/gitaly/issues/760 # https://gitlab.com/gitlab-org/gitaly/issues/760
'lib/elasticsearch/git/repository.rb', 'lib/elasticsearch/git/repository.rb',
=======
>>>>>>> upstream/master
# Can be deleted (?) once rugged is no longer used in production. Doesn't make Rugged calls. # Can be deleted (?) once rugged is no longer used in production. Doesn't make Rugged calls.
'config/initializers/8_metrics.rb', 'config/initializers/8_metrics.rb',
......
...@@ -283,9 +283,9 @@ describe('Api', () => { ...@@ -283,9 +283,9 @@ describe('Api', () => {
it('fetches an issue template', (done) => { it('fetches an issue template', (done) => {
const namespace = 'some namespace'; const namespace = 'some namespace';
const project = 'some project'; const project = 'some project';
const templateKey = 'template key'; const templateKey = ' template #%?.key ';
const templateType = 'template type'; const templateType = 'template type';
const expectedUrl = `${dummyUrlRoot}/${namespace}/${project}/templates/${templateType}/${templateKey}`; const expectedUrl = `${dummyUrlRoot}/${namespace}/${project}/templates/${templateType}/${encodeURIComponent(templateKey)}`;
spyOn(jQuery, 'ajax').and.callFake((request) => { spyOn(jQuery, 'ajax').and.callFake((request) => {
expect(request.url).toEqual(expectedUrl); expect(request.url).toEqual(expectedUrl);
return sendDummyResponse(); return sendDummyResponse();
......
...@@ -268,6 +268,21 @@ describe Gitlab::Git::Blob, seed_helper: true do ...@@ -268,6 +268,21 @@ describe Gitlab::Git::Blob, seed_helper: true do
expect(blobs).to all( be_a(Gitlab::Git::Blob) ) expect(blobs).to all( be_a(Gitlab::Git::Blob) )
end end
it 'accepts blob IDs as a lazy enumerator' do
blobs = described_class.batch_lfs_pointers(repository, [lfs_blob.id].lazy)
expect(blobs.count).to eq(1)
expect(blobs).to all( be_a(Gitlab::Git::Blob) )
end
it 'handles empty list of IDs gracefully' do
blobs_1 = described_class.batch_lfs_pointers(repository, [].lazy)
blobs_2 = described_class.batch_lfs_pointers(repository, [])
expect(blobs_1).to eq([])
expect(blobs_2).to eq([])
end
it 'silently ignores tree objects' do it 'silently ignores tree objects' do
blobs = described_class.batch_lfs_pointers(repository, [tree_object.oid]) blobs = described_class.batch_lfs_pointers(repository, [tree_object.oid])
......
...@@ -1992,6 +1992,47 @@ describe Gitlab::Git::Repository, seed_helper: true do ...@@ -1992,6 +1992,47 @@ describe Gitlab::Git::Repository, seed_helper: true do
end end
end end
describe '#create_from_bundle' do
shared_examples 'creating repo from bundle' do
let(:bundle_path) { File.join(Dir.tmpdir, "repo-#{SecureRandom.hex}.bundle") }
let(:project) { create(:project) }
let(:imported_repo) { project.repository.raw }
before do
expect(repository.bundle_to_disk(bundle_path)).to be true
end
after do
FileUtils.rm_rf(bundle_path)
end
it 'creates a repo from a bundle file' do
expect(imported_repo).not_to exist
result = imported_repo.create_from_bundle(bundle_path)
expect(result).to be true
expect(imported_repo).to exist
expect { imported_repo.fsck }.not_to raise_exception
end
it 'creates a symlink to the global hooks dir' do
imported_repo.create_from_bundle(bundle_path)
hooks_path = File.join(imported_repo.path, 'hooks')
expect(File.readlink(hooks_path)).to eq(Gitlab.config.gitlab_shell.hooks_path)
end
end
context 'when Gitaly create_repo_from_bundle feature is enabled' do
it_behaves_like 'creating repo from bundle'
end
context 'when Gitaly create_repo_from_bundle feature is disabled', :disable_gitaly do
it_behaves_like 'creating repo from bundle'
end
end
context 'gitlab_projects commands' do context 'gitlab_projects commands' do
let(:gitlab_projects) { repository.gitlab_projects } let(:gitlab_projects) { repository.gitlab_projects }
let(:timeout) { Gitlab.config.gitlab_shell.git_timeout } let(:timeout) { Gitlab.config.gitlab_shell.git_timeout }
......
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