Commit 965dc286 authored by Kamil Trzciński's avatar Kamil Trzciński

Merge commit '7fabc892' into object-storage-ee-to-ce-backport

parents e3fafa76 7fabc892

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

......@@ -152,8 +152,10 @@ stages:
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
##
# Trigger a package build in omnibus-gitlab repository
build-package:
#
package-qa:
image: ruby:2.4-alpine
before_script: []
stage: build
......@@ -193,7 +195,7 @@ review-docs-deploy:
name: review-docs/$CI_COMMIT_REF_NAME
# DOCS_REVIEW_APPS_DOMAIN and DOCS_GITLAB_REPO_SUFFIX are secret variables
# Discussion: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14236/diffs#note_40140693
url: http://preview-$CI_COMMIT_REF_SLUG.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX
url: http://$DOCS_GITLAB_REPO_SUFFIX-$CI_COMMIT_REF_SLUG.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX
on_stop: review-docs-cleanup
script:
- ./trigger-build-docs deploy
......@@ -256,7 +258,7 @@ flaky-examples-check:
USE_BUNDLE_INSTALL: "false"
NEW_FLAKY_SPECS_REPORT: rspec_flaky/report-new.json
stage: post-test
allow_failure: yes
allow_failure: true
retry: 0
only:
- branches
......@@ -416,15 +418,10 @@ ee_compat_check:
- /^[\d-]+-stable(-ee)?/
- branches@gitlab-org/gitlab-ee
- branches@gitlab/gitlab-ee
allow_failure: yes
retry: 0
cache:
key: "ee_compat_check_repo"
paths:
- ee_compat_check/ee-repo/
artifacts:
name: "${CI_JOB_NAME}_${CI_COMIT_REF_NAME}_${CI_COMMIT_SHA}"
when: on_failure
when: always
expire_in: 10d
paths:
- ee_compat_check/patches/*.patch
......@@ -453,6 +450,7 @@ db:migrate:reset-mysql:
stage: test
variables:
SETUP_DB: "false"
CREATE_DB_USER: "true"
script:
- git fetch https://gitlab.com/gitlab-org/gitlab-ce.git v9.3.0
- git checkout -f FETCH_HEAD
......@@ -478,7 +476,7 @@ migration:path-mysql:
<<: *pull-cache
stage: test
script:
- bundle exec rake db:rollback STEP=120
- bundle exec rake db:rollback STEP=119
- bundle exec rake db:migrate
db:rollback-pg:
......@@ -497,6 +495,7 @@ db:rollback-mysql:
variables:
SIZE: "1"
SETUP_DB: "false"
CREATE_DB_USER: "true"
script:
- git clone https://gitlab.com/gitlab-org/gitlab-test.git
/home/git/repositories/gitlab-org/gitlab-test.git
......@@ -532,7 +531,6 @@ gitlab:assets:compile:
NODE_ENV: "production"
RAILS_ENV: "production"
SETUP_DB: "false"
USE_DB: "false"
SKIP_STORAGE_VALIDATION: "true"
WEBPACK_REPORT: "true"
NO_COMPRESSION: "true"
......@@ -587,6 +585,17 @@ codequality:
artifacts:
paths: [codeclimate.json]
qa:internal:
<<: *except-docs
stage: test
variables:
SETUP_DB: "false"
services: []
script:
- cd qa/
- bundle install
- bundle exec rspec
coverage:
<<: *dedicated-runner
<<: *except-docs
......
Please read this!
Before opening a new issue, make sure to search for keywords in the issues
filtered by the "feature proposal" label:
For the Community Edition issue tracker:
- https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=feature+proposal
For the Enterprise Edition issue tracker:
- https://gitlab.com/gitlab-org/gitlab-ee/issues?label_name%5B%5D=feature+proposal
and verify the issue you're about to submit isn't a duplicate.
Please remove this notice if you're confident your issue isn't a duplicate.
------
### Description
(Include problem, use cases, benefits, and/or goals)
......@@ -25,26 +6,4 @@ Please remove this notice if you're confident your issue isn't a duplicate.
### Links / references
### Documentation blurb
#### Overview
What is it?
Why should someone use this feature?
What is the underlying (business) problem?
How do you use this feature?
#### Use cases
Who is this for? Provide one or more use cases.
### Feature checklist
Make sure these are completed before closing the issue,
with a link to the relevant commit.
- [ ] [Feature assurance](https://about.gitlab.com/handbook/product/#feature-assurance)
- [ ] Documentation
- [ ] Added to [features.yml](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/features.yml)
/label ~"feature proposal"
\ No newline at end of file
/label ~"feature proposal"
Remove this section and replace it with a description of your MR. Also follow the
checklist below and check off any tasks that are done. If a certain task can not
be done you should explain so in the MR body. You are free to remove any
sections that do not apply to your MR.
When gathering statistics (e.g. the output of `EXPLAIN ANALYZE`) you should make
sure your database has enough data. Having around 10 000 rows in the tables
being queries should provide a reasonable estimate of how a query will behave.
Also make sure that PostgreSQL uses the following settings:
* `random_page_cost`: `1`
* `work_mem`: `16MB`
* `maintenance_work_mem`: at least `64MB`
* `shared_buffers`: at least `256MB`
If you have access to GitLab.com's staging environment you should also run your
measurements there, and include the results in this MR.
Add a description of your merge request here. Merge requests without an adequate
description will not be reviewed until one is added.
## Database Checklist
......@@ -23,34 +8,23 @@ When adding migrations:
- [ ] Updated `db/schema.rb`
- [ ] Added a `down` method so the migration can be reverted
- [ ] Added the output of the migration(s) to the MR body
- [ ] Added the execution time of the migration(s) to the MR body
- [ ] Added tests for the migration in `spec/migrations` if necessary (e.g. when
migrating data)
- [ ] Made sure the migration won't interfere with a running GitLab cluster,
for example by disabling transactions for long running migrations
- [ ] Added tests for the migration in `spec/migrations` if necessary (e.g. when migrating data)
When adding or modifying queries to improve performance:
- [ ] Included the raw SQL queries of the relevant queries
- [ ] Included the output of `EXPLAIN ANALYZE` and execution timings of the
relevant queries
- [ ] Added tests for the relevant changes
When adding indexes:
- [ ] Described the need for these indexes in the MR body
- [ ] Made sure existing indexes can not be reused instead
- [ ] Included data that shows the performance improvement, preferably in the form of a benchmark
- [ ] Included the output of `EXPLAIN (ANALYZE, BUFFERS)` of the relevant queries
When adding foreign keys to existing tables:
- [ ] Included a migration to remove orphaned rows in the source table
- [ ] Included a migration to remove orphaned rows in the source table before adding the foreign key
- [ ] Removed any instances of `dependent: ...` that may no longer be necessary
When adding tables:
- [ ] Ordered columns based on their type sizes in descending order
- [ ] Added foreign keys if necessary
- [ ] Added indexes if necessary
- [ ] Ordered columns based on the [Ordering Table Columns](https://docs.gitlab.com/ee/development/ordering_table_columns.html#ordering-table-columns) guidelines
- [ ] Added foreign keys to any columns pointing to data in other tables
- [ ] Added indexes for fields that are used in statements such as WHERE, ORDER BY, GROUP BY, and JOINs
When removing columns, tables, indexes or other structures:
......@@ -64,8 +38,6 @@ When removing columns, tables, indexes or other structures:
- [ ] API support added
- [ ] Tests added for this feature/bug
- Review
- [ ] Has been reviewed by UX
- [ ] Has been reviewed by Frontend
- [ ] Has been reviewed by Backend
- [ ] Has been reviewed by Database
- [ ] Conform by the [merge request performance guides](http://docs.gitlab.com/ce/development/merge_request_performance_guidelines.html)
......
......@@ -241,7 +241,7 @@ linters:
# Numeric values should not contain unnecessary fractional portions.
UnnecessaryMantissa:
enabled: false
enabled: true
# Do not use parent selector references (&) when they would otherwise
# be unnecessary.
......
This diff is collapsed.
......@@ -543,6 +543,7 @@ When having your code reviewed and when reviewing merge requests please take the
etc.), they should conform to our [Licensing guidelines][license-finder-doc].
See the instructions in that document for help if your MR fails the
"license-finder" test with a "Dependencies that need approval" error.
1. The merge request meets the [definition of done](#definition-of-done).
## Definition of done
......@@ -597,6 +598,7 @@ merge request:
present time and never use past tense (has been/was). For example instead
of _prohibited this user from being saved due to the following errors:_ the
text should be _sorry, we could not create your account because:_
1. Code should be written in [US English][us-english]
This is also the style used by linting tools such as
[RuboCop](https://github.com/bbatsov/rubocop),
......@@ -662,6 +664,7 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[GitLab Inc engineering workflow]: https://about.gitlab.com/handbook/engineering/workflow/#labelling-issues
[polling-etag]: https://docs.gitlab.com/ce/development/polling.html
[testing]: doc/development/testing_guide/index.md
[us-english]: https://en.wikipedia.org/wiki/American_English
[^1]: Please note that specs other than JavaScript specs are considered backend
code.
source 'https://rubygems.org'
gem 'rails', '4.2.8'
gem 'rails', '4.2.10'
gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with
......@@ -111,7 +111,7 @@ gem 'google-api-client', '~> 0.13.6'
gem 'unf', '~> 0.1.4'
# Seed data
gem 'seed-fu', '~> 2.3.5'
gem 'seed-fu', '2.3.6' # Upgrade to > 2.3.7 once https://github.com/mbleigh/seed-fu/issues/123 is solved
# Markdown and HTML processing
gem 'html-pipeline', '~> 1.11.0'
......@@ -171,7 +171,7 @@ gem 're2', '~> 1.1.1'
gem 'version_sorter', '~> 2.1.0'
# Cache
gem 'redis-rails', '~> 5.0.1'
gem 'redis-rails', '~> 5.0.2'
# Redis
gem 'redis', '~> 3.2'
......@@ -245,7 +245,7 @@ gem 'font-awesome-rails', '~> 4.7'
gem 'gemojione', '~> 3.3'
gem 'gon', '~> 6.1.0'
gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 4.1.0'
gem 'jquery-rails', '~> 4.3.1'
gem 'request_store', '~> 1.3'
gem 'select2-rails', '~> 3.5.9'
gem 'virtus', '~> 1.0.1'
......@@ -263,6 +263,8 @@ gem 'gettext_i18n_rails', '~> 1.8.0'
gem 'gettext_i18n_rails_js', '~> 1.2.0'
gem 'gettext', '~> 3.2.2', require: false, group: :development
gem 'batch-loader'
# Perf bar
gem 'peek', '~> 1.0.1'
gem 'peek-gc', '~> 0.0.2'
......@@ -281,7 +283,7 @@ group :metrics do
gem 'influxdb', '~> 0.2', require: false
# Prometheus
gem 'prometheus-client-mmap', '~>0.7.0.beta18'
gem 'prometheus-client-mmap', '~> 0.7.0.beta39'
gem 'raindrops', '~> 0.18'
end
......@@ -343,7 +345,7 @@ group :development, :test do
gem 'benchmark-ips', '~> 2.3.0', require: false
gem 'license_finder', '~> 2.1.0', require: false
gem 'license_finder', '~> 3.1', require: false
gem 'knapsack', '~> 1.11.0'
gem 'activerecord_sane_schema_dumper', '0.2'
......@@ -398,7 +400,7 @@ group :ed25519 do
end
# Gitaly GRPC client
gem 'gitaly-proto', '~> 0.51.0', require: 'gitaly'
gem 'gitaly-proto', '~> 0.59.0', require: 'gitaly'
gem 'toml-rb', '~> 0.3.15', require: false
......
......@@ -4,38 +4,38 @@ GEM
RedCloth (4.3.2)
abstract_type (0.0.7)
ace-rails-ap (4.1.2)
actionmailer (4.2.8)
actionpack (= 4.2.8)
actionview (= 4.2.8)
activejob (= 4.2.8)
actionmailer (4.2.10)
actionpack (= 4.2.10)
actionview (= 4.2.10)
activejob (= 4.2.10)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.8)
actionview (= 4.2.8)
activesupport (= 4.2.8)
actionpack (4.2.10)
actionview (= 4.2.10)
activesupport (= 4.2.10)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.8)
activesupport (= 4.2.8)
actionview (4.2.10)
activesupport (= 4.2.10)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (4.2.8)
activesupport (= 4.2.8)
activejob (4.2.10)
activesupport (= 4.2.10)
globalid (>= 0.3.0)
activemodel (4.2.8)
activesupport (= 4.2.8)
activemodel (4.2.10)
activesupport (= 4.2.10)
builder (~> 3.1)
activerecord (4.2.8)
activemodel (= 4.2.8)
activesupport (= 4.2.8)
activerecord (4.2.10)
activemodel (= 4.2.10)
activesupport (= 4.2.10)
arel (~> 6.0)
activerecord_sane_schema_dumper (0.2)
rails (>= 4, < 5)
activesupport (4.2.8)
activesupport (4.2.10)
i18n (~> 0.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
......@@ -73,6 +73,7 @@ GEM
thread_safe (~> 0.3, >= 0.3.1)
babosa (1.0.2)
base32 (0.3.2)
batch-loader (1.1.1)
bcrypt (3.1.11)
bcrypt_pbkdf (1.0.0)
benchmark-ips (2.3.0)
......@@ -83,6 +84,7 @@ GEM
bindata (2.4.1)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
blankslate (2.1.2.4)
bootstrap-sass (3.3.6)
autoprefixer-rails (>= 5.2.1)
sass (>= 3.3.4)
......@@ -274,7 +276,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
gitaly-proto (0.51.0)
gitaly-proto (0.59.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (4.7.6)
......@@ -298,8 +300,8 @@ GEM
omniauth (~> 1.3)
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
rubyntlm (~> 0.5)
globalid (0.3.7)
activesupport (>= 4.1.0)
globalid (0.4.1)
activesupport (>= 4.2.0)
gollum-grit_adapter (1.0.1)
gitlab-grit (~> 2.7, >= 2.7.1)
gollum-lib (4.2.7)
......@@ -326,8 +328,6 @@ GEM
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
google-protobuf (3.4.1.1)
googleapis-common-protos-types (1.0.0)
google-protobuf (~> 3.0)
googleauth (0.5.3)
faraday (~> 0.12)
jwt (~> 1.4)
......@@ -354,9 +354,8 @@ GEM
rake
grape_logging (1.7.0)
grape
grpc (1.6.6)
grpc (1.4.5)
google-protobuf (~> 3.1)
googleapis-common-protos-types (~> 1.0.0)
googleauth (~> 0.5.1)
haml (4.0.7)
tilt
......@@ -398,7 +397,8 @@ GEM
json (~> 1.8)
multi_xml (>= 0.5.2)
httpclient (2.8.2)
i18n (0.8.6)
i18n (0.9.1)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
influxdb (0.2.3)
cause
......@@ -409,7 +409,7 @@ GEM
multipart-post
oauth (~> 0.5, >= 0.5.0)
jquery-atwho-rails (1.3.2)
jquery-rails (4.1.1)
jquery-rails (4.3.1)
rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
......@@ -451,11 +451,13 @@ GEM
actionmailer (>= 3.2)
letter_opener (~> 1.0)
railties (>= 3.2)
license_finder (2.1.0)
license_finder (3.1.1)
bundler
httparty
rubyzip
thor
toml (= 0.1.2)
with_env (> 1.0)
xml-simple
licensee (8.7.0)
rugged (~> 0.24)
......@@ -470,8 +472,8 @@ GEM
railties (>= 4, < 5.2)
loofah (2.0.3)
nokogiri (>= 1.5.9)
mail (2.6.6)
mime-types (>= 1.16, < 4)
mail (2.7.0)
mini_mime (>= 0.1.1)
mail_room (0.9.1)
memoist (0.16.0)
memoizable (0.4.2)
......@@ -484,7 +486,6 @@ GEM
mini_mime (0.1.4)
mini_portile2 (2.3.0)
minitest (5.7.0)
mmap2 (2.2.7)
mousetrap-rails (1.4.6)
multi_json (1.12.2)
multi_xml (0.6.0)
......@@ -569,8 +570,10 @@ GEM
parallel (1.12.0)
paranoia (2.3.1)
activerecord (>= 4.0, < 5.2)
parser (2.4.0.0)
ast (~> 2.2)
parser (2.4.0.2)
ast (~> 2.3)
parslet (1.5.0)
blankslate (~> 2.0)
path_expander (1.0.1)
peek (1.0.1)
concurrent-ruby (>= 0.9.0)
......@@ -619,8 +622,7 @@ GEM
parser
unparser
procto (0.0.3)
prometheus-client-mmap (0.7.0.beta18)
mmap2 (~> 2.2, >= 2.2.7)
prometheus-client-mmap (0.7.0.beta43)
pry (0.10.4)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
......@@ -650,16 +652,16 @@ GEM
rack
rack-test (0.6.3)
rack (>= 1.0)
rails (4.2.8)
actionmailer (= 4.2.8)
actionpack (= 4.2.8)
actionview (= 4.2.8)
activejob (= 4.2.8)
activemodel (= 4.2.8)
activerecord (= 4.2.8)
activesupport (= 4.2.8)
rails (4.2.10)
actionmailer (= 4.2.10)
actionpack (= 4.2.10)
actionview (= 4.2.10)
activejob (= 4.2.10)
activemodel (= 4.2.10)
activerecord (= 4.2.10)
activesupport (= 4.2.10)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.8)
railties (= 4.2.10)
sprockets-rails
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
......@@ -672,15 +674,15 @@ GEM
rails-i18n (4.0.9)
i18n (~> 0.7)
railties (~> 4.0)
railties (4.2.8)
actionpack (= 4.2.8)
activesupport (= 4.2.8)
railties (4.2.10)
actionpack (= 4.2.10)
activesupport (= 4.2.10)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (2.2.2)
rake
raindrops (0.18.0)
rake (12.1.0)
rake (12.3.0)
rblineprof (0.3.6)
debugger-ruby_core_source (~> 1.3)
rbnacl (4.0.2)
......@@ -695,24 +697,24 @@ GEM
recursive-open-struct (1.0.0)
redcarpet (3.4.0)
redis (3.3.3)
redis-actionpack (5.0.1)
redis-actionpack (5.0.2)
actionpack (>= 4.0, < 6)
redis-rack (>= 1, < 3)
redis-store (>= 1.1.0, < 1.4.0)
redis-activesupport (5.0.1)
redis-store (>= 1.1.0, < 2)
redis-activesupport (5.0.4)
activesupport (>= 3, < 6)
redis-store (~> 1.2.0)
redis-store (>= 1.3, < 2)
redis-namespace (1.5.2)
redis (~> 3.0, >= 3.0.4)
redis-rack (1.6.0)
rack (~> 1.5)
redis-store (~> 1.2.0)
redis-rails (5.0.1)
redis-actionpack (~> 5.0.0)
redis-activesupport (~> 5.0.0)
redis-store (~> 1.2.0)
redis-store (1.2.0)
redis (>= 2.2)
redis-rack (2.0.3)
rack (>= 1.5, < 3)
redis-store (>= 1.2, < 2)
redis-rails (5.0.2)
redis-actionpack (>= 5.0, < 6)
redis-activesupport (>= 5.0, < 6)
redis-store (>= 1.2, < 2)
redis-store (1.4.1)
redis (>= 2.2, < 5)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
......@@ -867,7 +869,7 @@ GEM
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.0)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
......@@ -898,12 +900,14 @@ GEM
tilt (2.0.6)
timecop (0.8.1)
timfel-krb5-auth (0.8.3)
toml (0.1.2)
parslet (~> 1.5.0)
toml-rb (0.3.15)
citrus (~> 3.0, > 3.0)
truncato (0.7.10)
htmlentities (~> 4.3.1)
nokogiri (~> 1.8.0, >= 1.7.0)
tzinfo (1.2.3)
tzinfo (1.2.4)
thread_safe (~> 0.1)
u2f (0.2.1)
uber (0.1.0)
......@@ -952,6 +956,7 @@ GEM
builder
expression_parser
rinku
with_env (1.1.0)
xml-simple (1.1.5)
xpath (2.1.0)
nokogiri (~> 1.3)
......@@ -974,6 +979,7 @@ DEPENDENCIES
awesome_print (~> 1.2.0)
babosa (~> 1.0.2)
base32 (~> 0.3.0)
batch-loader
bcrypt_pbkdf (~> 1.0)
benchmark-ips (~> 2.3.0)
better_errors (~> 2.1.0)
......@@ -1026,7 +1032,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
gitaly-proto (~> 0.51.0)
gitaly-proto (~> 0.59.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.6.2)
......@@ -1051,14 +1057,14 @@ DEPENDENCIES
influxdb (~> 0.2)
jira-ruby (~> 1.4)
jquery-atwho-rails (~> 1.3.2)
jquery-rails (~> 4.1.0)
jquery-rails (~> 4.3.1)
json-schema (~> 2.8.0)
jwt (~> 1.5.6)
kaminari (~> 1.0)
knapsack (~> 1.11.0)
kubeclient (~> 2.2.0)
letter_opener_web (~> 1.3.0)
license_finder (~> 2.1.0)
license_finder (~> 3.1)
licensee (~> 8.7.0)
lograge (~> 0.5)
loofah (~> 2.0.3)
......@@ -1101,14 +1107,14 @@ DEPENDENCIES
peek-sidekiq (~> 1.0.3)
pg (~> 0.18.2)
premailer-rails (~> 1.9.7)
prometheus-client-mmap (~> 0.7.0.beta18)
prometheus-client-mmap (~> 0.7.0.beta39)
pry-byebug (~> 3.4.1)
pry-rails (~> 0.3.4)
rack-attack (~> 4.4.1)
rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1)
rack-proxy (~> 0.6.0)
rails (= 4.2.8)
rails (= 4.2.10)
rails-deprecated_sanitizer (~> 1.0.3)
rails-i18n (~> 4.0.9)
rainbow (~> 2.2)
......@@ -1122,7 +1128,7 @@ DEPENDENCIES
redcarpet (~> 3.4)
redis (~> 3.2)
redis-namespace (~> 1.5.2)
redis-rails (~> 5.0.1)
redis-rails (~> 5.0.2)
request_store (~> 1.3)
responders (~> 2.0)
rouge (~> 2.0)
......@@ -1143,7 +1149,7 @@ DEPENDENCIES
sanitize (~> 2.0)
sass-rails (~> 5.0.6)
scss_lint (~> 0.54.0)
seed-fu (~> 2.3.5)
seed-fu (= 2.3.6)
select2-rails (~> 3.5.9)
selenium-webdriver (~> 3.5)
sentry-raven (~> 2.5.3)
......@@ -1185,4 +1191,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.15.4
1.16.0
......@@ -141,21 +141,29 @@ the stable branch are:
* Fixes for security issues
* New or updated translations (as long as they do not touch application code)
During the feature freeze all merge requests that are meant to go into the upcoming
release should have the correct milestone assigned _and_ have the label
~"Pick into Stable" set, so that release managers can find and pick them.
Merge requests without a milestone and this label will
not be merged into any stable branches.
Fixes marked like this will be shipped in the next RC for that release. Once
the final RC has been prepared ready for release on the 22nd, further fixes
marked ~"Pick into Stable" will go into a patch for that release.
If a merge request is to be picked into more than one release it will also need
the ~"Pick into Backports" label set to remind the release manager to change
the milestone after cherry-picking. As before, it should still have the
~"Pick into Stable" label and the milestone of the highest release it will be
picked into.
During the feature freeze all merge requests that are meant to go into the
upcoming release should have the correct milestone assigned _and_ the
`Pick into X.Y` label where `X.Y` is equal to the milestone, so that release
managers can find and pick them.
Merge requests without this label will not be picked into the stable release.
For example, if the upcoming release is `10.2.0` you will need to set the
`Pick into 10.2` label.
Fixes marked like this will be shipped in the next RC (before the 22nd), or the
next patch release.
If a merge request is to be picked into more than one release it will need one
`Pick into X.Y` label per release where the merge request should be back-ported
to.
For example, if the current patch release is `10.1.1` and a regression fix needs
to be backported down to the `9.5` release, you will need to assign it the
`10.1` milestone and the following labels:
- `Pick into 10.1`
- `Pick into 10.0`
- `Pick into 9.5`
### Asking for an exception
......
10.2.0-pre
10.3.0-pre
app/assets/images/emoji.png

1.16 MB | W: | H:

app/assets/images/emoji.png

1.16 MB | W: | H:

app/assets/images/emoji.png
app/assets/images/emoji.png
app/assets/images/emoji.png
app/assets/images/emoji.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/emoji/mrs_claus.png

2.15 KB | W: | H:

app/assets/images/emoji/mrs_claus.png

3.26 KB | W: | H:

app/assets/images/emoji/mrs_claus.png
app/assets/images/emoji/mrs_claus.png
app/assets/images/emoji/mrs_claus.png
app/assets/images/emoji/mrs_claus.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/emoji@2x.png

2.84 MB | W: | H:

app/assets/images/emoji@2x.png

2.84 MB | W: | H:

app/assets/images/emoji@2x.png
app/assets/images/emoji@2x.png
app/assets/images/emoji@2x.png
app/assets/images/emoji@2x.png
  • 2-up
  • Swipe
  • Onion skin
{"iconCount":173,"spriteSize":75815,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-right","assignee","bold","book","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]}
\ No newline at end of file
{"iconCount":180,"spriteSize":82176,"icons":["abuse","account","admin","angle-double-left","angle-double-right","angle-down","angle-left","angle-right","angle-up","appearance","applications","approval","arrow-down","arrow-right","assignee","bold","book","branch","bullhorn","calendar","cancel","chart","chevron-down","chevron-left","chevron-right","chevron-up","clock","close","code","collapse","comment-dots","comment-next","comment","comments","commit","credit-card","cut","dashboard","disk","doc_code","doc_image","doc_text","double-headed-arrow","download","duplicate","earth","ellipsis_v","emoji_slightly_smiling_face","emoji_smile","emoji_smiley","epic","external-link","eye-slash","eye","file-addition","file-deletion","file-modified","filter","folder","fork","geo-nodes","git-merge","group","history","home","hook","hourglass","image-comment-dark","import","issue-block","issue-child","issue-close","issue-duplicate","issue-new","issue-open-m","issue-open","issue-parent","issues","italic","key-2","key","label","labels","leave","level-up","license","link","list-bulleted","list-numbered","location-dot","location","lock-open","lock","log","mail","menu","merge-request-close","messages","mobile-issue-close","monitor","more","notifications-off","notifications","overview","pencil-square","pencil","pipeline","play","plus-square-o","plus-square","plus","preferences","profile","project","push-rules","question-o","question","quote","redo","remove","repeat","retry","scale","screen-full","screen-normal","scroll_down","scroll_up","search","settings","shield","slight-frown","slight-smile","smile","smiley","snippet","spam","spinner","star-o","star","status_canceled_borderless","status_canceled","status_closed","status_created_borderless","status_created","status_failed_borderless","status_failed","status_manual_borderless","status_manual","status_notfound_borderless","status_open","status_pending_borderless","status_pending","status_running_borderless","status_running","status_skipped_borderless","status_skipped","status_success_borderless","status_success_solid","status_success","status_warning_borderless","status_warning","stop","task-done","template","terminal","thumb-down","thumb-up","thumbtack","timer","todo-add","todo-done","token","unapproval","unassignee","unlink","user","users","volume-up","warning","work"]}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
<svg height="128" viewBox="0 0 142 128" width="142" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M94 62h20v4H94z" fill="#f0edf8"/><path d="M84.828 84l17.678 17.678-2.828 2.828L82 86.828z" fill="#fee1d3"/><path d="M42.828 24l17.678 17.678-2.828 2.828L40 26.828zM40 101.678L57.678 84l2.828 2.828-17.678 17.678z" fill="#f0edf8"/><path d="M82 41.678L99.678 24l2.828 2.828-17.678 17.678zM28 62h20v4H28zM3 52h24v24H3z" fill="#fee1d3"/><path d="M31 3h24v24H31z" fill="#f0edf8"/><path d="M87 3h24v24H87z" fill="#fef0e8"/><path d="M115 52h24v24h-24z" fill="#f0edf8"/><path d="M87 101h24v24H87z" fill="#fee1d3"/><path d="M31 101h24v24H31z" fill="#f0edf8"/><path d="M49 42h44v44H49z" fill="#c3b8e3"/><g fill-rule="nonzero"><path d="M5 53a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V54a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H5a5 5 0 0 1-5-5V54a5 5 0 0 1 5-5z" fill="#fdc4a8"/><path d="M56 43a6 6 0 0 0-6 6v30a6 6 0 0 0 6 6h30a6 6 0 0 0 6-6V49a6 6 0 0 0-6-6zm0-4h30c5.523 0 10 4.477 10 10v30c0 5.523-4.477 10-10 10H56c-5.523 0-10-4.477-10-10V49c0-5.523 4.477-10 10-10z" fill="#6b4fbb"/><path d="M89 4a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H89a5 5 0 0 1-5-5V5a5 5 0 0 1 5-5z" fill="#fee1d3"/><path d="M89 102a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1v-20a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H89a5 5 0 0 1-5-5v-20a5 5 0 0 1 5-5z" fill="#fdc4a8"/><path d="M117 53a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V54a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5h-20a5 5 0 0 1-5-5V54a5 5 0 0 1 5-5zM33 102a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1v-20a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H33a5 5 0 0 1-5-5v-20a5 5 0 0 1 5-5zM33 4a1 1 0 0 0-1 1v20a1 1 0 0 0 1 1h20a1 1 0 0 0 1-1V5a1 1 0 0 0-1-1zm0-4h20a5 5 0 0 1 5 5v20a5 5 0 0 1-5 5H33a5 5 0 0 1-5-5V5a5 5 0 0 1 5-5z" fill="#e1dbf1"/></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="220" viewBox="0 0 360 220"><g fill="none" fill-rule="evenodd"><path fill="#000" fill-opacity=".02" d="M125 44V24.003C125 18.48 129.483 14 135.005 14h89.99C230.52 14 235 18.477 235 24.003V43h84.992C326.624 43 332 48.372 332 55.002v144.996c0 6.63-5.38 12.002-12.008 12.002h-85.984c-6.632 0-12.008-5.372-12.008-12.002V183h-78v17.002c0 6.626-5.38 11.998-12.008 11.998H46.008C39.376 212 34 206.624 34 200.002V55.998C34 49.372 39.38 44 46.008 44H125z"/><g transform="translate(214 36)"><rect width="110" height="168" x="2" y="2" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M4 12.006c0-2.208.896-4.27 2.457-5.77a2 2 0 0 0-2.773-2.883A11.974 11.974 0 0 0 0 12.006a2 2 0 1 0 4 0zM14.388 4h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm17.51.227a8.015 8.015 0 0 1 5.022 3.756 2 2 0 1 0 3.458-2.011A12.01 12.01 0 0 0 104.844.34a2 2 0 0 0-.946 3.887zM110 16.78v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm-.024 17.844a7.99 7.99 0 0 1-2.903 5.558 2 2 0 0 0 2.54 3.09 11.977 11.977 0 0 0 4.35-8.338 2.002 2.002 0 0 0-1.838-2.15 2.003 2.003 0 0 0-2.15 1.84zM98.826 168h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-17.334-.4a8.032 8.032 0 0 1-4.71-4.143 1.998 1.998 0 0 0-2.667-.938 1.997 1.997 0 0 0-.938 2.667 12.022 12.022 0 0 0 7.063 6.21 1.998 1.998 0 1 0 1.252-3.798zM4 154.434v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0z"/><path fill="#F0EDF8" fill-rule="nonzero" d="M57 111c-11.598 0-21-9.402-21-21s9.402-21 21-21 21 9.402 21 21-9.402 21-21 21zm0-4c9.39 0 17-7.61 17-17s-7.61-17-17-17-17 7.61-17 17 7.61 17 17 17z"/><path fill="#6B4FBB" d="M58 88v-6.997c0-1.11-.895-2.003-2-2.003-1.112 0-2 .897-2 2.003v8.994a1.999 1.999 0 0 0 2.503 1.94c.162.04.33.063.506.063h7.98a2 2 0 0 0 .001-4H58z"/><rect width="8" height="4" x="8" y="14" fill="#EEE" rx="2"/><path fill="#EEE" d="M21 16c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 21 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 34 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 47 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 60 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 73 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 86 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 99 16z"/></g><g transform="translate(118 7)"><rect width="110" height="168" x="2" y="2" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M4 12.006c0-2.208.896-4.27 2.457-5.77a2 2 0 0 0-2.773-2.883A11.974 11.974 0 0 0 0 12.006a2 2 0 1 0 4 0zM14.388 4h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm18 0h8a2 2 0 0 0 0-4h-8a2 2 0 1 0 0 4zm17.51.227a8.015 8.015 0 0 1 5.022 3.756 2 2 0 1 0 3.458-2.011A12.01 12.01 0 0 0 104.844.34a2 2 0 0 0-.946 3.887zM110 16.78v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm0 18v8a2 2 0 0 0 4 0v-8a2 2 0 1 0-4 0zm-.024 17.844a7.99 7.99 0 0 1-2.903 5.558 2 2 0 0 0 2.54 3.09 11.977 11.977 0 0 0 4.35-8.338 2.002 2.002 0 0 0-1.838-2.15 2.003 2.003 0 0 0-2.15 1.84zM98.826 168h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-18 0h-8a2 2 0 0 0 0 4h8a2 2 0 1 0 0-4zm-17.334-.4a8.032 8.032 0 0 1-4.71-4.143 1.998 1.998 0 0 0-2.667-.938 1.997 1.997 0 0 0-.938 2.667 12.022 12.022 0 0 0 7.063 6.21 1.998 1.998 0 1 0 1.252-3.798zM4 154.434v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0zm0-18v-8a2 2 0 0 0-4 0v8a2 2 0 1 0 4 0z"/><g fill-rule="nonzero"><path fill="#F0EDF8" d="M57 112c-12.15 0-22-9.85-22-22s9.85-22 22-22 22 9.85 22 22-9.85 22-22 22zm0-6c8.837 0 16-7.163 16-16s-7.163-16-16-16-16 7.163-16 16 7.163 16 16 16z"/><path fill="#6B4FBB" d="M41.692 105.8A21.93 21.93 0 0 0 57 112c12.15 0 22-9.85 22-22s-9.85-22-22-22v6c8.837 0 16 7.163 16 16s-7.163 16-16 16a15.935 15.935 0 0 1-11.133-4.508l-4.175 4.31z"/></g><path fill="#EEE" d="M8 16c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2H9.998A1.995 1.995 0 0 1 8 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 21 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 34 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 47 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 60 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 73 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 86 16zm13 0c0-1.105.887-2 1.998-2h4.004c1.103 0 1.998.888 1.998 2 0 1.105-.887 2-1.998 2h-4.004A1.995 1.995 0 0 1 99 16z"/></g><g transform="translate(26 36)"><rect width="110" height="168" x="2" y="2" fill="#FFF" rx="10"/><path fill="#EEE" fill-rule="nonzero" d="M4 12.006v147.988A8 8 0 0 0 12.005 168h89.99a8.007 8.007 0 0 0 8.005-8.006V12.006A8 8 0 0 0 101.995 4h-89.99A8.007 8.007 0 0 0 4 12.006zm-4 0C0 5.376 5.377 0 12.005 0h89.99C108.628 0 114 5.37 114 12.006v147.988c0 6.63-5.377 12.006-12.005 12.006h-89.99C5.372 172 0 166.63 0 159.994V12.006z"/><g transform="translate(21 82)"><rect width="24" height="4" y="10" fill="#F0EDF8" rx="2"/><rect width="14" height="4" x="5" fill="#6B4FBB" rx="2"/></g><g transform="translate(69 82)"><rect width="24" height="4" y="10" fill="#F0EDF8" rx="2"/><rect width="14" height="4" x="5" fill="#6B4FBB" rx="2"/></g><g transform="translate(38 42)"><rect width="22" height="4" x="8" fill="#FEE1D3" rx="2"/><rect width="38" height="4" y="12" fill="#FB722E" rx="2"/></g><path fill="#EEE" d="M4 14h106v4H4z"/><path fill="#333" d="M35.724 138h9.696v-2.856h-2.856V122.76h-2.592c-1.08.648-2.136 1.08-3.792 1.392v2.184h2.856v8.808h-3.312V138zm17.736.288c-2.952 0-5.76-2.208-5.76-7.56 0-5.688 2.952-8.256 6.168-8.256 2.016 0 3.48.84 4.44 1.824l-1.848 2.112c-.528-.576-1.488-1.08-2.376-1.08-1.68 0-3.024 1.2-3.144 4.752.792-1.008 2.112-1.608 3.048-1.608 2.616 0 4.536 1.488 4.536 4.704 0 3.168-2.304 5.112-5.064 5.112zm-.072-2.64c1.056 0 1.92-.744 1.92-2.472 0-1.608-.84-2.208-1.992-2.208-.792 0-1.68.432-2.304 1.512.312 2.4 1.32 3.168 2.376 3.168zM63.9 132c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024zm.528 8.256l8.448-16.224h2.04l-8.448 16.224h-2.04zm11.016 0c-2.256 0-3.888-1.848-3.888-4.992 0-3.12 1.632-4.944 3.888-4.944 2.256 0 3.912 1.824 3.912 4.944 0 3.144-1.656 4.992-3.912 4.992zm0-1.968c.792 0 1.44-.792 1.44-3.024s-.648-2.976-1.44-2.976c-.792 0-1.44.744-1.44 2.976s.648 3.024 1.44 3.024z"/></g></g></svg>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M45.688 18.854c-4.869-1.989-10.488-1.975-15.29-.001a20.014 20.014 0 0 0-6.493 4.268 19.798 19.798 0 0 0-4.346 6.381 19.135 19.135 0 0 0-1.525 7.537c0 2.066.33 4.118.983 6.104a20.142 20.142 0 0 0 1.83 3.937 5.983 5.983 0 0 0-2.086 4.538c0 3.309 2.691 6 6 6s6-2.691 6-6-2.691-6-6-6c-.779 0-1.522.154-2.205.425a18.13 18.13 0 0 1-1.642-3.533 17.467 17.467 0 0 1-.881-5.472c0-2.351.459-4.623 1.391-6.814a17.721 17.721 0 0 1 3.88-5.675 18.057 18.057 0 0 1 5.85-3.845c4.329-1.778 9.392-1.79 13.78.002a18.077 18.077 0 0 1 5.843 3.84c3.39 3.34 5.257 7.776 5.257 12.493a17.463 17.463 0 0 1-.878 5.481 17.451 17.451 0 0 1-2.569 4.923c-2.134 2.866-3.818 4.698-5.174 6.173-2.424 2.643-3.98 4.599-4.383 8.384H32.215a1 1 0 1 0 0 2h11.739a1 1 0 0 0 .999-.947c.19-3.645 1.345-5.263 3.934-8.09 1.385-1.506 3.107-3.381 5.304-6.331a19.422 19.422 0 0 0 2.864-5.489c.651-1.98.98-4.04.979-6.109 0-5.256-2.078-10.198-5.856-13.92a20.079 20.079 0 0 0-6.49-4.265M28.761 51.612c0 2.206-1.794 4-4 4s-4-1.794-4-4 1.794-4 4-4 4 1.794 4 4M40 74h-4a1 1 0 1 0 0 2h4a1 1 0 1 0 0-2M42 70h-8a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2M38 10a1 1 0 0 0 1-1V1a1 1 0 1 0-2 0v8a1 1 0 0 0 1 1M20.828 15.828a.999.999 0 0 0 .707-1.707l-5.656-5.656a.999.999 0 1 0-1.414 1.414l5.656 5.656a.997.997 0 0 0 .707.293M10 33H2a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2M60.12 8.465l-5.656 5.656a.999.999 0 1 0 1.414 1.414l5.656-5.656a.999.999 0 1 0-1.414-1.414M74 33h-8a1 1 0 1 0 0 2h8a1 1 0 1 0 0-2M43 66H33a1 1 0 1 0 0 2h10a1 1 0 1 0 0-2"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M5 43a1 1 0 1 0 2 0v-4h4a1 1 0 1 0 0-2H7v-4a1 1 0 1 0-2 0v4H1a1 1 0 1 0 0 2h4v4M75 37h-4v-4a1 1 0 1 0-2 0v4h-4a1 1 0 1 0 0 2h4v4a1 1 0 1 0 2 0v-4h4a1 1 0 1 0 0-2M21 38a1 1 0 0 0 .47.848l8 5a.999.999 0 0 0 1.061-1.696L23.887 38l6.644-4.152a1 1 0 1 0-1.061-1.695l-8 5A.998.998 0 0 0 21 38M55 38a1 1 0 0 0-.47-.848l-8-5a.999.999 0 1 0-1.061 1.695L52.113 38l-6.644 4.152a1 1 0 1 0 1.061 1.696l8-5A1 1 0 0 0 55 38M41.803 26.05a1 1 0 0 0-1.256.65l-7 22a1.001 1.001 0 0 0 .953 1.303 1 1 0 0 0 .953-.697l7-22a1.001 1.001 0 0 0-.65-1.256M62 7c3.859 0 7 3.141 7 7v11a1 1 0 1 0 2 0V14c0-4.963-4.04-9-9-9H45.91c-.479-2.833-2.943-5-5.91-5-3.309 0-6 2.691-6 6s2.691 6 6 6c2.967 0 5.431-2.167 5.91-5H62m-22 3c-2.206 0-4-1.794-4-4s1.794-4 4-4 4 1.794 4 4-1.794 4-4 4M6 26a1 1 0 0 0 1-1V14c0-3.859 3.141-7 7-7h11.09l-3.293 3.293a.999.999 0 1 0 1.414 1.414l5-5a.999.999 0 0 0 0-1.414l-5-5a.999.999 0 1 0-1.414 1.414L25.09 5H14c-4.963 0-9 4.04-9 9v11a1 1 0 0 0 1 1M36 64c-2.967 0-5.431 2.167-5.91 5H14c-3.859 0-7-3.141-7-7V51a1 1 0 1 0-2 0v11c0 4.963 4.04 9 9 9h16.09c.478 2.833 2.942 5 5.91 5 3.309 0 6-2.691 6-6s-2.691-6-6-6m0 10c-2.206 0-4-1.794-4-4s1.794-4 4-4 4 1.794 4 4-1.794 4-4 4M70 50a1 1 0 0 0-1 1v11c0 3.859-3.141 7-7 7H50.91l3.293-3.293a.999.999 0 1 0-1.414-1.414l-5 5a.999.999 0 0 0 0 1.414l5 5a.997.997 0 0 0 1.414 0 .999.999 0 0 0 0-1.414L50.91 71H62c4.963 0 9-4.04 9-9V51a1 1 0 0 0-1-1"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M42.26 40.44a.989.989 0 0 0 1.109-.877l2.625-22.444a.997.997 0 0 0-.993-1.117h-14a1 1 0 0 0-.994 1.108l3.454 31.575a6.981 6.981 0 0 0-2.46 5.317c0 3.859 3.141 7 7 7s7-3.141 7-7-3.141-7-7-7c-.94 0-1.835.189-2.655.527l-3.23-29.527h11.761L41.383 39.33a1 1 0 0 0 .877 1.11m.741 13.562c0 2.757-2.243 5-5 5s-5-2.243-5-5 2.243-5 5-5 5 2.243 5 5"/><path d="M73.236 23.749a1 1 0 0 0-1.854.75A35.788 35.788 0 0 1 74 38c0 19.851-16.149 36-36 36S2 57.851 2 38 18.149 2 38 2c7.6 0 14.83 2.332 20.965 6.74A5.955 5.955 0 0 0 58 12c0 1.603.624 3.109 1.758 4.242A5.956 5.956 0 0 0 64 18a5.956 5.956 0 0 0 4.242-1.758C69.376 15.109 70 13.603 70 12s-.624-3.109-1.758-4.242A5.956 5.956 0 0 0 64 6a5.943 5.943 0 0 0-3.668 1.259C53.812 2.512 46.104 0 38 0 17.047 0 0 17.047 0 38s17.047 38 38 38 38-17.047 38-38c0-4.93-.93-9.725-2.764-14.251zM64 8c1.068 0 2.072.416 2.828 1.172S68 10.932 68 12s-.416 2.072-1.172 2.828c-1.512 1.512-4.145 1.512-5.656 0C60.416 14.072 60 13.068 60 12s.416-2.072 1.172-2.828S62.932 8 64 8z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M12 8c0-3.309-2.691-6-6-6S0 4.691 0 8c0 2.967 2.167 5.431 5 5.91v8.181c-2.833.478-5 2.942-5 5.909s2.167 5.431 5 5.91v8.181c-2.833.478-5 2.942-5 5.909s2.167 5.431 5 5.91v8.181c-2.833.478-5 2.942-5 5.909 0 3.309 2.691 6 6 6s6-2.691 6-6c0-2.967-2.167-5.431-5-5.91v-8.18c2.833-.478 5-2.942 5-5.91s-2.167-5.431-5-5.91v-8.18c2.833-.478 5-2.942 5-5.91s-2.167-5.431-5-5.91v-8.18c2.833-.479 5-2.943 5-5.91M2 8c0-2.206 1.794-4 4-4s4 1.794 4 4-1.794 4-4 4-4-1.794-4-4m8 60c0 2.206-1.794 4-4 4s-4-1.794-4-4 1.794-4 4-4 4 1.794 4 4m0-20c0 2.206-1.794 4-4 4s-4-1.794-4-4 1.794-4 4-4 4 1.794 4 4m0-20c0 2.206-1.794 4-4 4s-4-1.794-4-4 1.794-4 4-4 4 1.794 4 4M21 6h54a1 1 0 1 0 0-2H21a1 1 0 1 0 0 2M21 12h35a1 1 0 1 0 0-2H21a1 1 0 1 0 0 2M75 24H21a1 1 0 1 0 0 2h54a1 1 0 1 0 0-2M21 32h34a1 1 0 1 0 0-2H21a1 1 0 1 0 0 2M75 44H21a1 1 0 1 0 0 2h54a1 1 0 1 0 0-2M21 52h34a1 1 0 1 0 0-2H21a1 1 0 1 0 0 2M75 64H21a1 1 0 1 0 0 2h54a1 1 0 1 0 0-2M55 70H21a1 1 0 1 0 0 2h34a1 1 0 1 0 0-2"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M67.7 10h-6.751C60.442 4.402 55.728 0 50 0c-6.06 0-11 4.935-11 11s4.935 11 11 11c5.728 0 10.442-4.402 10.949-10H67.7c1.269 0 2.3.987 2.3 2.2v57.6c0 1.213-1.031 2.2-2.3 2.2H8.3C7.031 74 6 73.013 6 71.8V14.2C6 12.987 7.031 12 8.3 12h15.15a1 1 0 1 0 0-2H8.3C5.929 10 4 11.884 4 14.2v57.6C4 74.116 5.929 76 8.3 76h59.4c2.371 0 4.3-1.884 4.3-4.2V14.2c0-2.316-1.929-4.2-4.3-4.2M50 20c-4.963 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9"/><path d="M21.293 29.29a.999.999 0 0 0 0 1.414l12.975 12.975-12.975 12.974a.999.999 0 1 0 1.414 1.414l13.682-13.682a.999.999 0 0 0 0-1.414L22.707 29.29a.999.999 0 0 0-1.414 0M54 59a1 1 0 1 0 0-2H42a1 1 0 1 0 0 2h12"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M48.949 37C48.442 31.402 43.728 27 38 27s-10.442 4.402-10.949 10h-13.05a1 1 0 1 0 0 2h13.05c.507 5.598 5.221 10 10.949 10s10.442-4.402 10.949-10h12.24a1 1 0 1 0 0-2h-12.24M38 47c-4.963 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9"/><path d="M73.236 23.749a1 1 0 0 0-1.854.75A35.788 35.788 0 0 1 74 38c0 19.851-16.149 36-36 36S2 57.851 2 38 18.149 2 38 2c7.6 0 14.83 2.332 20.965 6.74A5.955 5.955 0 0 0 58 12c0 1.603.624 3.109 1.758 4.242A5.956 5.956 0 0 0 64 18a5.956 5.956 0 0 0 4.242-1.758C69.376 15.109 70 13.603 70 12s-.624-3.109-1.758-4.242A5.956 5.956 0 0 0 64 6a5.943 5.943 0 0 0-3.668 1.259C53.812 2.512 46.104 0 38 0 17.047 0 0 17.047 0 38s17.047 38 38 38 38-17.047 38-38c0-4.93-.93-9.725-2.764-14.251zM64 8c1.068 0 2.072.416 2.828 1.172S68 10.932 68 12s-.416 2.072-1.172 2.828c-1.512 1.512-4.145 1.512-5.656 0C60.416 14.072 60 13.068 60 12s.416-2.072 1.172-2.828S62.932 8 64 8z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M14.267 7.32l-4.896 5.277-1.702-1.533a.999.999 0 1 0-1.338 1.486l2.434 2.192c.064.058.139.091.212.13.035.018.065.048.101.062a.99.99 0 0 0 .752-.016c.044-.019.077-.058.118-.084.076-.047.155-.086.219-.154l5.566-6a1 1 0 0 0-1.466-1.36M31 9h44a1 1 0 1 0 0-2H31a1 1 0 1 0 0 2M31 15h24a1 1 0 1 0 0-2H31a1 1 0 1 0 0 2"/><path d="M11 0C4.93 0 0 4.935 0 11s4.935 11 11 11 11-4.935 11-11S17.065 0 11 0m0 20c-4.963 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9M14.267 34.32l-4.896 5.277-1.702-1.533a1 1 0 1 0-1.338 1.486l2.434 2.192c.064.058.139.091.212.13.035.018.065.048.101.062a.99.99 0 0 0 .752-.016c.044-.019.077-.058.118-.084.076-.047.155-.086.219-.154l5.566-6a1 1 0 0 0-1.466-1.36M75 34H31a1 1 0 1 0 0 2h44a1 1 0 1 0 0-2M31 42h24a1 1 0 1 0 0-2H31a1 1 0 1 0 0 2"/><path d="M11 27C4.93 27 0 31.935 0 38s4.935 11 11 11 11-4.935 11-11-4.935-11-11-11m0 20c-4.963 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9M14.267 61.32l-4.896 5.277-1.702-1.533a1 1 0 1 0-1.338 1.486l2.434 2.192c.064.058.139.091.212.13.035.018.065.048.101.062a.99.99 0 0 0 .752-.016c.044-.019.077-.058.118-.084.076-.047.155-.086.219-.154l5.566-6a1 1 0 0 0-1.466-1.36"/><path d="M11 54C4.93 54 0 58.935 0 65s4.935 11 11 11 11-4.935 11-11-4.935-11-11-11m0 20c-4.963 0-9-4.04-9-9s4.04-9 9-9 9 4.04 9 9-4.04 9-9 9M75 61H31a1 1 0 1 0 0 2h44a1 1 0 1 0 0-2M55 67H31a1 1 0 1 0 0 2h24a1 1 0 1 0 0-2"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M73.236 23.749a1 1 0 1 0-1.854.75A35.788 35.788 0 0 1 74 38c0 19.851-16.149 36-36 36S2 57.851 2 38 18.149 2 38 2c7.6 0 14.83 2.332 20.965 6.74A5.955 5.955 0 0 0 58 12c0 1.603.624 3.109 1.758 4.242A5.956 5.956 0 0 0 64 18a5.956 5.956 0 0 0 4.242-1.758C69.376 15.109 70 13.603 70 12s-.624-3.109-1.758-4.242A5.956 5.956 0 0 0 64 6a5.943 5.943 0 0 0-3.668 1.259C53.812 2.512 46.104 0 38 0 17.047 0 0 17.047 0 38s17.047 38 38 38 38-17.047 38-38c0-4.93-.93-9.725-2.764-14.251zM64 8c1.068 0 2.072.416 2.828 1.172S68 10.932 68 12s-.416 2.072-1.172 2.828c-1.512 1.512-4.145 1.512-5.656 0C60.416 14.072 60 13.068 60 12s.416-2.072 1.172-2.828S62.932 8 64 8z"/><path d="M27.19 32.17a.997.997 0 0 0-1.366-.364L13.17 39.132a1 1 0 0 0 0 1.73l12.654 7.326a1 1 0 0 0 1.002-1.73l-11.159-6.461 11.159-6.461a.998.998 0 0 0 .364-1.366M48.808 47.827a1 1 0 0 0 1.366.364l12.654-7.326a1 1 0 0 0 0-1.73l-12.654-7.326a1 1 0 0 0-1.002 1.73L60.331 40l-11.159 6.461a.998.998 0 0 0-.364 1.366M42.71 23.06L31.398 56.29a1 1 0 0 0 1.892.645l11.312-33.23a1 1 0 0 0-1.892-.645"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M62.44 54.765l-9.912-11.09c.315-3.881.481-7.241.508-10.271-.029-13.871-3.789-23.05-13.413-32.746-.855-.859-2.411-.828-3.294.059-7.594 7.65-11.139 13.934-12.575 22.3a6.94 6.94 0 0 0-4.699 2.039c-1.321 1.321-2.05 3.079-2.05 4.949s.729 3.628 2.051 4.949c1.321 1.322 3.079 2.051 4.949 2.051s3.628-.729 4.949-2.051a6.951 6.951 0 0 0 2.051-4.949 6.955 6.955 0 0 0-2.051-4.949c-.9-.9-2-1.517-3.205-1.824 1.373-7.859 4.764-13.818 11.999-21.11.128-.13.356-.158.456-.059 9.207 9.274 12.805 18.06 12.832 31.33-.026 3.079-.202 6.527-.536 10.54a.997.997 0 0 0 .25.749l10.166 11.379c.062.076.109.23.093.32l-4.547 17.407c-.004.015-.009.036-.079.106a.403.403 0 0 1-.2.106l-3.577.002c-.144-.009-.265-.077-.309-.153l-5.425-10.328a1.002 1.002 0 0 0-.886-.535H30.024c-.371 0-.713.206-.886.535l-5.407 10.303-.069.072a.366.366 0 0 1-.199.105l-3.588.001c-.179-.009-.304-.123-.33-.227l-4.531-17.338a.525.525 0 0 1 .049-.34L25.26 44.682a1 1 0 0 0-1.492-1.332L13.539 54.803c-.448.554-.63 1.312-.474 2.084l4.544 17.396c.253.963 1.146 1.669 2.218 1.719h3.636c.581 0 1.187-.261 1.615-.693.114-.114.286-.286.406-.528l5.144-9.793h14.754l5.16 9.822c.396.697 1.124 1.143 2.01 1.192l3.712-.003a2.396 2.396 0 0 0 1.544-.694c.313-.316.504-.646.598-1.022l4.557-17.451a2.502 2.502 0 0 0-.518-2.066M29.01 30.001c0 1.335-.521 2.591-1.465 3.535s-2.2 1.465-3.535 1.465-2.591-.521-3.535-1.465-1.465-2.2-1.465-3.535.521-2.591 1.465-3.535 2.2-1.465 3.535-1.465 2.591.521 3.535 1.465 1.465 2.2 1.465 3.535"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 76 76"><path d="M68 67c-1.725 0-3.36.541-4.723 1.545A12.998 12.998 0 0 0 52 62c-2.734 0-5.359.853-7.555 2.43L42.159 49h1.228l3.829 7.645c.339.598.962.979 1.724 1.022l2.812-.003a2.07 2.07 0 0 0 1.316-.595c.264-.266.433-.559.514-.882l3.433-13.145a2.138 2.138 0 0 0-.449-1.763l-7.385-8.268c.231-2.875.354-5.376.374-7.641C49.532 14.863 46.684 7.908 39.393.564c-.737-.742-2.072-.715-2.829.044-5.617 5.659-8.309 10.336-9.446 16.463a5.95 5.95 0 0 0-3.36 1.686C22.624 19.891 22 21.397 22 23s.624 3.109 1.758 4.242C24.891 28.376 26.397 29 28 29s3.109-.624 4.242-1.758C33.376 26.109 34 24.603 34 23s-.624-3.109-1.758-4.242a5.952 5.952 0 0 0-3.098-1.648c1.095-5.538 3.637-9.855 8.83-15.14 6.874 6.924 9.561 13.485 9.581 23.392-.021 2.316-.151 4.903-.402 7.91a.999.999 0 0 0 .25.749l7.663 8.572-3.391 13.07-2.695.036-4.081-8.15a1.001 1.001 0 0 0-.895-.553h-12.01c-.379 0-.725.214-.895.553l-4.04 8.114-2.707.015-3.427-13.07 7.671-8.588a1 1 0 0 0-1.492-1.332l-7.7 8.623c-.383.47-.54 1.116-.406 1.787l3.419 13.08c.216.829.98 1.438 1.907 1.48h2.735c.508 0 1.016-.218 1.391-.595.091-.09.242-.241.358-.475l3.804-7.597h1.228l-2.286 15.43a12.914 12.914 0 0 0-7.555-2.43c-4.685 0-8.979 2.53-11.277 6.545a7.943 7.943 0 0 0-4.723-1.545c-4.411 0-8 3.589-8 8a1 1 0 0 0 1 1h74a1 1 0 0 0 1-1c0-4.411-3.589-8-8-8m-36-44a3.973 3.973 0 0 1-1.172 2.828c-1.512 1.512-4.145 1.512-5.656 0-.756-.756-1.172-1.76-1.172-2.828s.416-2.072 1.172-2.828 1.76-1.172 2.828-1.172 2.072.416 2.828 1.172 1.172 1.76 1.172 2.828m-29.917 51a6.01 6.01 0 0 1 5.917-5c1.638 0 3.17.652 4.313 1.836a.998.998 0 0 0 1.634-.289 11.011 11.011 0 0 1 10.05-6.547c2.836 0 5.532 1.085 7.593 3.055a1.001 1.001 0 0 0 1.681-.576l2.588-17.479h4.275l2.589 17.479a.999.999 0 1 0 1.681.576 10.945 10.945 0 0 1 7.593-3.055c4.343 0 8.288 2.57 10.05 6.547a.998.998 0 0 0 1.634.289 5.948 5.948 0 0 1 4.313-1.836 6.01 6.01 0 0 1 5.917 5H2.076"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 16 16"><g fill-rule="evenodd"><path d="M14 16.01h1V7.99C15 4.128 11.866.999 8 .999c-3.858 0-7 3.13-7 6.991v8.02h1V7.99c0-3.306 2.691-5.991 6-5.991 3.314 0 6 2.682 6 5.991v8.02M3.48 2.656a2 2 0 1 0-2.155 3.228c.102-.321.226-.631.371-.93a1.001 1.001 0 1 1 1.069-1.599 6.96 6.96 0 0 1 .717-.699m9.04-.002a2 2 0 1 1 2.155 3.23 6.835 6.835 0 0 0-.37-.931 1 1 0 1 0-1.068-1.599 6.96 6.96 0 0 0-.717-.699"/><path d="M5.726 8.04h1.557v.124c0 .283-.033.534-.1.752a1.583 1.583 0 0 1-.33.566c-.35.394-.795.591-1.335.591-.527 0-.979-.19-1.355-.571a1.893 1.893 0 0 1-.564-1.377c0-.547.191-1.01.574-1.391a1.902 1.902 0 0 1 1.396-.574c.295 0 .57.06.825.181.244.12.484.316.72.586l-.405.388c-.309-.412-.686-.618-1.13-.618-.399 0-.733.138-1 .413-.27.27-.405.609-.405 1.015 0 .42.151.766.452 1.037.282.252.587.378.915.378.28 0 .531-.094.754-.283.223-.19.347-.418.373-.683h-.94v-.535m2.884.061c0-.53.194-.986.583-1.367a1.919 1.919 0 0 1 1.396-.571c.537 0 .998.192 1.382.576.386.384.578.845.578 1.384 0 .542-.194 1-.581 1.379a1.944 1.944 0 0 1-1.408.569c-.487 0-.923-.168-1.311-.505-.426-.373-.64-.861-.64-1.465m.574.007c0 .417.14.759.42 1.028.278.269.6.403.964.403.395 0 .729-.137 1-.41.272-.277.408-.613.408-1.01 0-.402-.134-.739-.403-1.01a1.33 1.33 0 0 0-.991-.41c-.392 0-.723.137-.993.41a1.36 1.36 0 0 0-.405 1m-.184 3.918c.525.026.812.063.812.063.271.025.324-.096.116-.273 0 0-.775-.813-1.933-.813-1.159 0-1.923.813-1.923.813-.211.174-.153.3.12.273 0 0 .286-.037.81-.063v.477c0 .268.224.5.5.5.268 0 .5-.223.5-.498v-.252.25c0 .268.224.5.5.5.268 0 .5-.223.5-.498v-.478m-1-1.023c.552 0 1-.224 1-.5s-.448-.5-1-.5-1 .224-1 .5.448.5 1 .5"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" version="1" viewBox="0 0 501 501"><path d="M236 .7C137.7 7.5 54 68.2 18.2 158.5c-32 81-19.6 172.8 33 242.5 39.8 53 97.2 87 164.3 97 16.5 2.7 48 3.2 63.5 1.2 48.7-6.3 92.2-24.6 129-54.2 13-10.5 33-31.2 42.2-43.7 26.4-35.5 42.8-75.8 49-120.3 1.6-12.3 1.6-48.7 0-61-4-28.3-12-54.8-24.2-79.5-12.8-26-26.5-45.3-46.8-65.8C417.8 64 400.2 49 398.4 49c-.6 0-.4 10.5.3 26l1.3 26 7 8.7c19 23.7 32.8 53.5 38.2 83 2.5 14 3 43 1 55.8-4.5 27.8-15.2 54-31 76.5-8.6 12.2-28 31.6-40.2 40.2-24 17-50 27.6-80 33-10 1.8-49 1.8-59 0-43-7.7-78.8-26-107.2-54.8-29.3-29.7-46.5-64-52.4-104.4-2-14-1.5-42 1-55C90 121.4 132 72 192 49.7c8-3 18.4-5.8 29.5-8.2 1.7-.4 34.4-38 35.3-40.6.3-1-10.2-1-20.8-.4z"/><path d="M322.2 24.6c-1.3.8-8.4 9.3-16 18.7-7.4 9.5-22.4 28-33.2 41.2-51 62.2-66 81.6-70.6 91-6 12-8.4 21-9 33-1.2 19.8 5 36 19 50C222 268 230 273 243 277.2c9 3 10.4 3.2 24 3.2 13.8 0 15 0 22.6-3 23.2-9 39-28.4 45-55.7 2-8.2 2-28.7.4-79.7l-2-72c-1-36.8-1.4-41.8-3-44-2-3-4.8-3.6-7.8-1.4z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 374 268" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="d" width="230" height="176" rx="10" fill="#fff"/><rect id="e" width="14" rx="2" height="4"/><rect id="f" width="14" x="40" rx="2" height="4"/><rect id="g" width="14" x="40" y="24" rx="2" height="4"/><rect id="h" width="7" x="20" y="12" rx="2" height="4"/><rect id="i" width="7" y="24" rx="2" height="4"/><rect id="j" width="7" x="33" y="12" rx="2" height="4"/><circle id="l" cx="31" cy="31" r="31"/><circle id="c" cx="35" cy="35" r="35"/><circle id="a" cx="44" cy="44" r="44"/><circle id="b" cx="31" cy="31" r="31"/></defs><g fill="none" fill-rule="evenodd"><g transform="translate(0 94)"><circle cx="57" cy="57" r="44" fill="#f9f9f9"/><g transform="rotate(-7.999 120.507 -22.508)"><use fill="#fff" xlink:href="#a"/><circle cx="44" cy="44" r="42" stroke="#eee" stroke-width="4"/><path fill="#fee1d3" fill-rule="nonzero" d="M34.394 55.736A4 4 0 0 1 36.706 55H56a6 6 0 0 0 6-6V35a6 6 0 0 0-6-6H34a6 6 0 0 0-6 6v25.26l6.394-4.529m2.312 3.264l-7.972 5.647A3.001 3.001 0 0 1 24 62.194v-27.2c0-5.523 4.477-10 10-10h22c5.523 0 10 4.477 10 10v14c0 5.523-4.477 10-10 10H36.706"/><path fill="#fc6d26" d="M38 40a2 2 0 1 1 .001 3.999A2 2 0 0 1 38 40m7 0a2 2 0 1 1 .001 3.999A2 2 0 0 1 45 40m7 0a2 2 0 1 1 .001 3.999A2 2 0 0 1 52 40"/></g></g><g transform="translate(48)"><circle cx="41" cy="41" r="31" fill="#f9f9f9"/><g transform="rotate(-7.999 84.554 -15.551)"><use fill="#fff" xlink:href="#b"/><circle cx="31" cy="31" r="29" stroke="#eee" stroke-width="4"/><rect width="20" height="4" x="21" y="29" fill="#6b4fbb" rx="2"/></g></g><path fill="#f9f9f9" d="M235.58 229H102c-6.627 0-12-5.373-12-12V65c0-6.627 5.373-12 12-12h206c6.627 0 12 5.373 12 12v18.399A34.834 34.834 0 0 1 337 79c19.33 0 35 15.67 35 35s-15.67 35-35 35a34.831 34.831 0 0 1-17-4.399v72.4c0 6.627-5.373 12-12 12h-11.58c.381 1.941.58 3.947.58 6 0 17.12-13.879 31-31 31-17.12 0-31-13.879-31-31 0-2.053.2-4.059.58-6"/><g transform="translate(87 50)"><g transform="rotate(7.999 -44.933 1563.894)"><use fill="#fff" xlink:href="#c"/><circle cx="35" cy="35" r="33" stroke="#eee" stroke-width="4"/><g transform="translate(20 19)"><circle cx="15" cy="16" r="15" fill="#f4f1fa" stroke="#6b4fbb" stroke-width="3"/><g fill="#6b4fbb"><path d="M19.419 6.996h-.007L16.959 4l-2.454 2.997H14.5L12.046 4 9.591 6.998h-.003L7.133 4 4.677 6.999H2.001c2.605-4.204 7.231-7 12.502-7 5.269 0 9.892 2.793 12.498 6.994h-2.676l-2.452-2.994-2.453 2.996"/><circle cx="9.5" cy="17.5" r="1.5"/><circle cx="20.5" cy="17.5" r="1.5"/></g></g></g><use xlink:href="#d"/><rect width="226" height="172" x="2" y="2" stroke="#eee" stroke-width="4" rx="10"/><rect width="4" height="122" x="33" y="42" fill="#eee" rx="2"/><g transform="translate(13 59)"><rect width="10" height="4" fill="#fee1d3" rx="2"/><rect width="10" height="4" y="12" fill="#f0edf8" rx="2"/><rect width="10" height="4" y="24" fill="#fef0e9" rx="2"/><rect width="10" height="4" y="36" fill="#fee1d3" rx="2"/><rect width="10" height="4" y="48" fill="#e1dbf1" rx="2"/><rect width="10" height="4" y="60" fill="#f0edf8" rx="2"/><rect width="10" height="4" y="72" fill="#fef0e9" rx="2"/><rect width="10" height="4" y="84" fill="#fee1d3" rx="2"/></g><g transform="translate(55 59)"><use fill="#6b4fbb" xlink:href="#e"/><rect width="14" height="4" x="20" fill="#f0edf8" rx="2"/><use fill="#fef0e9" xlink:href="#f"/><rect width="14" height="4" y="12" fill="#f0edf8" rx="2"/><use fill="#fef0e9" xlink:href="#g"/><rect width="14" height="4" y="48" fill="#e1dbf1" rx="2"/><rect width="14" height="4" x="40" y="36" fill="#fef0e9" rx="2"/><use fill="#fee1d3" xlink:href="#h"/><rect width="7" height="4" x="27" y="36" fill="#6b4fbb" rx="2"/><rect width="7" height="4" x="20" y="48" fill="#fee1d3" rx="2"/><use fill="#fc6d26" xlink:href="#i"/><rect width="21" height="4" x="13" y="24" fill="#e1dbf1" rx="2"/><rect width="21" height="4" y="36" fill="#eee" rx="2"/><use fill="#6b4fbb" xlink:href="#j"/><g transform="translate(98)"><use fill="#fee1d3" xlink:href="#e"/><rect width="14" height="4" x="20" fill="#f0edf8" rx="2"/><use fill="#fc6d26" xlink:href="#f"/><rect width="14" height="4" y="12" fill="#fef0e9" rx="2" id="k"/><use fill="#e1dbf1" xlink:href="#g"/><rect width="14" height="4" y="48" fill="#f0edf8" rx="2"/><rect width="14" height="4" x="40" y="36" fill="#fee1d3" rx="2"/><use fill="#fc6d26" xlink:href="#h"/><rect width="7" height="4" x="27" y="36" fill="#6b4fbb" rx="2"/><rect width="7" height="4" x="20" y="48" fill="#fc6d26" rx="2"/><use fill="#6b4fbb" xlink:href="#i"/><rect width="21" height="4" x="13" y="24" fill="#fee1d3" rx="2"/><rect width="21" height="4" y="36" fill="#fef0e9" rx="2"/><use fill="#6b4fbb" xlink:href="#j"/></g><g transform="translate(0 60)"><use fill="#f0edf8" xlink:href="#e"/><rect width="14" height="4" x="20" fill="#6b4fbb" rx="2"/><use fill="#e1dbf1" xlink:href="#f"/><use xlink:href="#k"/><use fill="#fee1d3" xlink:href="#g"/><use fill="#eee" xlink:href="#h"/><use fill="#6b4fbb" xlink:href="#i"/><rect width="21" height="4" x="13" y="24" fill="#fef0e9" rx="2"/><use fill="#fc6d26" xlink:href="#j"/></g><rect width="4" height="63" x="74" y="13" fill="#eee" rx="2"/></g><rect width="230" height="4" y="27" fill="#eee" rx="2"/></g><g transform="rotate(7.999 -1289.786 1797.583)"><use fill="#fff" xlink:href="#l"/><circle cx="31" cy="31" r="29" stroke="#eee" stroke-width="4"/><path fill="#fc6d26" d="M29 29h-6a2 2 0 1 0 0 4h6v6a2 2 0 1 0 4 0v-6h6a2 2 0 1 0 0-4h-6v-6a2 2 0 1 0-4 0v6"/></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 406 305" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="0" width="159.8" height="127.81" x=".196" y="5" rx="10"/><rect id="2" width="160" height="128" x=".666" y=".41" rx="10"/><rect id="4" width="160.19" height="128.19" x=".339" y=".59" rx="10"/><mask id="1" width="159.8" height="127.81" x="0" y="0" fill="#fff"><use xlink:href="#0"/></mask><mask id="3" width="160" height="128" x="0" y="0" fill="#fff"><use xlink:href="#2"/></mask><mask id="5" width="160.19" height="128.19" x="0" y="0" fill="#fff"><use xlink:href="#4"/></mask></defs><g fill="none" fill-rule="evenodd" transform="translate(12 3)"><rect width="160" height="128" x="122.08" y="146.08" fill="#f9f9f9" transform="matrix(.99619.08716-.08716.99619 19.08-16.813)" rx="10"/><g transform="matrix(.96593.25882-.25882.96593 227.1 57.47)"><rect width="159.8" height="127.81" x="1.64" y="10.06" fill="#f9f9f9" rx="8"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#1)" xlink:href="#0"/><g transform="translate(24.368 36.951)"><path fill="#d2caea" fill-rule="nonzero" d="m71.785 44.2c.761.296 1.625.099 2.184-.496l35.956-38.34c.756-.806.715-2.071-.091-2.827-.806-.756-2.071-.715-2.827.091l-35.03 37.36-41.888-16.285c-.749-.291-1.6-.106-2.16.471l-26.368 27.16c-.769.793-.751 2.059.042 2.828.793.769 2.059.751 2.828-.042l25.444-26.21 41.911 16.294"/><g fill="#fff"><circle cx="5.716" cy="5.104" r="5" stroke="#6b4fbb" stroke-width="4" transform="translate(65.917 34.945)"/><g stroke="#fb722e"><ellipse cx="4.632" cy="50.05" stroke-width="3.2" rx="4" ry="3.999"/><g stroke-width="4"><ellipse cx="29.632" cy="27.05" rx="4" ry="3.999"/><ellipse cx="107.63" cy="4.048" rx="4" ry="3.999"/></g></g></g></g></g><rect width="160.19" height="128.19" x="36.28" y="86.74" fill="#f9f9f9" transform="matrix(.99619-.08716.08716.99619-12.703 10.717)" rx="10"/><g transform="matrix(.99619.08716-.08716.99619 126.61 137.8)"><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#3)" xlink:href="#2"/><path fill="#6b4fbb" stroke="#6b4fbb" stroke-width="3.2" d="m84.67 28.41c18.225 0 33 15.07 33 33.651h-33v-33.651" stroke-linecap="round" stroke-linejoin="round"/><path fill="#d2caea" fill-rule="nonzero" d="m78.67 66.41h30c1.105 0 2 .895 2 2 0 18.778-15.222 34-34 34-18.778 0-34-15.222-34-34 0-18.778 15.222-34 34-34 1.105 0 2 .895 2 2v30m-32 2c0 16.569 13.431 30 30 30 15.896 0 28.905-12.364 29.934-28h-29.934c-1.105 0-2-.895-2-2v-29.934c-15.636 1.029-28 14.04-28 29.934"/></g><g transform="matrix(.99619-.08716.08716.99619 30 88.03)"><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#5)" xlink:href="#4"/><g transform="translate(42 34)"><path fill="#fef0ea" d="m0 13.391c0-.768.628-1.391 1.4-1.391h9.2c.773 0 1.4.626 1.4 1.391v49.609h-12v-49.609"/><path fill="#fb722e" d="m66 21.406c0-.777.628-1.406 1.4-1.406h9.2c.773 0 1.4.624 1.4 1.406v41.594h-12v-41.594"/><path fill="#6b4fbb" d="m22 1.404c0-.776.628-1.404 1.4-1.404h9.2c.773 0 1.4.624 1.4 1.404v61.6h-12v-61.6"/><path fill="#d2caea" d="m44 39.4c0-.772.628-1.398 1.4-1.398h9.2c.773 0 1.4.618 1.4 1.398v23.602h-12v-23.602"/></g></g><g fill="#fee8dc"><path d="m6.226 94.95l-2.84.631c-1.075.239-1.752-.445-1.515-1.515l.631-2.84-.631-2.84c-.239-1.075.445-1.752 1.515-1.515l2.84.631 2.84-.631c1.075-.239 1.752.445 1.515 1.515l-.631 2.84.631 2.84c.239 1.075-.445 1.752-1.515 1.515l-2.84-.631" transform="matrix(.70711.70711-.70711.70711 66.33 22.317)"/><path d="m312.78 53.43l-3.634.807c-1.296.288-2.115-.52-1.825-1.825l.807-3.634-.807-3.634c-.288-1.296.52-2.115 1.825-1.825l3.634.807 3.634-.807c1.296-.288 2.115.52 1.825 1.825l-.807 3.634.807 3.634c.288 1.296-.52 2.115-1.825 1.825l-3.634-.807" transform="matrix(.70711.70711-.70711.70711 126.1-206.88)"/></g><path fill="#e1dcf1" d="m124.78 12.43l-3.617.804c-1.306.29-2.129-.53-1.839-1.839l.804-3.617-.804-3.617c-.29-1.306.53-2.129 1.839-1.839l3.617.804 3.617-.804c1.306-.29 2.129.53 1.839 1.839l-.804 3.617.804 3.617c.29 1.306-.53 2.129-1.839 1.839l-3.617-.804" transform="matrix(.70711-.70711.70711.70711 31.05 90.51)"/><path fill="#d2caea" d="m374.78 244.43l-3.617.804c-1.306.29-2.129-.53-1.839-1.839l.804-3.617-.804-3.617c-.29-1.306.53-2.129 1.839-1.839l3.617.804 3.617-.804c1.306-.29 2.129.53 1.839 1.839l-.804 3.617.804 3.617c.29 1.306-.53 2.129-1.839 1.839l-3.617-.804" transform="matrix(.70711-.70711.70711.70711-59.779 335.24)"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 406 305" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="a" width="159.8" height="127.81" x=".196" y="5" rx="10"/><rect id="b" width="160" height="128" x=".666" y=".41" rx="10"/><rect id="c" width="160.19" height="128.19" x=".339" y=".59" rx="10"/><mask id="d" width="159.8" height="127.81" x="0" y="0" fill="#fff"><use xlink:href="#a"/></mask><mask id="e" width="160" height="128" x="0" y="0" fill="#fff"><use xlink:href="#b"/></mask><mask id="f" width="160.19" height="128.19" x="0" y="0" fill="#fff"><use xlink:href="#c"/></mask></defs><g fill="none" fill-rule="evenodd" transform="translate(12 3)"><rect width="160" height="128" x="122.08" y="146.08" fill="#f9f9f9" transform="rotate(5 202.071 210.085)" rx="10"/><g transform="rotate(15 -104.714 891.23)"><rect width="159.8" height="127.81" x="1.64" y="10.06" fill="#f9f9f9" rx="8"/><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#d)" xlink:href="#a"/><path fill="#d2caea" fill-rule="nonzero" d="M96.153 81.151a2.001 2.001 0 0 0 2.184-.496l35.956-38.34a2 2 0 1 0-2.918-2.736l-35.03 37.36-41.888-16.285a2 2 0 0 0-2.16.471l-26.368 27.16a2 2 0 1 0 2.87 2.786l25.444-26.21 41.911 16.294"/><g fill="#fff" transform="translate(24.368 36.951)"><circle cx="5.716" cy="5.104" r="5" stroke="#6b4fbb" stroke-width="4" transform="translate(65.917 34.945)"/><g stroke="#fb722e"><ellipse cx="4.632" cy="50.05" stroke-width="3.2" rx="4" ry="3.999"/><g stroke-width="4"><ellipse cx="29.632" cy="27.05" rx="4" ry="3.999"/><ellipse cx="107.63" cy="4.048" rx="4" ry="3.999"/></g></g></g></g><rect width="160.19" height="128.19" x="36.28" y="86.74" fill="#f9f9f9" transform="rotate(-5 116.372 150.825)" rx="10"/><g transform="rotate(5 -1514.687 1518.752)"><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#e)" xlink:href="#b"/><path fill="#6b4fbb" stroke="#6b4fbb" stroke-width="3.2" d="M84.67 28.41c18.225 0 33 15.07 33 33.651h-33V28.41" stroke-linecap="round" stroke-linejoin="round"/><path fill="#d2caea" fill-rule="nonzero" d="M78.67 66.41h30a2 2 0 0 1 2 2c0 18.778-15.222 34-34 34s-34-15.222-34-34 15.222-34 34-34a2 2 0 0 1 2 2v30m-32 2c0 16.569 13.431 30 30 30 15.896 0 28.905-12.364 29.934-28H76.67a2 2 0 0 1-2-2V38.476c-15.636 1.029-28 14.04-28 29.934"/></g><g transform="rotate(-5 1023.06 -299.524)"><use fill="#fff" stroke="#eee" stroke-width="8" mask="url(#f)" xlink:href="#c"/><path fill="#fef0ea" d="M42 47.391c0-.768.628-1.391 1.4-1.391h9.2c.773 0 1.4.626 1.4 1.391V97H42V47.391"/><path fill="#fb722e" d="M108 55.406c0-.777.628-1.406 1.4-1.406h9.2a1.4 1.4 0 0 1 1.4 1.406V97h-12V55.406"/><path fill="#6b4fbb" d="M64 35.404c0-.776.628-1.404 1.4-1.404h9.2a1.4 1.4 0 0 1 1.4 1.404v61.6H64v-61.6"/><path fill="#d2caea" d="M86 73.4a1.4 1.4 0 0 1 1.4-1.398h9.2c.773 0 1.4.618 1.4 1.398v23.602H86V73.4"/></g><g fill="#fee8dc"><path d="M3.592 93.86l-2.454-1.562c-.93-.592-.924-1.554 0-2.143l2.454-1.562 1.562-2.454c.592-.93 1.554-.925 2.143 0l1.562 2.454 2.454 1.562c.93.591.924 1.554 0 2.143L8.86 93.86l-1.562 2.454c-.591.93-1.554.924-2.143 0L3.592 93.86M309.489 52.07l-3.14-1.998c-1.12-.713-1.128-1.863 0-2.581l3.14-2 1.999-3.14c.713-1.12 1.863-1.127 2.58 0l2 3.14 3.14 2c1.12.713 1.128 1.863 0 2.58l-3.14 2-2 3.14c-.712 1.12-1.862 1.128-2.58 0l-1.999-3.14"/></g><path fill="#e1dcf1" d="M128.073 11.066l-1.99 3.126c-.718 1.129-1.88 1.131-2.6 0l-1.99-3.126-3.126-1.989c-1.128-.718-1.13-1.88 0-2.6l3.127-1.99 1.989-3.126c.718-1.128 1.88-1.13 2.6 0l1.99 3.126 3.126 1.99c1.128.718 1.13 1.88 0 2.6l-3.126 1.99"/><path fill="#d2caea" d="M378.07 243.068l-1.989 3.126c-.718 1.129-1.88 1.131-2.6 0l-1.99-3.126-3.126-1.989c-1.128-.718-1.13-1.88 0-2.6l3.127-1.99 1.989-3.126c.718-1.128 1.88-1.13 2.6 0l1.99 3.126 3.126 1.99c1.128.718 1.13 1.88 0 2.6l-3.126 1.99"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 168 107" xmlns:xlink="http://www.w3.org/1999/xlink"><g fill="#eee" fill-rule="evenodd"><path d="M4.01 2h1.102a1 1 0 0 0 0-2H4.01A4.001 4.001 0 0 0 0 4a1 1 0 0 0 2 0c0-1.108.892-2 2.01-2m12.702 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7m11.6 0a1 1 0 0 0 0-2h-5.7a1 1 0 0 0 0 2h5.7M164 2c.822 0 1.554.503 1.86 1.254a1 1 0 1 0 1.853-.753 4.01 4.01 0 0 0-3.712-2.5h-2.188a1 1 0 0 0 0 2h2.188m2.01 12.518a1 1 0 0 0 2 0v-5.7a1 1 0 0 0-2 0v5.7m0 11.6a1 1 0 0 0 2 0v-5.7a1 1 0 0 0-2 0v5.7m0 11.6a1 1 0 0 0 2 0v-5.7a1 1 0 0 0-2 0v5.7m0 6.282c0 1.108-.892 2-2.01 2h-.72a1 1 0 0 0 0 2h.72a4.001 4.001 0 0 0 4.01-4v-.382a1 1 0 0 0-2 0v.382m-14.325 2a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-11.6 0a1 1 0 0 0 0 2h5.7a1 1 0 0 0 0-2h-5.7m-8.47 0a2.01 2.01 0 0 1-1.782-1.085 1 1 0 0 0-1.775.923 4.007 4.007 0 0 0 3.556 2.162h2.57a1 1 0 0 0 0-2h-2.57m-2.01-12.136a1 1 0 0 0-2 0v5.7a1 1 0 0 0 2 0v-5.7m0-11.6a1 1 0 0 0-2 0v5.7a1 1 0 0 0 2 0v-5.7m0-11.6a1 1 0 0 0-2 0v5.7a1 1 0 0 0 2 0v-5.7m0-6.664a1 1 0 0 0-2 0v.764a1 1 0 0 0 2 0v-.764" id="a"/><circle cx="21" cy="24" r="10"/><rect width="33" height="3" x="37" y="18" rx="1.5" id="b"/><rect width="53" height="3" x="37" y="27" rx="1.5" id="c"/><path d="M131 29c0 .552.447.999.996.999h22.01c.545 0 .996-.451.996-.999v-9a.998.998 0 0 0-.996-.999h-22.01c-.545 0-.996.451-.996.999v9m.996-12h22.01a2.998 2.998 0 0 1 2.996 2.999v9a3.003 3.003 0 0 1-2.996 2.999h-22.01A2.998 2.998 0 0 1 129 28.999v-9A3.003 3.003 0 0 1 131.996 17" id="d"/><g transform="translate(0 59)"><use xlink:href="#a"/><circle cx="21" cy="24" r="10"/><use xlink:href="#b"/><use xlink:href="#c"/><use xlink:href="#d"/></g></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#000" fill-opacity=".03" d="M2.12 42C2.04 43 2 44 2 45c0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3C74.35 61.03 58.42 76 39 76S3.65 61.03 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M59.65 32.65H60l-2-2.42-2 2.4-2-2.4-2 2.4-2-2.4-2 2.4-2-2.4-2 2.42h.77C45.57 34.6 46 36.75 46 39c0 2.84-.7 5.5-1.92 7.86 1.97 2.28 4.83 3.64 7.92 3.64 5.8 0 10.5-4.74 10.5-10.6 0-2.8-1.08-5.36-2.85-7.25zM43.18 29.6c2.4-2.1 5.52-3.3 8.82-3.3 7.46 0 13.5 6.1 13.5 13.6S59.46 53.5 52 53.5c-3.68 0-7.1-1.5-9.6-4.04C39.3 53.44 34.44 56 29 56c-9.4 0-17-7.6-17-17s7.6-17 17-17c3.22 0 6.23.9 8.8 2.45 2.13 1.3 3.97 3.05 5.38 5.16zM17 34c-.65 1.54-1 3.23-1 5 0 7.18 5.82 13 13 13s13-5.82 13-13c0-1.77-.35-3.46-1-5h-9c-.53 0-1.04-.2-1.4-.6L29 31.84l-1.6 1.58c-.36.4-.87.6-1.4.6h-9zm21.38-4a12.996 12.996 0 0 0-18.76 0h5.55l2.42-2.4c.74-.8 2-.8 2.8 0l2.4 2.4h5.54z"/><path fill="#6B4FBB" d="M47.6 42.32c-.66 0-1.2-.54-1.2-1.2 0-.68.54-1.22 1.2-1.22.66 0 1.2.54 1.2 1.2 0 .68-.54 1.22-1.2 1.22zm8.8 0c-.66 0-1.2-.54-1.2-1.2 0-.68.54-1.22 1.2-1.22.66 0 1.2.54 1.2 1.2 0 .68-.54 1.22-1.2 1.22zM25 44h8c0 2.2-1.8 4-4 4s-4-1.8-4-4zm-1.5-1c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76S3.647 61.032 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M30 24c-2.21 0-4 1.79-4 4v22c0 2.21 1.79 4 4 4h18c2.21 0 4-1.79 4-4V28c0-2.21-1.79-4-4-4H30zm0-4h18a8 8 0 0 1 8 8v22a8 8 0 0 1-8 8H30a8 8 0 0 1-8-8V28a8 8 0 0 1 8-8z"/><path fill="#6B4FBB" d="M33 30h8a2 2 0 1 1 0 4h-8a2 2 0 1 1 0-4zm0 7h12a2 2 0 1 1 0 4H33a2 2 0 1 1 0-4zm0 7h12a2 2 0 1 1 0 4H33a2 2 0 1 1 0-4z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#000" fill-opacity=".03" d="M2.12 42C2.04 43 2 44 2 45c0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3C74.35 61.03 58.42 76 39 76S3.65 61.03 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#E1DBF2" d="M44 31l-2.5-3-2.5 3-2.5-3-2.5 3-2.5-3-2.5 3h-2.72c2.65-4.2 7.36-7 12.72-7s10.07 2.8 12.72 7H49l-2.5-3-2.5 3z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M39 57c-9.4 0-17-7.6-17-17s7.6-17 17-17 17 7.6 17 17-7.6 17-17 17zm0-4c7.18 0 13-5.82 13-13s-5.82-13-13-13-13 5.82-13 13 5.82 13 13 13z"/><path fill="#6B4FBB" d="M35 45h8c0 2.2-1.8 4-4 4s-4-1.8-4-4zm-1.5-2c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#000" fill-opacity=".03" d="M2.12 42C2.04 43 2 44 2 45c0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3C74.35 61.03 58.42 76 39 76S3.65 61.03 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#FEE1D3" fill-rule="nonzero" d="M24.92 35.15a4.012 4.012 0 0 1-.6-5.63l1.26-1.55c1.4-1.72 3.9-2 5.63-.6l.7.56c.7-.4 1.4-.73 2.1-1V26c0-2.2 1.8-4 4-4h2c2.2 0 4 1.8 4 4v.92c.8.28 1.5.62 2.1 1l.7-.55c1.7-1.4 4.3-1.12 5.7.6l1.3 1.55c1.4 1.72 1.2 4.23-.6 5.63l-.7.6c.3.74.4 1.5.5 2.3l.9.2c2.2.5 3.5 2.64 3 4.8L56.4 45c-.5 2.15-2.64 3.5-4.8 3l-.88-.2c-.44.63-.92 1.24-1.46 1.8l.4.82c.9 1.98.1 4.38-1.9 5.35l-1.8.87c-2 .97-4.37.15-5.34-1.84l-.46-.85c-.34.03-.74.05-1.13.05-.4 0-.8-.02-1.2-.05l-.4.85c-.95 2-3.34 2.8-5.33 1.84l-1.8-.87a4.011 4.011 0 0 1-1.83-5.35l.4-.8c-.54-.58-1.02-1.2-1.46-1.83l-.8.2c-2.2.5-4.3-.9-4.8-3l-.4-2c-.5-2.2.85-4.3 3-4.8l.9-.2c.1-.8.3-1.6.5-2.3l-.7-.6zm4.95.77c-.53 1.2-.83 2.47-.87 3.8-.02.9-.66 1.68-1.55 1.9l-2.32.53.45 1.94 2.3-.6c.9-.2 1.8.2 2.23 1 .7 1.1 1.5 2.2 2.5 3 .7.6.9 1.6.5 2.4l-1 2.1 1.8.9 1.1-2.1c.4-.8 1.3-1.3 2.2-1.1.7.1 1.3.2 2 .2s1.3-.1 2-.2c.9-.2 1.8.3 2.2 1.1l1 2.1 1.8-.9-1.2-2c-.4-.8-.2-1.8.5-2.4 1-.85 1.84-1.88 2.45-3.05.4-.82 1.33-1.24 2.2-1.04l2.33.54.45-1.95-2.32-.54c-.9-.2-1.52-.97-1.54-1.88-.03-1.4-.33-2.6-.86-3.8-.4-.9-.2-1.8.5-2.4l1.9-1.5-1.3-1.6-1.8 1.5c-.8.5-1.8.6-2.5 0-1.1-.8-2.3-1.4-3.5-1.7-.9-.2-1.5-1-1.5-1.9V26h-2v2.38c0 .9-.6 1.7-1.5 1.93-1.3.4-2.5 1-3.5 1.7-.8.6-1.8.6-2.5 0l-1.9-1.5-1.26 1.6 1.8 1.5c.7.6.94 1.6.6 2.4z"/><path fill="#FC6D26" fill-rule="nonzero" d="M39 46c-3.3 0-6-2.7-6-6s2.7-6 6-6 6 2.7 6 6-2.7 6-6 6zm0-4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="330" height="132" viewBox="0 0 330 132"><g fill="none" fill-rule="evenodd"><path fill="#000" fill-opacity=".03" d="M174.12 42c-.08 1-.12 2-.12 3 0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3-1.53 19.03-17.46 34-36.88 34s-35.35-14.97-36.88-34z"/><path fill="#EEE" fill-rule="nonzero" d="M211 78c-21.54 0-39-17.46-39-39s17.46-39 39-39 39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S230.33 4 211 4s-35 15.67-35 35 15.67 35 35 35z"/><g fill-rule="nonzero"><path fill="#FEE1D3" d="M211.5 51c-6.42 0-12.26-2.84-17.43-8.4a4.008 4.008 0 0 1-.27-5.13C199 30.57 204.92 27 211.5 27s12.5 3.56 17.7 10.47a3.994 3.994 0 0 1-.27 5.12c-5.17 5.53-11 8.4-17.43 8.4zm0-4c5.25 0 10.05-2.34 14.5-7.13-4.5-5.98-9.3-8.87-14.5-8.87-5.2 0-10 2.9-14.5 8.87 4.45 4.8 9.25 7.13 14.5 7.13z"/><path fill="#FC6D26" d="M211 47c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm0-4c2.2 0 4-1.8 4-4s-1.8-4-4-4-4 1.8-4 4 1.8 4 4 4zm0-1c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3z"/></g><path fill="#000" fill-opacity=".03" d="M88.12 83c-.08 1-.12 2-.12 3 0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3-1.53 19.03-17.46 34-36.88 34s-35.35-14.97-36.88-34z"/><path fill="#EEE" fill-rule="nonzero" d="M125 119c-21.54 0-39-17.46-39-39s17.46-39 39-39 39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35s-15.67-35-35-35-35 15.67-35 35 15.67 35 35 35z"/><path fill="#FEE1D3" fill-rule="nonzero" d="M116 86.34c2.33.83 4 3.05 4 5.66 0 3.3-2.7 6-6 6s-6-2.7-6-6c0-2.6 1.67-4.83 4-5.66V72h4v14.34zM128 66c5.52 0 10 4.48 10 10v12h-4V76c0-3.3-2.7-6-6-6v1.83c0 .55-.45 1-1 1-.24 0-.47-.1-.65-.24l-4.46-3.87c-.46-.36-.5-1-.15-1.4.03-.05.07-.1.1-.12l4.47-3.82c.42-.35 1.05-.3 1.4.1.16.2.25.43.25.66V66zm-14 28c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/><path fill="#FC6D26" fill-rule="nonzero" d="M114 74c-3.3 0-6-2.7-6-6s2.7-6 6-6 6 2.7 6 6-2.7 6-6 6zm0-4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm22 28c-3.3 0-6-2.7-6-6s2.7-6 6-6 6 2.7 6 6-2.7 6-6 6zm0-4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2z"/><path fill="#000" fill-opacity=".03" d="M2.12 52C2.04 53 2 54 2 55c0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3C74.35 71.03 58.42 86 39 86S3.65 71.03 2.12 52z"/><path fill="#EEE" fill-rule="nonzero" d="M39 88C17.46 88 0 70.54 0 49s17.46-39 39-39 39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 14 39 14 4 29.67 4 49s15.67 35 35 35z"/><path fill="#6B4FBB" fill-rule="nonzero" d="M48 41h-4c0-2.76-2.24-5-5-5s-5 2.24-5 5h-4a9 9 0 0 1 18 0zm-18 0h4v3h-4v-3zm14 0h4v3h-4v-3z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M30 47c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h18c.55 0 1-.45 1-1V48c0-.55-.45-1-1-1H30zm0-4h18c2.76 0 5 2.24 5 5v12c0 2.76-2.24 5-5 5H30c-2.76 0-5-2.24-5-5V48c0-2.76 2.24-5 5-5z"/><path fill="#6B4FBB" d="M38 53.73c-.6-.34-1-1-1-1.73 0-1.1.9-2 2-2s2 .9 2 2c0 .74-.4 1.4-1 1.73V55c0 .55-.45 1-1 1s-1-.45-1-1v-1.27z"/><path fill="#000" fill-opacity=".03" d="M254.12 92c-.08 1-.12 2-.12 3 0 20.43 16.57 37 37 37s37-16.57 37-37c0-1-.04-2-.12-3-1.53 19.03-17.46 34-36.88 34s-35.35-14.97-36.88-34z"/><path fill="#EEE" fill-rule="nonzero" d="M291 128c-21.54 0-39-17.46-39-39s17.46-39 39-39 39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35s-15.67-35-35-35-35 15.67-35 35 15.67 35 35 35z"/><path fill="#6B4BBE" fill-rule="nonzero" d="M292 78c5.52 0 10 4.48 10 10 0 2.28-.76 4.43-2.14 6.18-1.03 1.3-.8 3.2.5 4.22 1.3 1.02 3.2.8 4.2-.5 2.22-2.8 3.44-6.26 3.44-9.9 0-8.84-7.16-16-16-16v-3.13c0-.2-.06-.4-.17-.56-.3-.42-.93-.54-1.38-.23l-9.2 6.13c-.1.06-.2.16-.28.27-.3.45-.18 1.08.28 1.38l9.2 6.13c.16.1.35.17.55.17.55 0 1-.45 1-1V78z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M290 100c-5.52 0-10-4.48-10-10 0-2.25.74-4.38 2.1-6.12 1-1.3.77-3.2-.54-4.2-1.3-1.02-3.2-.78-4.2.53A15.796 15.796 0 0 0 274 90c0 8.84 7.16 16 16 16v3.13c0 .55.45 1 1 1 .2 0 .4-.06.55-.17l9.2-6.13c.46-.3.6-.93.28-1.38-.07-.1-.17-.2-.28-.28l-9.2-6.13c-.45-.3-1.08-.2-1.38.27-.1.2-.17.4-.17.6v3.1z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76 19.575 76 3.647 61.032 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#E1DBF2" d="M30.24 27.823A14.98 14.98 0 0 0 24 40c0 2.549.636 4.949 1.757 7.051-.297-2.684.644-4.026 2.823-4.026 3.707 0 2.462 5.365 4.473 5.761 2.01.396 4.175.396 4.267 3.29.04 1.257-.265 2.157-.917 2.7a15.095 15.095 0 0 0 8.555-1.006c.035-1.91.303-4.941 2.21-5.61 2.373-.833-.55-1.431.734-3.368 1.17-1.762-3.297-5.2 0-4.832 3.477.388 5.044-.816 6.024-1.456a14.903 14.903 0 0 0-1.373-4.94c-.873.4-2.19.465-3.702-.538-.757-.502-1.084-3.944-2.107-3.944-3.823 0-4.065 3.17-5.994 3.944-1.076.431-4.193 3.773-5.614 3.596-1.126-.14-1.071-4.417-2.45-5.166-1.359-.738-2.174-1.948-2.447-3.633zM39 59c-10.493 0-19-8.507-19-19s8.507-19 19-19 19 8.507 19 19-8.507 19-19 19z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="78" height="82" viewBox="0 0 78 82"><g fill="none" fill-rule="evenodd"><path fill="#F9F9F9" d="M2.12 42c-.08.99-.12 1.99-.12 3 0 20.435 16.565 37 37 37s37-16.565 37-37c0-1.01-.04-2.01-.12-3C74.353 61.032 58.425 76 39 76S3.647 61.032 2.12 42z"/><path fill="#EEE" fill-rule="nonzero" d="M39 78C17.46 78 0 60.54 0 39S17.46 0 39 0s39 17.46 39 39-17.46 39-39 39zm0-4c19.33 0 35-15.67 35-35S58.33 4 39 4 4 19.67 4 39s15.67 35 35 35z"/><path fill="#6B4FBB" d="M33 52h12a2 2 0 1 1 0 4H33a2 2 0 1 1 0-4zm1 5h10a2 2 0 1 1 0 4H34a2 2 0 1 1 0-4z"/><path fill="#E1DBF2" fill-rule="nonzero" d="M45.542 46.932l.346-2.36a8.004 8.004 0 0 1 1.566-3.705c3.025-3.946 4.485-7.29 4.547-9.96C52.153 24.41 46.843 20 39 20c-7.777 0-13 4.374-13 11 0 2.4 1.462 5.73 4.573 9.846a8.009 8.009 0 0 1 1.536 3.683l.353 2.456 13.08-.054zm-17.038.624L28.15 45.1a3.997 3.997 0 0 0-.768-1.842C23.794 38.51 22 34.424 22 31c0-9.39 7.61-15 17-15s17.218 5.614 17 15c-.085 3.64-1.875 7.74-5.37 12.3a3.99 3.99 0 0 0-.784 1.853l-.346 2.36a4.003 4.003 0 0 1-3.942 3.42l-13.08.053a4 4 0 0 1-3.974-3.43z"/><path fill="#6B4FBB" d="M41 38.732a2 2 0 1 1 2 0V42a1 1 0 0 1-2 0v-3.268zm-6 0a2 2 0 1 1 2 0V42a1 1 0 0 1-2 0v-3.268z"/></g></svg>
\ No newline at end of file
import { truncate } from './lib/utils/text_utility';
const MAX_MESSAGE_LENGTH = 500;
const MESSAGE_CELL_SELECTOR = '.abuse-reports .message';
......@@ -15,7 +17,7 @@ export default class AbuseReports {
if (reportMessage.length > MAX_MESSAGE_LENGTH) {
$messageCellElement.data('original-message', reportMessage);
$messageCellElement.data('message-truncated', 'true');
$messageCellElement.text(window.gl.text.truncate(reportMessage, MAX_MESSAGE_LENGTH));
$messageCellElement.text(truncate(reportMessage, MAX_MESSAGE_LENGTH));
}
}
......
/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, prefer-arrow-callback, max-len */
import Clipboard from 'clipboard';
import Clipboard from 'vendor/clipboard';
function showTooltip(target, title) {
const $target = $(target);
const originalTitle = $target.data('original-title');
var genericError, genericSuccess, showTooltip;
if (!$target.data('hideTooltip')) {
$target
.attr('title', title)
.tooltip('fixTitle')
.tooltip('show')
.attr('title', originalTitle)
.tooltip('fixTitle');
}
}
genericSuccess = function(e) {
function genericSuccess(e) {
showTooltip(e.trigger, 'Copied');
// Clear the selection and blur the trigger so it loses its border
e.clearSelection();
return $(e.trigger).blur();
};
$(e.trigger).blur();
}
// Safari doesn't support `execCommand`, so instead we inform the user to
// copy manually.
//
// See http://clipboardjs.com/#browser-support
genericError = function(e) {
var key;
/**
* Safari > 10 doesn't support `execCommand`, so instead we inform the user to copy manually.
* See http://clipboardjs.com/#browser-support
*/
function genericError(e) {
let key;
if (/Mac/i.test(navigator.userAgent)) {
key = '&#8984;'; // Command
} else {
key = 'Ctrl';
}
return showTooltip(e.trigger, "Press " + key + "-C to copy");
};
showTooltip = function(target, title) {
var $target = $(target);
var originalTitle = $target.data('original-title');
if (!$target.data('hideTooltip')) {
$target
.attr('title', 'Copied')
.tooltip('fixTitle')
.tooltip('show')
.attr('title', originalTitle)
.tooltip('fixTitle');
}
};
showTooltip(e.trigger, `Press ${key}-C to copy`);
}
$(function() {
export default function initCopyToClipboard() {
const clipboard = new Clipboard('[data-clipboard-target], [data-clipboard-text]');
clipboard.on('success', genericSuccess);
clipboard.on('error', genericError);
// This a workaround around ClipboardJS limitations to allow the context-specific copy/pasting of plain text or GFM.
// The Ruby `clipboard_button` helper sneaks a JSON hash with `text` and `gfm` keys into the `data-clipboard-text`
// attribute that ClipboardJS reads from.
// When ClipboardJS creates a new `textarea` (directly inside `body`, with a `readonly` attribute`), sets its value
// to the value of this data attribute, focusses on it, and finally programmatically issues the 'Copy' command,
// this code intercepts the copy command/event at the last minute to deconstruct this JSON hash and set the
// `text/plain` and `text/x-gfm` copy data types to the intended values.
$(document).on('copy', 'body > textarea[readonly]', function(e) {
/**
* This a workaround around ClipboardJS limitations to allow the context-specific copy/pasting
* of plain text or GFM. The Ruby `clipboard_button` helper sneaks a JSON hash with `text` and
* `gfm` keys into the `data-clipboard-text` attribute that ClipboardJS reads from.
* When ClipboardJS creates a new `textarea` (directly inside `body`, with a `readonly`
* attribute`), sets its value to the value of this data attribute, focusses on it, and finally
* programmatically issues the 'Copy' command, this code intercepts the copy command/event at
* the last minute to deconstruct this JSON hash and set the `text/plain` and `text/x-gfm` copy
* data types to the intended values.
*/
$(document).on('copy', 'body > textarea[readonly]', (e) => {
const clipboardData = e.originalEvent.clipboardData;
if (!clipboardData) return;
......@@ -71,4 +70,4 @@ $(function() {
clipboardData.setData('text/plain', json.text);
clipboardData.setData('text/x-gfm', json.gfm);
});
});
}
import './autosize';
import './bind_in_out';
import initCopyAsGFM from './copy_as_gfm';
import initCopyToClipboard from './copy_to_clipboard';
import './details_behavior';
import installGlEmojiElement from './gl_emoji';
import './quick_submit';
......@@ -9,3 +10,4 @@ import './toggler_behavior';
installGlEmojiElement();
initCopyAsGFM();
initCopyToClipboard();
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, vars-on-top, no-unused-vars, no-new, max-len */
/* global EditBlob */
/* global NewCommitForm */
import NewCommitForm from '../new_commit_form';
import EditBlob from './edit_blob';
import BlobFileDropzone from '../blob/blob_file_dropzone';
......
/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren */
/* global BoardService */
import _ from 'underscore';
import Vue from 'vue';
import VueResource from 'vue-resource';
import Flash from '../flash';
import { __ } from '../locale';
import FilteredSearchBoards from './filtered_search_boards';
import eventHub from './eventhub';
import sidebarEventHub from '../sidebar/event_hub';
import './models/issue';
import './models/label';
import './models/list';
......@@ -14,7 +15,7 @@ import './models/milestone';
import './models/assignee';
import './stores/boards_store';
import './stores/modal_store';
import './services/board_service';
import BoardService from './services/board_service';
import './mixins/modal_mixins';
import './mixins/sortable_default_options';
import './filters/due_date_filters';
......@@ -77,11 +78,16 @@ $(() => {
});
Store.rootPath = this.boardsEndpoint;
// Listen for updateTokens event
eventHub.$on('updateTokens', this.updateTokens);
eventHub.$on('newDetailIssue', this.updateDetailIssue);
eventHub.$on('clearDetailIssue', this.clearDetailIssue);
sidebarEventHub.$on('toggleSubscription', this.toggleSubscription);
},
beforeDestroy() {
eventHub.$off('updateTokens', this.updateTokens);
eventHub.$off('newDetailIssue', this.updateDetailIssue);
eventHub.$off('clearDetailIssue', this.clearDetailIssue);
sidebarEventHub.$off('toggleSubscription', this.toggleSubscription);
},
mounted () {
this.filterManager = new FilteredSearchBoards(Store.filter, true);
......@@ -112,6 +118,46 @@ $(() => {
methods: {
updateTokens() {
this.filterManager.updateTokens();
},
updateDetailIssue(newIssue) {
const sidebarInfoEndpoint = newIssue.sidebarInfoEndpoint;
if (sidebarInfoEndpoint && newIssue.subscribed === undefined) {
newIssue.setFetchingState('subscriptions', true);
BoardService.getIssueInfo(sidebarInfoEndpoint)
.then(res => res.json())
.then((data) => {
newIssue.setFetchingState('subscriptions', false);
newIssue.updateData({
subscribed: data.subscribed,
});
})
.catch(() => {
newIssue.setFetchingState('subscriptions', false);
Flash(__('An error occurred while fetching sidebar data'));
});
}
Store.detail.issue = newIssue;
},
clearDetailIssue() {
Store.detail.issue = {};
},
toggleSubscription(id) {
const issue = Store.detail.issue;
if (issue.id === id && issue.toggleSubscriptionEndpoint) {
issue.setFetchingState('subscriptions', true);
BoardService.toggleIssueSubscription(issue.toggleSubscriptionEndpoint)
.then(() => {
issue.setFetchingState('subscriptions', false);
issue.updateData({
subscribed: !issue.subscribed,
});
})
.catch(() => {
issue.setFetchingState('subscriptions', false);
Flash(__('An error occurred when toggling the notification subscription'));
});
}
}
},
});
......
<script>
import './issue_card_inner';
import eventHub from '../eventhub';
const Store = gl.issueBoards.BoardsStore;
export default {
name: 'BoardsIssueCard',
template: `
<li class="card"
:class="{ 'user-can-drag': !disabled && issue.id, 'is-disabled': disabled || !issue.id, 'is-active': issueDetailVisible }"
:index="index"
:data-issue-id="issue.id"
@mousedown="mouseDown"
@mousemove="mouseMove"
@mouseup="showIssue($event)">
<issue-card-inner
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
:root-path="rootPath"
:update-filters="true" />
</li>
`,
components: {
'issue-card-inner': gl.issueBoards.IssueCardInner,
},
......@@ -56,12 +42,30 @@ export default {
this.showDetail = false;
if (Store.detail.issue && Store.detail.issue.id === this.issue.id) {
Store.detail.issue = {};
eventHub.$emit('clearDetailIssue');
} else {
Store.detail.issue = this.issue;
eventHub.$emit('newDetailIssue', this.issue);
Store.detail.list = this.list;
}
}
},
},
};
</script>
<template>
<li class="card"
:class="{ 'user-can-drag': !disabled && issue.id, 'is-disabled': disabled || !issue.id, 'is-active': issueDetailVisible }"
:index="index"
:data-issue-id="issue.id"
@mousedown="mouseDown"
@mousemove="mouseMove"
@mouseup="showIssue($event)">
<issue-card-inner
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
:root-path="rootPath"
:update-filters="true" />
</li>
</template>
/* global Sortable */
import boardNewIssue from './board_new_issue';
import boardCard from './board_card';
import boardCard from './board_card.vue';
import eventHub from '../eventhub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
......
......@@ -5,12 +5,13 @@
import Vue from 'vue';
import Flash from '../../flash';
import eventHub from '../../sidebar/event_hub';
import AssigneeTitle from '../../sidebar/components/assignees/assignee_title';
import Assignees from '../../sidebar/components/assignees/assignees';
import assigneeTitle from '../../sidebar/components/assignees/assignee_title';
import assignees from '../../sidebar/components/assignees/assignees';
import DueDateSelectors from '../../due_date_select';
import './sidebar/remove_issue';
import IssuableContext from '../../issuable_context';
import LabelsSelect from '../../labels_select';
import subscriptions from '../../sidebar/components/subscriptions/subscriptions.vue';
const Store = gl.issueBoards.BoardsStore;
......@@ -117,11 +118,11 @@ gl.issueBoards.BoardSidebar = Vue.extend({
new DueDateSelectors();
new LabelsSelect();
new Sidebar();
gl.Subscription.bindAll('.subscription');
},
components: {
assigneeTitle,
assignees,
removeBtn: gl.issueBoards.RemoveIssueBtn,
'assignee-title': AssigneeTitle,
assignees: Assignees,
subscriptions,
},
});
......@@ -3,6 +3,7 @@
import Vue from 'vue';
import Flash from '../../../flash';
import './lists_dropdown';
import { pluralize } from '../../../lib/utils/text_utility';
const ModalStore = gl.issueBoards.ModalStore;
......@@ -21,7 +22,7 @@ gl.issueBoards.ModalFooter = Vue.extend({
submitText() {
const count = ModalStore.selectedCount();
return `Add ${count > 0 ? count : ''} ${gl.text.pluralize('issue', count)}`;
return `Add ${count > 0 ? count : ''} ${pluralize('issue', count)}`;
},
},
methods: {
......
......@@ -17,6 +17,12 @@ class ListIssue {
this.assignees = [];
this.selected = false;
this.position = obj.relative_position || Infinity;
this.isFetching = {
subscriptions: true,
};
this.isLoading = {};
this.sidebarInfoEndpoint = obj.issue_sidebar_endpoint;
this.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint;
if (obj.milestone) {
this.milestone = new ListMilestone(obj.milestone);
......@@ -73,6 +79,18 @@ class ListIssue {
return gl.issueBoards.BoardsStore.state.lists.filter(list => list.findIssue(this.id));
}
updateData(newData) {
Object.assign(this, newData);
}
setFetchingState(key, value) {
this.isFetching[key] = value;
}
setLoadingState(key, value) {
this.isLoading[key] = value;
}
update (url) {
const data = {
issue: {
......
......@@ -2,7 +2,7 @@
import Vue from 'vue';
class BoardService {
export default class BoardService {
constructor ({ boardsEndpoint, listsEndpoint, bulkUpdatePath, boardId }) {
this.boards = Vue.resource(`${boardsEndpoint}{/id}.json`, {}, {
issues: {
......@@ -88,6 +88,14 @@ class BoardService {
return this.issues.bulkUpdate(data);
}
static getIssueInfo(endpoint) {
return Vue.http.get(endpoint);
}
static toggleIssueSubscription(endpoint) {
return Vue.http.post(endpoint);
}
}
window.BoardService = BoardService;
......@@ -48,6 +48,7 @@ export default class Clusters {
this.toggle = this.toggle.bind(this);
this.installApplication = this.installApplication.bind(this);
this.showToken = this.showToken.bind(this);
this.toggleButton = document.querySelector('.js-toggle-cluster');
this.toggleInput = document.querySelector('.js-toggle-input');
......@@ -56,6 +57,8 @@ export default class Clusters {
this.creatingContainer = document.querySelector('.js-cluster-creating');
this.errorReasonContainer = this.errorContainer.querySelector('.js-error-reason');
this.successApplicationContainer = document.querySelector('.js-cluster-application-notice');
this.showTokenButton = document.querySelector('.js-show-cluster-token');
this.tokenField = document.querySelector('.js-cluster-token');
initSettingsPanels();
this.initApplications();
......@@ -97,11 +100,13 @@ export default class Clusters {
addListeners() {
this.toggleButton.addEventListener('click', this.toggle);
if (this.showTokenButton) this.showTokenButton.addEventListener('click', this.showToken);
eventHub.$on('installApplication', this.installApplication);
}
removeListeners() {
this.toggleButton.removeEventListener('click', this.toggle);
if (this.showTokenButton) this.showTokenButton.removeEventListener('click', this.showToken);
eventHub.$off('installApplication', this.installApplication);
}
......@@ -145,8 +150,18 @@ export default class Clusters {
}
toggle() {
this.toggleButton.classList.toggle('checked');
this.toggleInput.setAttribute('value', this.toggleButton.classList.contains('checked').toString());
this.toggleButton.classList.toggle('is-checked');
this.toggleInput.setAttribute('value', this.toggleButton.classList.contains('is-checked').toString());
}
showToken() {
const type = this.tokenField.getAttribute('type');
if (type === 'password') {
this.tokenField.setAttribute('type', 'text');
} else {
this.tokenField.setAttribute('type', 'password');
}
}
hideAll() {
......
import Flash from '../flash';
import { s__ } from '../locale';
import ClustersService from './services/clusters_service';
/**
* Toggles loading and disabled classes.
* @param {HTMLElement} button
*/
const toggleLoadingButton = (button) => {
if (button.getAttribute('disabled')) {
button.removeAttribute('disabled');
} else {
button.setAttribute('disabled', true);
}
button.classList.toggle('is-loading');
};
/**
* Toggles checked class for the given button
* @param {HTMLElement} button
*/
const toggleValue = (button) => {
button.classList.toggle('is-checked');
};
/**
* Handles toggle buttons in the cluster's table.
*
* When the user clicks the toggle button for each cluster, it:
* - toggles the button
* - shows a loading and disables button
* - Makes a put request to the given endpoint
* Once we receive the response, either:
* 1) Show updated status in case of successfull response
* 2) Show initial status in case of failed response
*/
export default function setClusterTableToggles() {
document.querySelectorAll('.js-toggle-cluster-list')
.forEach(button => button.addEventListener('click', (e) => {
const toggleButton = e.currentTarget;
const endpoint = toggleButton.getAttribute('data-endpoint');
toggleValue(toggleButton);
toggleLoadingButton(toggleButton);
const value = toggleButton.classList.contains('is-checked');
ClustersService.updateCluster(endpoint, { cluster: { enabled: value } })
.then(() => {
toggleLoadingButton(toggleButton);
})
.catch(() => {
toggleLoadingButton(toggleButton);
toggleValue(toggleButton);
Flash(s__('ClusterIntegration|Something went wrong on our end.'));
});
}));
}
import axios from 'axios';
import setAxiosCsrfToken from '../../lib/utils/axios_utils';
import axios from '../../lib/utils/axios_utils';
export default class ClusterService {
constructor(options = {}) {
setAxiosCsrfToken();
this.options = options;
this.appInstallEndpointMap = {
helm: this.options.installHelmEndpoint,
......@@ -18,7 +15,10 @@ export default class ClusterService {
}
installApplication(appId) {
const endpoint = this.appInstallEndpointMap[appId];
return axios.post(endpoint);
return axios.post(this.appInstallEndpointMap[appId]);
}
static updateCluster(endpoint, data) {
return axios.put(endpoint, data);
}
}
This diff is collapsed.
......@@ -3,6 +3,8 @@
prefer-template, object-shorthand, prefer-arrow-callback */
/* global Pager */
import { pluralize } from './lib/utils/text_utility';
export default (function () {
const CommitsList = {};
......@@ -86,7 +88,7 @@ export default (function () {
// Update commits count in the previous commits header.
commitsCount += Number($(processedData).nextUntil('li.js-commit-header').first().find('li.commit').length);
$commitsHeadersLast.find('span.commits-count').text(`${commitsCount} ${gl.text.pluralize('commit', commitsCount)}`);
$commitsHeadersLast.find('span.commits-count').text(`${commitsCount} ${pluralize('commit', commitsCount)}`);
}
gl.utils.localTimeAgo($processedData.find('.js-timeago'));
......
......@@ -3,3 +3,4 @@ import './polyfills';
import './jquery';
import './bootstrap';
import './vue';
import '../lib/utils/axios_utils';
......@@ -10,6 +10,7 @@ import 'core-js/fn/string/from-code-point';
import 'core-js/fn/symbol';
// Browser polyfills
import 'classlist-polyfill';
import './polyfills/custom_event';
import './polyfills/element';
import './polyfills/event';
......
/* eslint-disable func-names, prefer-arrow-callback */
import Api from './api';
import { humanize } from './lib/utils/text_utility';
export default class CreateLabelDropdown {
constructor($el, namespacePath, projectPath) {
......@@ -107,7 +108,7 @@ export default class CreateLabelDropdown {
errors = label.message;
} else {
errors = Object.keys(label.message).map(key =>
`${gl.text.humanize(key)} ${label.message[key].join(', ')}`,
`${humanize(key)} ${label.message[key].join(', ')}`,
).join('<br/>');
}
......
/* eslint-disable no-param-reassign */
import { __ } from '../locale';
import '../lib/utils/text_utility';
import { dasherize } from '../lib/utils/text_utility';
import DEFAULT_EVENT_OBJECTS from './default_event_objects';
const EMPTY_STAGE_TEXTS = {
......@@ -36,7 +36,7 @@ export default {
});
newData.stages.forEach((item) => {
const stageSlug = gl.text.dasherize(item.name.toLowerCase());
const stageSlug = dasherize(item.name.toLowerCase());
item.active = false;
item.isUserAllowed = data.permissions[stageSlug];
item.emptyStageText = EMPTY_STAGE_TEXTS[stageSlug];
......
......@@ -32,7 +32,9 @@
doAction() {
this.isLoading = true;
eventHub.$emit(`${this.type}.key`, this.deployKey);
eventHub.$emit(`${this.type}.key`, this.deployKey, () => {
this.isLoading = false;
});
},
},
computed: {
......@@ -50,6 +52,9 @@
:disabled="isLoading"
@click="doAction">
{{ text }}
<loading-icon v-if="isLoading" />
<loading-icon
v-if="isLoading"
:inline="true"
/>
</button>
</template>
......@@ -47,12 +47,15 @@
.then(() => this.fetchKeys())
.catch(() => new Flash('Error enabling deploy key'));
},
disableKey(deployKey) {
disableKey(deployKey, callback) {
// eslint-disable-next-line no-alert
if (confirm('You are going to remove this deploy key. Are you sure?')) {
this.service.disableKey(deployKey.id)
.then(() => this.fetchKeys())
.then(callback)
.catch(() => new Flash('Error removing deploy key'));
} else {
callback();
}
},
},
......
......@@ -16,7 +16,8 @@ import './components/diff_note_avatars';
import './components/new_issue_for_discussion';
$(() => {
const projectPath = document.querySelector('.merge-request').dataset.projectPath;
const projectPathHolder = document.querySelector('.merge-request') || document.querySelector('.commit-box');
const projectPath = projectPathHolder.dataset.projectPath;
const COMPONENT_SELECTOR = 'resolve-btn, resolve-discussion-btn, jump-to-discussion, comment-and-resolve-btn, new-issue-for-discussion-btn';
window.gl = window.gl || {};
......
......@@ -43,7 +43,7 @@ class ResolveServiceClass {
discussion.resolveAllNotes(resolvedBy);
}
gl.mrWidget.checkStatus();
if (gl.mrWidget) gl.mrWidget.checkStatus();
discussion.updateHeadline(data);
})
.catch(() => new Flash('An error occurred when trying to resolve a discussion. Please try again.'));
......
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */
import { s__ } from './locale';
/* global ProjectSelect */
import projectSelect from './project_select';
import IssuableIndex from './issuable_index';
/* global Milestone */
import Milestone from './milestone';
import IssuableForm from './issuable_form';
import LabelsSelect from './labels_select';
/* global MilestoneSelect */
/* global NewBranchForm */
import NewBranchForm from './new_branch_form';
/* global NotificationsForm */
/* global NotificationsDropdown */
import groupAvatar from './group_avatar';
......@@ -18,21 +18,19 @@ import groupsSelect from './groups_select';
/* global Search */
/* global Admin */
import NamespaceSelect from './namespace_select';
/* global NewCommitForm */
/* global NewBranchForm */
/* global Project */
/* global ProjectAvatar */
import NewCommitForm from './new_commit_form';
import Project from './project';
import projectAvatar from './project_avatar';
/* global MergeRequest */
/* global Compare */
/* global CompareAutocomplete */
/* global ProjectFindFile */
/* global ProjectNew */
/* global ProjectShow */
/* global ProjectImport */
import ProjectNew from './project_new';
import projectImport from './project_import';
import Labels from './labels';
import LabelManager from './label_manager';
/* global Sidebar */
import IssuableTemplateSelectors from './templates/issuable_template_selectors';
import Flash from './flash';
import CommitsList from './commits';
import Issue from './issue';
......@@ -91,6 +89,8 @@ import Members from './members';
import memberExpirationDate from './member_expiration_date';
import DueDateSelectors from './due_date_select';
import Diff from './diff';
import ProjectLabelSubscription from './project_label_subscription';
import ProjectVariables from './project_variables';
(function() {
var Dispatcher;
......@@ -187,7 +187,7 @@ import Diff from './diff';
initIssuableSidebar();
break;
case 'dashboard:milestones:index':
new ProjectSelect();
projectSelect();
break;
case 'projects:milestones:show':
case 'groups:milestones:show':
......@@ -197,7 +197,7 @@ import Diff from './diff';
break;
case 'dashboard:issues':
case 'dashboard:merge_requests':
new ProjectSelect();
projectSelect();
initLegacyFilters();
break;
case 'groups:issues':
......@@ -206,7 +206,7 @@ import Diff from './diff';
const filteredSearchManager = new gl.FilteredSearchManager(page === 'groups:issues' ? 'issues' : 'merge_requests');
filteredSearchManager.setup();
}
new ProjectSelect();
projectSelect();
break;
case 'dashboard:todos:index':
new Todos();
......@@ -264,7 +264,7 @@ import Diff from './diff';
new IssuableForm($('.issue-form'));
new LabelsSelect();
new MilestoneSelect();
new gl.IssuableTemplateSelectors();
new IssuableTemplateSelectors();
break;
case 'projects:merge_requests:creations:new':
const mrNewCompareNode = document.querySelector('.js-merge-request-new-compare');
......@@ -288,7 +288,7 @@ import Diff from './diff';
new IssuableForm($('.merge-request-form'));
new LabelsSelect();
new MilestoneSelect();
new gl.IssuableTemplateSelectors();
new IssuableTemplateSelectors();
new AutoWidthDropdownSelect($('.js-target-branch-select')).init();
break;
case 'projects:tags:new':
......@@ -298,18 +298,21 @@ import Diff from './diff';
break;
case 'projects:snippets:show':
initNotes();
new ZenMode();
break;
case 'projects:snippets:new':
case 'projects:snippets:edit':
case 'projects:snippets:create':
case 'projects:snippets:update':
new GLForm($('.snippet-form'), true);
new ZenMode();
break;
case 'snippets:new':
case 'snippets:edit':
case 'snippets:create':
case 'snippets:update':
new GLForm($('.snippet-form'), false);
new ZenMode();
break;
case 'projects:releases:edit':
new ZenMode();
......@@ -317,7 +320,6 @@ import Diff from './diff';
break;
case 'projects:merge_requests:show':
new Diff();
shortcut_handler = new ShortcutsIssuable(true);
new ZenMode();
initIssuableSidebar();
......@@ -327,6 +329,8 @@ import Diff from './diff';
window.mergeRequest = new MergeRequest({
action: mrShowNode.dataset.mrAction,
});
shortcut_handler = new ShortcutsIssuable(true);
break;
case 'dashboard:activity':
new gl.Activities();
......@@ -339,7 +343,8 @@ import Diff from './diff';
container: '.js-commit-pipeline-graph',
}).bindEvents();
initNotes();
initChangesDropdown();
const stickyBarPaddingTop = 16;
initChangesDropdown(document.querySelector('.navbar-gitlab').offsetHeight - stickyBarPaddingTop);
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
break;
case 'projects:commit:pipelines':
......@@ -378,9 +383,10 @@ import Diff from './diff';
initSettingsPanels();
break;
case 'projects:imports:show':
new ProjectImport();
projectImport();
break;
case 'projects:pipelines:new':
case 'projects:pipelines:create':
new NewBranchForm($('.js-new-pipeline-form'));
break;
case 'projects:pipelines:builds':
......@@ -484,7 +490,7 @@ import Diff from './diff';
if ($el.find('.dropdown-group-label').length) {
new GroupLabelSubscription($el);
} else {
new gl.ProjectLabelSubscription($el);
new ProjectLabelSubscription($el);
}
});
break;
......@@ -520,7 +526,7 @@ import Diff from './diff';
// Initialize expandable settings panels
initSettingsPanels();
case 'groups:settings:ci_cd:show':
new gl.ProjectVariables();
new ProjectVariables();
break;
case 'ci:lints:create':
case 'ci:lints:show':
......@@ -536,6 +542,7 @@ import Diff from './diff';
new LineHighlighter();
new BlobViewer();
initNotes();
new ZenMode();
break;
case 'import:fogbugz:new_user_map':
new UsersSelect();
......@@ -548,7 +555,15 @@ import Diff from './diff';
import(/* webpackChunkName: "clusters" */ './clusters/clusters_bundle')
.then(cluster => new cluster.default()) // eslint-disable-line new-cap
.catch((err) => {
Flash(s__('ClusterIntegration|Problem setting up the cluster JavaScript'));
Flash(s__('ClusterIntegration|Problem setting up the cluster'));
throw err;
});
break;
case 'projects:clusters:index':
import(/* webpackChunkName: "clusters_index" */ './clusters/clusters_index')
.then(clusterIndex => clusterIndex.default())
.catch((err) => {
Flash(s__('ClusterIntegration|Problem setting up the clusters list'));
throw err;
});
break;
......@@ -604,7 +619,7 @@ import Diff from './diff';
break;
case 'projects':
new Project();
new ProjectAvatar();
projectAvatar();
switch (path[1]) {
case 'compare':
new CompareAutocomplete();
......@@ -623,7 +638,6 @@ import Diff from './diff';
case 'show':
new Star();
new ProjectNew();
new ProjectShow();
new NotificationsDropdown();
break;
case 'wikis':
......
......@@ -3,6 +3,7 @@ const DATA_DROPDOWN = 'data-dropdown';
const SELECTED_CLASS = 'droplab-item-selected';
const ACTIVE_CLASS = 'droplab-item-active';
const IGNORE_CLASS = 'droplab-item-ignore';
const IGNORE_HIDING_CLASS = 'droplab-item-ignore-hiding';
// Matches `{{anything}}` and `{{ everything }}`.
const TEMPLATE_REGEX = /\{\{(.+?)\}\}/g;
......@@ -13,4 +14,5 @@ export {
ACTIVE_CLASS,
TEMPLATE_REGEX,
IGNORE_CLASS,
IGNORE_HIDING_CLASS,
};
import utils from './utils';
import { SELECTED_CLASS, IGNORE_CLASS } from './constants';
import { SELECTED_CLASS, IGNORE_CLASS, IGNORE_HIDING_CLASS } from './constants';
class DropDown {
constructor(list) {
constructor(list, config = {}) {
this.currentIndex = 0;
this.hidden = true;
this.list = typeof list === 'string' ? document.querySelector(list) : list;
this.items = [];
this.eventWrapper = {};
if (config.addActiveClassToDropdownButton) {
this.dropdownToggle = this.list.parentNode.querySelector('.js-dropdown-toggle');
}
this.getItems();
this.initTemplateString();
this.addEvents();
......@@ -42,7 +45,7 @@ class DropDown {
this.addSelectedClass(selected);
e.preventDefault();
this.hide();
if (!e.target.classList.contains(IGNORE_HIDING_CLASS)) this.hide();
const listEvent = new CustomEvent('click.dl', {
detail: {
......@@ -67,7 +70,20 @@ class DropDown {
addEvents() {
this.eventWrapper.clickEvent = this.clickEvent.bind(this);
this.eventWrapper.closeDropdown = this.closeDropdown.bind(this);
this.list.addEventListener('click', this.eventWrapper.clickEvent);
this.list.addEventListener('keyup', this.eventWrapper.closeDropdown);
}
closeDropdown(event) {
// `ESC` key closes the dropdown.
if (event.keyCode === 27) {
event.preventDefault();
return this.toggle();
}
return true;
}
setData(data) {
......@@ -110,6 +126,8 @@ class DropDown {
this.list.style.display = 'block';
this.currentIndex = 0;
this.hidden = false;
if (this.dropdownToggle) this.dropdownToggle.classList.add('active');
}
hide() {
......@@ -117,6 +135,8 @@ class DropDown {
this.list.style.display = 'none';
this.currentIndex = 0;
this.hidden = true;
if (this.dropdownToggle) this.dropdownToggle.classList.remove('active');
}
toggle() {
......@@ -128,6 +148,7 @@ class DropDown {
destroy() {
this.hide();
this.list.removeEventListener('click', this.eventWrapper.clickEvent);
this.list.removeEventListener('keyup', this.eventWrapper.closeDropdown);
}
static setImagesSrc(template) {
......
......@@ -3,7 +3,7 @@ import DropDown from './drop_down';
class Hook {
constructor(trigger, list, plugins, config) {
this.trigger = trigger;
this.list = new DropDown(list);
this.list = new DropDown(list, config);
this.type = 'Hook';
this.event = 'click';
this.plugins = plugins || [];
......
......@@ -36,7 +36,10 @@ export default function dropzoneInput(form) {
$formDropzone.append(divHover);
$formDropzone.find('.div-dropzone-hover').append(iconPaperclip);
if (!uploadsPath) return;
if (!uploadsPath) {
$formDropzone.addClass('js-invalid-dropzone');
return;
}
const dropzone = $formDropzone.dropzone({
url: uploadsPath,
......
......@@ -7,6 +7,17 @@ function isFlagEmoji(emojiUnicode) {
return emojiUnicode.length === 4 && cp >= flagACodePoint && cp <= flagZCodePoint;
}
// Tested on mac OS 10.12.6 and Windows 10 FCU, it renders as two separate characters
const baseFlagCodePoint = 127987; // parseInt('1F3F3', 16)
const rainbowCodePoint = 127752; // parseInt('1F308', 16)
function isRainbowFlagEmoji(emojiUnicode) {
const characters = Array.from(emojiUnicode);
// Length 4 because flags are made of 2 characters which are surrogate pairs
return emojiUnicode.length === 4 &&
characters[0].codePointAt(0) === baseFlagCodePoint &&
characters[1].codePointAt(0) === rainbowCodePoint;
}
// Chrome <57 renders keycaps oddly
// See https://bugs.chromium.org/p/chromium/issues/detail?id=632294
// Same issue on Windows also fixed in Chrome 57, http://i.imgur.com/rQF7woO.png
......@@ -57,9 +68,11 @@ function isPersonZwjEmoji(emojiUnicode) {
// in `isEmojiUnicodeSupported` logic
function checkFlagEmojiSupport(unicodeSupportMap, emojiUnicode) {
const isFlagResult = isFlagEmoji(emojiUnicode);
const isRainbowFlagResult = isRainbowFlagEmoji(emojiUnicode);
return (
(unicodeSupportMap.flag && isFlagResult) ||
!isFlagResult
(unicodeSupportMap.rainbowFlag && isRainbowFlagResult) ||
(!isFlagResult && !isRainbowFlagResult)
);
}
......@@ -113,6 +126,7 @@ function isEmojiUnicodeSupported(unicodeSupportMap = {}, emojiUnicode, unicodeVe
export {
isEmojiUnicodeSupported as default,
isFlagEmoji,
isRainbowFlagEmoji,
isKeycapEmoji,
isSkinToneComboEmoji,
isHorceRacingSkinToneComboEmoji,
......
import AccessorUtilities from '../../lib/utils/accessor';
const GL_EMOJI_VERSION = '0.2.0';
const unicodeSupportTestMap = {
// man, student (emojione does not have any of these yet), http://emojipedia.org/emoji-zwj-sequences/
// occupationZwj: '\u{1F468}\u{200D}\u{1F393}',
......@@ -13,6 +15,7 @@ const unicodeSupportTestMap = {
horseRacing: '\u{1F3C7}\u{1F3FF}',
// US flag, http://emojipedia.org/flags/
flag: '\u{1F1FA}\u{1F1F8}',
rainbowFlag: '\u{1F3F3}\u{1F308}',
// http://emojipedia.org/modifiers/
skinToneModifier: [
// spy_tone5
......@@ -141,23 +144,31 @@ function generateUnicodeSupportMap(testMap) {
}
export default function getUnicodeSupportMap() {
let unicodeSupportMap;
let userAgentFromCache;
const isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
if (isLocalStorageAvailable) userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent');
let glEmojiVersionFromCache;
let userAgentFromCache;
if (isLocalStorageAvailable) {
glEmojiVersionFromCache = window.localStorage.getItem('gl-emoji-version');
userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent');
}
let unicodeSupportMap;
try {
unicodeSupportMap = JSON.parse(window.localStorage.getItem('gl-emoji-unicode-support-map'));
} catch (err) {
// swallow
}
if (!unicodeSupportMap || userAgentFromCache !== navigator.userAgent) {
if (
!unicodeSupportMap ||
glEmojiVersionFromCache !== GL_EMOJI_VERSION ||
userAgentFromCache !== navigator.userAgent
) {
unicodeSupportMap = generateUnicodeSupportMap(unicodeSupportTestMap);
if (isLocalStorageAvailable) {
window.localStorage.setItem('gl-emoji-version', GL_EMOJI_VERSION);
window.localStorage.setItem('gl-emoji-user-agent', navigator.userAgent);
window.localStorage.setItem('gl-emoji-unicode-support-map', JSON.stringify(unicodeSupportMap));
}
......
<script>
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tablePagination from '../../vue_shared/components/table_pagination.vue';
import environmentTable from '../components/environments_table.vue';
export default {
props: {
isLoading: {
type: Boolean,
required: true,
},
environments: {
type: Array,
required: true,
},
pagination: {
type: Object,
required: true,
},
canCreateDeployment: {
type: Boolean,
required: true,
},
canReadEnvironment: {
type: Boolean,
required: true,
},
},
components: {
environmentTable,
loadingIcon,
tablePagination,
},
methods: {
onChangePage(page) {
this.$emit('onChangePage', page);
},
},
};
</script>
<template>
<div class="environments-container">
<loading-icon
label="Loading environments"
v-if="isLoading"
size="3"
/>
<slot name="emptyState"></slot>
<div
class="table-holder"
v-if="!isLoading && environments.length > 0">
<environment-table
:environments="environments"
:can-create-deployment="canCreateDeployment"
:can-read-environment="canReadEnvironment"
/>
<table-pagination
v-if="pagination && pagination.totalPages > 1"
:change="onChangePage"
:pageInfo="pagination"
/>
</div>
</div>
</template>
<script>
export default {
name: 'environmentsEmptyState',
props: {
newPath: {
type: String,
required: true,
},
canCreateEnvironment: {
type: Boolean,
required: true,
},
helpPath: {
type: String,
required: true,
},
},
};
</script>
<template>
<div class="blank-state-row">
<div class="blank-state-center">
<h2 class="blank-state-title js-blank-state-title">
{{s__("Environments|You don't have any environments right now.")}}
</h2>
<p class="blank-state-text">
{{s__("Environments|Environments are places where code gets deployed, such as staging or production.")}}
<br />
<a :href="helpPath">
{{s__("Environments|Read more about environments")}}
</a>
</p>
<a
v-if="canCreateEnvironment"
:href="newPath"
class="btn btn-create js-new-environment-button">
{{s__("Environments|New environment")}}
</a>
</div>
</div>
</template>
<script>
import Visibility from 'visibilityjs';
import Flash from '../../flash';
import EnvironmentsService from '../services/environments_service';
import environmentTable from './environments_table.vue';
import EnvironmentsStore from '../stores/environments_store';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tablePagination from '../../vue_shared/components/table_pagination.vue';
import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils';
import eventHub from '../event_hub';
import Poll from '../../lib/utils/poll';
import environmentsMixin from '../mixins/environments_mixin';
export default {
components: {
environmentTable,
tablePagination,
loadingIcon,
},
mixins: [
environmentsMixin,
],
data() {
const environmentsData = document.querySelector('#environments-list-view').dataset;
const store = new EnvironmentsStore();
return {
store,
state: store.state,
visibility: 'available',
isLoading: false,
cssContainerClass: environmentsData.cssClass,
endpoint: environmentsData.environmentsDataEndpoint,
canCreateDeployment: environmentsData.canCreateDeployment,
canReadEnvironment: environmentsData.canReadEnvironment,
canCreateEnvironment: environmentsData.canCreateEnvironment,
projectEnvironmentsPath: environmentsData.projectEnvironmentsPath,
projectStoppedEnvironmentsPath: environmentsData.projectStoppedEnvironmentsPath,
newEnvironmentPath: environmentsData.newEnvironmentPath,
helpPagePath: environmentsData.helpPagePath,
isMakingRequest: false,
// Pagination Properties,
paginationInformation: {},
pageNumber: 1,
};
},
computed: {
scope() {
return getParameterByName('scope');
},
canReadEnvironmentParsed() {
return convertPermissionToBoolean(this.canReadEnvironment);
},
canCreateDeploymentParsed() {
return convertPermissionToBoolean(this.canCreateDeployment);
},
canCreateEnvironmentParsed() {
return convertPermissionToBoolean(this.canCreateEnvironment);
},
},
/**
* Fetches all the environments and stores them.
* Toggles loading property.
*/
created() {
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.service = new EnvironmentsService(this.endpoint);
const poll = new Poll({
resource: this.service,
method: 'get',
data: { scope, page },
successCallback: this.successCallback,
errorCallback: this.errorCallback,
notificationCallback: (isMakingRequest) => {
this.isMakingRequest = isMakingRequest;
},
});
if (!Visibility.hidden()) {
this.isLoading = true;
poll.makeRequest();
}
Visibility.change(() => {
if (!Visibility.hidden()) {
poll.restart();
} else {
poll.stop();
}
});
eventHub.$on('toggleFolder', this.toggleFolder);
eventHub.$on('postAction', this.postAction);
},
beforeDestroy() {
eventHub.$off('toggleFolder');
eventHub.$off('postAction');
},
methods: {
toggleFolder(folder) {
this.store.toggleFolder(folder);
if (!folder.isOpen) {
this.fetchChildEnvironments(folder, true);
}
},
/**
* Will change the page number and update the URL.
*
* @param {Number} pageNumber desired page to go to.
* @return {String}
*/
changePage(pageNumber) {
const param = setParamInURL('page', pageNumber);
gl.utils.visitUrl(param);
return param;
},
fetchEnvironments() {
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.isLoading = true;
return this.service.get({ scope, page })
.then(this.successCallback)
.catch(this.errorCallback);
},
fetchChildEnvironments(folder, showLoader = false) {
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', showLoader);
this.service.getFolderContent(folder.folder_path)
.then(resp => resp.json())
.then(response => this.store.setfolderContent(folder, response.environments))
.then(() => this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false))
.catch(() => {
// eslint-disable-next-line no-new
new Flash('An error occurred while fetching the environments.');
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false);
});
},
postAction(endpoint) {
if (!this.isMakingRequest) {
this.isLoading = true;
this.service.postAction(endpoint)
.then(() => this.fetchEnvironments())
.catch(() => new Flash('An error occurred while making the request.'));
}
},
successCallback(resp) {
this.saveData(resp);
// We need to verify if any folder is open to also update it
const openFolders = this.store.getOpenFolders();
if (openFolders.length) {
openFolders.forEach(folder => this.fetchChildEnvironments(folder));
}
},
errorCallback() {
this.isLoading = false;
// eslint-disable-next-line no-new
new Flash('An error occurred while fetching the environments.');
},
},
};
</script>
<template>
<div :class="cssContainerClass">
<div class="top-area">
<ul
v-if="!isLoading"
class="nav-links">
<li :class="{ active: scope === null || scope === 'available' }">
<a :href="projectEnvironmentsPath">
Available
<span class="badge js-available-environments-count">
{{state.availableCounter}}
</span>
</a>
</li>
<li :class="{ active : scope === 'stopped' }">
<a :href="projectStoppedEnvironmentsPath">
Stopped
<span class="badge js-stopped-environments-count">
{{state.stoppedCounter}}
</span>
</a>
</li>
</ul>
<div
v-if="canCreateEnvironmentParsed && !isLoading"
class="nav-controls">
<a
:href="newEnvironmentPath"
class="btn btn-create">
New environment
</a>
</div>
</div>
<div class="environments-container">
<loading-icon
label="Loading environments"
size="3"
v-if="isLoading"
/>
<div
class="blank-state blank-state-no-icon"
v-if="!isLoading && state.environments.length === 0">
<h2 class="blank-state-title js-blank-state-title">
You don't have any environments right now.
</h2>
<p class="blank-state-text">
Environments are places where code gets deployed, such as staging or production.
<br />
<a :href="helpPagePath">
Read more about environments
</a>
</p>
<a
v-if="canCreateEnvironmentParsed"
:href="newEnvironmentPath"
class="btn btn-create js-new-environment-button">
New environment
</a>
</div>
<div
class="table-holder"
v-if="!isLoading && state.environments.length > 0">
<environment-table
:environments="state.environments"
:can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"
/>
</div>
<table-pagination
v-if="state.paginationInformation && state.paginationInformation.totalPages > 1"
:change="changePage"
:pageInfo="state.paginationInformation" />
</div>
</div>
</template>
<script>
import tooltip from '../../vue_shared/directives/tooltip';
import { s__ } from '../../locale';
/**
* Renders the external url link in environments table.
......@@ -18,7 +19,7 @@ export default {
computed: {
title() {
return 'Open';
return s__('Environments|Open');
},
},
};
......
......@@ -2,7 +2,7 @@
import Timeago from 'timeago.js';
import _ from 'underscore';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import '../../lib/utils/text_utility';
import { humanize } from '../../lib/utils/text_utility';
import ActionsComponent from './environment_actions.vue';
import ExternalUrlComponent from './environment_external_url.vue';
import StopComponent from './environment_stop.vue';
......@@ -139,7 +139,7 @@ export default {
if (this.hasManualActions) {
return this.model.last_deployment.manual_actions.map((action) => {
const parsedAction = {
name: gl.text.humanize(action.name),
name: humanize(action.name),
play_path: action.play_path,
playable: action.playable,
};
......@@ -432,7 +432,7 @@ export default {
v-if="!model.isFolder"
class="table-mobile-header"
role="rowheader">
Environment
{{s__("Environments|Environment")}}
</div>
<a
v-if="!model.isFolder"
......@@ -505,7 +505,7 @@ export default {
<div
role="rowheader"
class="table-mobile-header">
Commit
{{s__("Environments|Commit")}}
</div>
<div
v-if="hasLastDeploymentKey"
......@@ -521,7 +521,7 @@ export default {
<div
v-if="!hasLastDeploymentKey"
class="commit-title table-mobile-content">
No deployments yet
{{s__("Environments|No deployments yet")}}
</div>
</div>
......@@ -531,7 +531,7 @@ export default {
<div
role="rowheader"
class="table-mobile-header">
Updated
{{s__("Environments|Updated")}}
</div>
<span
v-if="canShowDate"
......
......@@ -34,6 +34,7 @@ export default {
:aria-label="title">
<i
class="fa fa-area-chart"
aria-hidden="true" />
aria-hidden="true"
/>
</a>
</template>
......@@ -48,10 +48,10 @@ export default {
:disabled="isLoading">
<span v-if="isLastDeployment">
Re-deploy
{{s__("Environments|Re-deploy")}}
</span>
<span v-else>
Rollback
{{s__("Environments|Rollback")}}
</span>
<loading-icon v-if="isLoading" />
......
<script>
import Flash from '../../flash';
import { s__ } from '../../locale';
import emptyState from './empty_state.vue';
import eventHub from '../event_hub';
import environmentsMixin from '../mixins/environments_mixin';
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
export default {
props: {
endpoint: {
type: String,
required: true,
},
canCreateEnvironment: {
type: Boolean,
required: true,
},
canCreateDeployment: {
type: Boolean,
required: true,
},
canReadEnvironment: {
type: Boolean,
required: true,
},
cssContainerClass: {
type: String,
required: true,
},
newEnvironmentPath: {
type: String,
required: true,
},
helpPagePath: {
type: String,
required: true,
},
},
components: {
emptyState,
},
mixins: [
CIPaginationMixin,
environmentsMixin,
],
created() {
eventHub.$on('toggleFolder', this.toggleFolder);
},
beforeDestroy() {
eventHub.$off('toggleFolder');
},
methods: {
toggleFolder(folder) {
this.store.toggleFolder(folder);
if (!folder.isOpen) {
this.fetchChildEnvironments(folder, true);
}
},
fetchChildEnvironments(folder, showLoader = false) {
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', showLoader);
this.service.getFolderContent(folder.folder_path)
.then(resp => resp.json())
.then(response => this.store.setfolderContent(folder, response.environments))
.then(() => this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false))
.catch(() => {
Flash(s__('Environments|An error occurred while fetching the environments.'));
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false);
});
},
successCallback(resp) {
this.saveData(resp);
// We need to verify if any folder is open to also update it
const openFolders = this.store.getOpenFolders();
if (openFolders.length) {
openFolders.forEach(folder => this.fetchChildEnvironments(folder));
}
},
},
};
</script>
<template>
<div :class="cssContainerClass">
<div class="top-area">
<tabs
:tabs="tabs"
@onChangeTab="onChangeTab"
scope="environments"
/>
<div
v-if="canCreateEnvironment && !isLoading"
class="nav-controls">
<a
:href="newEnvironmentPath"
class="btn btn-create">
{{s__("Environments|New environment")}}
</a>
</div>
</div>
<container
:is-loading="isLoading"
:environments="state.environments"
:pagination="state.paginationInformation"
:can-create-deployment="canCreateDeployment"
:can-read-environment="canReadEnvironment"
@onChangePage="onChangePage"
>
<empty-state
slot="emptyState"
v-if="!isLoading && state.environments.length === 0"
:new-path="newEnvironmentPath"
:help-path="helpPagePath"
:can-create-environment="canCreateEnvironment"
/>
</container>
</div>
</template>
......@@ -2,12 +2,12 @@
/**
* Render environments table.
*/
import EnvironmentTableRowComponent from './environment_item.vue';
import environmentItem from './environment_item.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default {
components: {
'environment-item': EnvironmentTableRowComponent,
environmentItem,
loadingIcon,
},
......@@ -42,19 +42,19 @@ export default {
<div class="ci-table" role="grid">
<div class="gl-responsive-table-row table-row-header" role="row">
<div class="table-section section-10 environments-name" role="columnheader">
Environment
{{s__("Environments|Environment")}}
</div>
<div class="table-section section-10 environments-deploy" role="columnheader">
Deployment
{{s__("Environments|Deployment")}}
</div>
<div class="table-section section-15 environments-build" role="columnheader">
Job
{{s__("Environments|Job")}}
</div>
<div class="table-section section-25 environments-commit" role="columnheader">
Commit
{{s__("Environments|Commit")}}
</div>
<div class="table-section section-10 environments-date" role="columnheader">
Updated
{{s__("Environments|Updated")}}
</div>
</div>
<template
......@@ -86,7 +86,7 @@ export default {
<a
:href="folderUrl(model)"
class="btn btn-default">
Show all
{{s__("Environments|Show all")}}
</a>
</div>
</div>
......
import Vue from 'vue';
import EnvironmentsComponent from './components/environment.vue';
import environmentsComponent from './components/environments_app.vue';
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
import Translate from '../vue_shared/translate';
Vue.use(Translate);
document.addEventListener('DOMContentLoaded', () => new Vue({
el: '#environments-list-view',
components: {
'environments-table-app': EnvironmentsComponent,
environmentsComponent,
},
data() {
const environmentsData = document.querySelector(this.$options.el).dataset;
return {
endpoint: environmentsData.environmentsDataEndpoint,
newEnvironmentPath: environmentsData.newEnvironmentPath,
helpPagePath: environmentsData.helpPagePath,
cssContainerClass: environmentsData.cssClass,
canCreateEnvironment: convertPermissionToBoolean(environmentsData.canCreateEnvironment),
canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment),
canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment),
};
},
render(createElement) {
return createElement('environments-component', {
props: {
endpoint: this.endpoint,
newEnvironmentPath: this.newEnvironmentPath,
helpPagePath: this.helpPagePath,
cssContainerClass: this.cssContainerClass,
canCreateEnvironment: this.canCreateEnvironment,
canCreateDeployment: this.canCreateDeployment,
canReadEnvironment: this.canReadEnvironment,
},
});
},
render: createElement => createElement('environments-table-app'),
}));
import Vue from 'vue';
import EnvironmentsFolderComponent from './environments_folder_view.vue';
import environmentsFolderApp from './environments_folder_view.vue';
import { convertPermissionToBoolean } from '../../lib/utils/common_utils';
import Translate from '../../vue_shared/translate';
Vue.use(Translate);
document.addEventListener('DOMContentLoaded', () => new Vue({
el: '#environments-folder-list-view',
components: {
'environments-folder-app': EnvironmentsFolderComponent,
environmentsFolderApp,
},
data() {
const environmentsData = document.querySelector(this.$options.el).dataset;
return {
endpoint: environmentsData.endpoint,
folderName: environmentsData.folderName,
cssContainerClass: environmentsData.cssClass,
canCreateDeployment: convertPermissionToBoolean(environmentsData.canCreateDeployment),
canReadEnvironment: convertPermissionToBoolean(environmentsData.canReadEnvironment),
};
},
render(createElement) {
return createElement('environments-folder-app', {
props: {
endpoint: this.endpoint,
folderName: this.folderName,
cssContainerClass: this.cssContainerClass,
canCreateDeployment: this.canCreateDeployment,
canReadEnvironment: this.canReadEnvironment,
},
});
},
render: createElement => createElement('environments-folder-app'),
}));
<script>
import Visibility from 'visibilityjs';
import Flash from '../../flash';
import EnvironmentsService from '../services/environments_service';
import environmentTable from '../components/environments_table.vue';
import EnvironmentsStore from '../stores/environments_store';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tablePagination from '../../vue_shared/components/table_pagination.vue';
import Poll from '../../lib/utils/poll';
import eventHub from '../event_hub';
import environmentsMixin from '../mixins/environments_mixin';
import { convertPermissionToBoolean, getParameterByName, setParamInURL } from '../../lib/utils/common_utils';
export default {
components: {
environmentTable,
tablePagination,
loadingIcon,
},
mixins: [
environmentsMixin,
],
data() {
const environmentsData = document.querySelector('#environments-folder-list-view').dataset;
const store = new EnvironmentsStore();
const pathname = window.location.pathname;
const endpoint = `${pathname}.json`;
const folderName = pathname.substr(pathname.lastIndexOf('/') + 1);
return {
store,
folderName,
endpoint,
state: store.state,
visibility: 'available',
isLoading: false,
cssContainerClass: environmentsData.cssClass,
canCreateDeployment: environmentsData.canCreateDeployment,
canReadEnvironment: environmentsData.canReadEnvironment,
// Pagination Properties,
paginationInformation: {},
pageNumber: 1,
};
},
computed: {
scope() {
return getParameterByName('scope');
},
canReadEnvironmentParsed() {
return convertPermissionToBoolean(this.canReadEnvironment);
},
canCreateDeploymentParsed() {
return convertPermissionToBoolean(this.canCreateDeployment);
},
/**
* URL to link in the stopped tab.
*
* @return {String}
*/
stoppedPath() {
return `${window.location.pathname}?scope=stopped`;
},
/**
* URL to link in the available tab.
*
* @return {String}
*/
availablePath() {
return window.location.pathname;
},
},
/**
* Fetches all the environments and stores them.
* Toggles loading property.
*/
created() {
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.service = new EnvironmentsService(this.endpoint);
const poll = new Poll({
resource: this.service,
method: 'get',
data: { scope, page },
successCallback: this.successCallback,
errorCallback: this.errorCallback,
notificationCallback: (isMakingRequest) => {
this.isMakingRequest = isMakingRequest;
import environmentsMixin from '../mixins/environments_mixin';
import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';
export default {
props: {
endpoint: {
type: String,
required: true,
},
folderName: {
type: String,
required: true,
},
cssContainerClass: {
type: String,
required: true,
},
canCreateDeployment: {
type: Boolean,
required: true,
},
canReadEnvironment: {
type: Boolean,
required: true,
},
});
if (!Visibility.hidden()) {
this.isLoading = true;
poll.makeRequest();
}
Visibility.change(() => {
if (!Visibility.hidden()) {
poll.restart();
} else {
poll.stop();
}
});
eventHub.$on('postAction', this.postAction);
},
beforeDestroyed() {
eventHub.$off('postAction');
},
methods: {
/**
* Will change the page number and update the URL.
*
* @param {Number} pageNumber desired page to go to.
*/
changePage(pageNumber) {
const param = setParamInURL('page', pageNumber);
gl.utils.visitUrl(param);
return param;
},
fetchEnvironments() {
const scope = getParameterByName('scope') || this.visibility;
const page = getParameterByName('page') || this.pageNumber;
this.isLoading = true;
return this.service.get({ scope, page })
.then(this.successCallback)
.catch(this.errorCallback);
},
successCallback(resp) {
this.saveData(resp);
},
errorCallback() {
this.isLoading = false;
// eslint-disable-next-line no-new
new Flash('An error occurred while fetching the environments.');
},
postAction(endpoint) {
if (!this.isMakingRequest) {
this.isLoading = true;
this.service.postAction(endpoint)
.then(() => this.fetchEnvironments())
.catch(() => new Flash('An error occurred while making the request.'));
}
mixins: [
environmentsMixin,
CIPaginationMixin,
],
methods: {
successCallback(resp) {
this.saveData(resp);
},
},
},
};
};
</script>
<template>
<div :class="cssContainerClass">
......@@ -171,56 +43,23 @@ export default {
v-if="!isLoading">
<h4 class="js-folder-name environments-folder-name">
Environments / <b>{{folderName}}</b>
{{s__("Environments|Environments")}} / <b>{{folderName}}</b>
</h4>
<ul class="nav-links">
<li :class="{ active: scope === null || scope === 'available' }">
<a
:href="availablePath"
class="js-available-environments-folder-tab">
Available
<span class="badge js-available-environments-count">
{{state.availableCounter}}
</span>
</a>
</li>
<li :class="{ active : scope === 'stopped' }">
<a
:href="stoppedPath"
class="js-stopped-environments-folder-tab">
Stopped
<span class="badge js-stopped-environments-count">
{{state.stoppedCounter}}
</span>
</a>
</li>
</ul>
</div>
<div class="environments-container">
<loading-icon
label="Loading environments"
v-if="isLoading"
size="3"
<tabs
:tabs="tabs"
@onChangeTab="onChangeTab"
scope="environments"
/>
<div
class="table-holder"
v-if="!isLoading && state.environments.length > 0">
<environment-table
:environments="state.environments"
:can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"
/>
<table-pagination
v-if="state.paginationInformation && state.paginationInformation.totalPages > 1"
:change="changePage"
:pageInfo="state.paginationInformation"/>
</div>
</div>
<container
:is-loading="isLoading"
:environments="state.environments"
:pagination="state.paginationInformation"
:can-create-deployment="canCreateDeployment"
:can-read-environment="canReadEnvironment"
@onChangePage="onChangePage"
/>
</div>
</template>
/**
* Common code between environmets app and folder view
*/
import Visibility from 'visibilityjs';
import Poll from '../../lib/utils/poll';
import {
getParameterByName,
parseQueryStringIntoObject,
} from '../../lib/utils/common_utils';
import { s__ } from '../../locale';
import Flash from '../../flash';
import eventHub from '../event_hub';
import EnvironmentsStore from '../stores/environments_store';
import EnvironmentsService from '../services/environments_service';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tablePagination from '../../vue_shared/components/table_pagination.vue';
import environmentTable from '../components/environments_table.vue';
import tabs from '../../vue_shared/components/navigation_tabs.vue';
import container from '../components/container.vue';
export default {
components: {
environmentTable,
container,
loadingIcon,
tabs,
tablePagination,
},
data() {
const store = new EnvironmentsStore();
return {
store,
state: store.state,
isLoading: false,
isMakingRequest: false,
scope: getParameterByName('scope') || 'available',
page: getParameterByName('page') || '1',
requestData: {},
};
},
methods: {
saveData(resp) {
const headers = resp.headers;
return resp.json().then((response) => {
this.isLoading = false;
this.store.storeAvailableCount(response.available_count);
this.store.storeStoppedCount(response.stopped_count);
this.store.storeEnvironments(response.environments);
this.store.setPagination(headers);
if (_.isEqual(parseQueryStringIntoObject(resp.url.split('?')[1]), this.requestData)) {
this.store.storeAvailableCount(response.available_count);
this.store.storeStoppedCount(response.stopped_count);
this.store.storeEnvironments(response.environments);
this.store.setPagination(headers);
}
});
},
/**
* Handles URL and query parameter changes.
* When the user uses the pagination or the tabs,
* - update URL
* - Make API request to the server with new parameters
* - Update the polling function
* - Update the internal state
*/
updateContent(parameters) {
this.updateInternalState(parameters);
// fetch new data
return this.service.get(this.requestData)
.then(response => this.successCallback(response))
.then(() => {
// restart polling
this.poll.restart({ data: this.requestData });
})
.catch(() => {
this.errorCallback();
// restart polling
this.poll.restart();
});
},
errorCallback() {
this.isLoading = false;
Flash(s__('Environments|An error occurred while fetching the environments.'));
},
postAction(endpoint) {
if (!this.isMakingRequest) {
this.isLoading = true;
this.service.postAction(endpoint)
.then(() => this.fetchEnvironments())
.catch(() => {
this.isLoading = false;
Flash(s__('Environments|An error occurred while making the request.'));
});
}
},
fetchEnvironments() {
this.isLoading = true;
return this.service.get(this.requestData)
.then(this.successCallback)
.catch(this.errorCallback);
},
},
computed: {
tabs() {
return [
{
name: s__('Available'),
scope: 'available',
count: this.state.availableCounter,
isActive: this.scope === 'available',
},
{
name: s__('Stopped'),
scope: 'stopped',
count: this.state.stoppedCounter,
isActive: this.scope === 'stopped',
},
];
},
},
/**
* Fetches all the environments and stores them.
* Toggles loading property.
*/
created() {
this.service = new EnvironmentsService(this.endpoint);
this.requestData = { page: this.page, scope: this.scope };
this.poll = new Poll({
resource: this.service,
method: 'get',
data: this.requestData,
successCallback: this.successCallback,
errorCallback: this.errorCallback,
notificationCallback: (isMakingRequest) => {
this.isMakingRequest = isMakingRequest;
},
});
if (!Visibility.hidden()) {
this.isLoading = true;
this.poll.makeRequest();
} else {
this.fetchEnvironments();
}
Visibility.change(() => {
if (!Visibility.hidden()) {
this.poll.restart();
} else {
this.poll.stop();
}
});
eventHub.$on('postAction', this.postAction);
},
beforeDestroyed() {
eventHub.$off('postAction');
},
};
......@@ -36,7 +36,12 @@ export default class EnvironmentsStore {
storeEnvironments(environments = []) {
const filteredEnvironments = environments.map((env) => {
const oldEnvironmentState = this.state.environments
.find(element => element.id === env.latest.id) || {};
.find((element) => {
if (env.latest) {
return element.id === env.latest.id;
}
return element.id === env.id;
}) || {};
let filtered = {};
......
......@@ -41,7 +41,7 @@ const createFlashEl = (message, type, isInContentWrapper = false) => `
`;
const removeFlashClickListener = (flashEl, fadeTransition) => {
flashEl.parentNode.addEventListener('click', () => hideFlash(flashEl, fadeTransition));
flashEl.addEventListener('click', () => hideFlash(flashEl, fadeTransition));
};
/*
......
......@@ -287,6 +287,10 @@ class GfmAutoComplete {
}
setupLabels($input) {
const fetchData = this.fetchData.bind(this);
const LABEL_COMMAND = { LABEL: '/label', UNLABEL: '/unlabel', RELABEL: '/relabel' };
let command = '';
$input.atwho({
at: '~',
alias: 'labels',
......@@ -309,8 +313,45 @@ class GfmAutoComplete {
title: sanitize(m.title),
color: m.color,
search: m.title,
set: m.set,
}));
},
matcher(flag, subtext) {
const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers);
const subtextNodes = subtext.split(/\n+/g).pop().split(GfmAutoComplete.regexSubtext);
// Check if ~ is followed by '/label', '/relabel' or '/unlabel' commands.
command = subtextNodes.find((node) => {
if (node === LABEL_COMMAND.LABEL ||
node === LABEL_COMMAND.RELABEL ||
node === LABEL_COMMAND.UNLABEL) { return node; }
return null;
});
return match && match.length ? match[1] : null;
},
filter(query, data, searchKey) {
if (GfmAutoComplete.isLoading(data)) {
fetchData(this.$inputor, this.at);
return data;
}
if (data === GfmAutoComplete.defaultLoadingData) {
return $.fn.atwho.default.callbacks.filter(query, data, searchKey);
}
// The `LABEL_COMMAND.RELABEL` is intentionally skipped
// because we want to return all the labels (unfiltered) for that command.
if (command === LABEL_COMMAND.LABEL) {
// Return labels with set: undefined.
return data.filter(label => !label.set);
} else if (command === LABEL_COMMAND.UNLABEL) {
// Return labels with set: true.
return data.filter(label => label.set);
}
return data;
},
},
});
}
......@@ -338,27 +379,15 @@ class GfmAutoComplete {
let resultantValue = value;
if (value && !this.setting.skipSpecialCharacterTest) {
const withoutAt = value.substring(1);
if (withoutAt && /[^\w\d]/.test(withoutAt)) {
const regex = value.charAt() === '~' ? /\W|^\d+$/ : /\W/;
if (withoutAt && regex.test(withoutAt)) {
resultantValue = `${value.charAt()}"${withoutAt}"`;
}
}
return resultantValue;
},
matcher(flag, subtext) {
// The below is taken from At.js source
// Tweaked to commands to start without a space only if char before is a non-word character
// https://github.com/ichord/At.js
const atSymbolsWithBar = Object.keys(this.app.controllers).join('|');
const atSymbolsWithoutBar = Object.keys(this.app.controllers).join('');
const targetSubtext = subtext.split(/\s+/g).pop();
const resultantFlag = flag.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
const accentAChar = decodeURI('%C3%80');
const accentYChar = decodeURI('%C3%BF');
const regexp = new RegExp(`^(?:\\B|[^a-zA-Z0-9_${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`, 'gi');
const match = regexp.exec(targetSubtext);
const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers);
if (match) {
return match[1];
......@@ -419,8 +448,27 @@ class GfmAutoComplete {
return dataToInspect &&
(dataToInspect === loadingState || dataToInspect.name === loadingState);
}
static defaultMatcher(flag, subtext, controllers) {
// The below is taken from At.js source
// Tweaked to commands to start without a space only if char before is a non-word character
// https://github.com/ichord/At.js
const atSymbolsWithBar = Object.keys(controllers).join('|');
const atSymbolsWithoutBar = Object.keys(controllers).join('');
const targetSubtext = subtext.split(GfmAutoComplete.regexSubtext).pop();
const resultantFlag = flag.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
const accentAChar = decodeURI('%C3%80');
const accentYChar = decodeURI('%C3%BF');
const regexp = new RegExp(`^(?:\\B|[^a-zA-Z0-9_${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`, 'gi');
return regexp.exec(targetSubtext);
}
}
GfmAutoComplete.regexSubtext = new RegExp(/\s+/g);
GfmAutoComplete.defaultLoadingData = ['loading'];
GfmAutoComplete.atTypeMap = {
......
......@@ -331,7 +331,7 @@ GitLabDropdown = (function() {
if (_this.dropdown.find('.dropdown-toggle-page').length) {
selector = ".dropdown-page-one " + selector;
}
return $(selector);
return $(selector, this.instance.dropdown);
};
})(this),
data: (function(_this) {
......@@ -514,10 +514,11 @@ GitLabDropdown = (function() {
const dropdownToggle = this.dropdown.find('.dropdown-menu-toggle');
const hasFilterBulkUpdate = dropdownToggle.hasClass('js-filter-bulk-update');
const shouldRefreshOnOpen = dropdownToggle.hasClass('js-gl-dropdown-refresh-on-open');
const hasMultiSelect = dropdownToggle.hasClass('js-multiselect');
// Makes indeterminate items effective
if (this.fullData && hasFilterBulkUpdate) {
if (this.fullData && (shouldRefreshOnOpen || hasFilterBulkUpdate)) {
this.parseData(this.fullData);
}
......
......@@ -2,6 +2,7 @@
import GfmAutoComplete from './gfm_auto_complete';
import dropzoneInput from './dropzone_input';
import textUtils from './lib/utils/text_markdown';
export default class GLForm {
constructor(form, enableGFM = false) {
......@@ -46,7 +47,7 @@ export default class GLForm {
}
// form and textarea event listeners
this.addEventListeners();
gl.text.init(this.form);
textUtils.init(this.form);
// hide discard button
this.form.find('.js-note-discard').hide();
this.form.show();
......@@ -85,7 +86,7 @@ export default class GLForm {
clearEventListeners() {
this.textarea.off('focus');
this.textarea.off('blur');
gl.text.removeListeners(this.form);
textUtils.removeListeners(this.form);
}
addEventListeners() {
......
<script>
import tooltip from '../../vue_shared/directives/tooltip';
import identicon from '../../vue_shared/components/identicon.vue';
import eventHub from '../event_hub';
......@@ -8,6 +9,9 @@ import itemStats from './item_stats.vue';
import itemActions from './item_actions.vue';
export default {
directives: {
tooltip,
},
components: {
identicon,
itemCaret,
......@@ -112,19 +116,30 @@ export default {
</a>
</div>
<div
class="title">
class="title namespace-title">
<a
v-tooltip
:href="group.relativePath"
class="no-expand">{{group.fullName}}</a>
:title="group.fullName"
class="no-expand"
data-placement="top"
>{{
// ending bracket must be by closing tag to prevent
// link hover text-decoration from over-extending
group.name
}}</a>
<span
v-if="group.permission"
class="access-type"
class="user-access-role"
>
{{s__('GroupsTreeRole|as')}} {{group.permission}}
{{group.permission}}
</span>
</div>
<div
class="description">{{group.description}}</div>
v-if="group.description"
class="description">
{{group.description}}
</div>
</div>
<group-folder
v-if="group.isOpen && hasChildren"
......
......@@ -4,9 +4,11 @@ import tooltip from '../../vue_shared/directives/tooltip';
import PopupDialog from '../../vue_shared/components/popup_dialog.vue';
import eventHub from '../event_hub';
import { COMMON_STR } from '../constants';
import Icon from '../../vue_shared/components/icon.vue';
export default {
components: {
Icon,
PopupDialog,
},
directives: {
......@@ -63,9 +65,9 @@ export default {
:aria-label="editBtnTitle"
data-container="body"
class="edit-group btn no-expand">
<i
class="fa fa-cogs"
aria-hidden="true"/>
<icon
name="settings">
</icon>
</a>
<a
v-tooltip
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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