Merge pull request #1282 from nextcloud/dev-doc

[no-ci] Dev docs
This commit is contained in:
Andy Scherzinger 2021-05-25 10:48:01 +02:00 committed by GitHub
commit 74f6f91dc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 728 additions and 49 deletions

399
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,399 @@
# [Nextcloud](https://nextcloud.com) Talk for Android app
# Index
1. [Guidelines](#guidelines)
1. [Issue reporting](#issue-reporting)
1. [Labels](#labels)
1. [Pull request](#pull-request)
1. [Issue](#issue)
1. [Bug workflow](#bug-workflow)
1. [Contributing to Source Code](#contributing-to-source-code)
1. [Developing process](#developing-process)
1. [Branching model](#branching-model)
1. [Android Studio formatter setup](#android-studio-formatter-setup)
1. [Build variants](#build-variants)
1. [Contribution process](#contribution-process)
1. [Fork and download android repository](#fork-and-download-android-repository)
1. [Create pull request](#create-pull-request)
1. [Create another pull request](#create-another-pull-request)
1. [Backport pull request](#backport-pull-request)
1. [Adding new files](#adding-new-files)
1. [Testing](#testing)
1. [File naming](#file-naming)
1. [Menu files](#menu-files)
1. [Translations](#translations)
1. [Engineering practices](#engineering-practices)
1. [Approach to technical debt](#approach-to-technical-debt)
1. [Dependency injection](#dependency-injection)
1. [Testing](#testing)
1. [Releases](#releases)
1. [Types](#types)
1. [Stable](#stable)
1. [Release Candidate](#release-candidate)
1. [Alpha Release](#alpha-release)
1. [QA Release](#qa-release)
1. [Version Name and number](#version-name-and-number)
1. [Stable / Release candidate](#stable--release-candidate)
1. [Release cycle](#release-cycle)
1. [Release Process](#release-process)
1. [Stable Release](#stable-release)
1. [Release Candidate Release](#release-candidate-release)
1. [Alpha Release](#alpha-release)
# Guidelines
## Issue reporting
* [Report the issue](https://github.com/nextcloud/talk-android/issues/new/choose) and choose bug report or feature request. The template includes all the information we need to track down the issue.
* This repository is *only* for issues within the Nextcloud Talk Android app code. Issues in other components should be reported in their own repositories, e.g. [Nextcloud server](https://github.com/nextcloud/server/issues)
* Search the [existing issues](https://github.com/nextcloud/talk-android/issues) first, it's likely that your issue was already reported.
If your issue appears to be a bug, and hasn't been reported, open a new issue.
## Labels
### Pull request
* 2 developing
* 3 to review
### Issue
* nothing
* approved
* PR exists (and then the PR# should be shown in first post)
### Bug workflow
Every bug should be triaged in approved/needs info in a given time.
* approved: at least one other is able to reproduce it
* needs info: something unclear, or not able to reproduce
* if no response within 1 months, bug will be closed
* pr exists: if bug is fixed, link to pr
# Contributing to Source Code
Thanks for wanting to contribute source code to Nextcloud. That's great!
New contributions are added under GPL version 3+.
## Developing process
We are all about quality while not sacrificing speed so we use a very pragmatic workflow.
* create an issue with feature request
* discuss it with other developers
* create mockup if necessary
* must be approved --> label approved
* after that no conceptual changes!
* develop code
* create [pull request](https://github.com/nextcloud/talk-android/pulls)
* to assure the quality of the app, any PR gets reviewed, approved and tested before it will be merged to master
### Branching model
![branching model](/doc/branching.png "Branching Model")
* All contributions (bug fix or feature PRs) target the ```master``` branch
* Feature releases will always be based on ```master```
* Bug fix releases will always be based on their respective feature-release-bug-fix-branches
* Bug fixes relevant for the most recent _and_ released feature (e.g. ```11.0.0```) or bugfix (e.g. ```11.2.1```) release will be backported to the respective bugfix branch (e.g. ```stable-11.0``` or ```stable-11.2```)
* Hot fixes not relevant for an upcoming feature release but the latest release can target the bug fix branch directly
### Android Studio formatter setup
Our formatter setup is rather simple:
* Standard Android Studio
* Line length 120 characters (```Settings``` → ```Editor``` → ```Code Style``` → ```Right margin(columns)```: 120)
* Auto optimize imports (```Settings``` → ```Editor``` → ```Auto Import``` → ```Optimize imports on the fly```)
### Build variants
There are three build variants
* generic: no Google Stuff, used for F-Droid
* gplay: with Google Stuff (Push notification), used for Google Play Store
* qa: based on pr and available as direct download within the pr for testing purposes
### Apply a license
Nextcloud doesn't require a CLA (Contributor License Agreement).
The copyright belongs to all the individual contributors.
Therefore we recommend that every contributor adds following line to the header of a file, if they changed it substantially:
```
@copyright Copyright (c) <year>, <your name> (<your email address>)
```
For further information on how to add or update the license header correctly please have a look at [our licensing HowTo][applyalicense].
### Sign your work
We use the Developer Certificate of Origin (DCO) as a additional safeguard for the Nextcloud project.
This is a well established and widely used mechanism to assure contributors have confirmed their right to license their contribution under the project's license.
Please read [developer-certificate-of-origin][dcofile].
If you can certify it, then just add a line to every git commit message:
````
Signed-off-by: Random J Developer <random@developer.example.org>
````
Use your real name (sorry, no pseudonyms or anonymous contributions).
If you set your `user.name` and `user.email` git configs, you can sign your commit automatically with `git commit -s`.
You can also use git [aliases](https://git-scm.com/book/tr/v2/Git-Basics-Git-Aliases) like `git config --global alias.ci 'commit -s'`.
Now you can commit with `git ci` and the commit will be signed.
## Contribution process
Contribute your code targeting/based-on the branch ```master```.
It will give us a better chance to test your code before merging it with stable code.
### Fork and download android repository:
* Please follow [SETUP.md](/SETUP.md) to setup Nextcloud Talk Android app work environment.
### Create pull request:
* Commit your changes locally: ```git commit -a```
* Push your changes to your GitHub repo: ```git push```
* Browse to <https://github.com/YOURGITHUBNAME/talk-android/pulls> and issue pull request
* Enter description and send pull request.
### Create another pull request:
To make sure your new pull request does not contain commits which are already contained in previous PRs, create a new branch which is a clone of upstream/master.
* ```git fetch upstream```
* ```git checkout -b my_new_master_branch upstream/master```
* If you want to rename that branch later: ```git checkout -b my_new_master_branch_with_new_name```
* Push branch to server: ```git push -u origin name_of_local_master_branch```
* Use GitHub to issue PR
### Backport pull request:
Use backport-bot via "/backport to stable-version", e.g. "/backport to stable-11.2".
This will automatically add "backport-request" label to PR and bot will create a new PR to targeted branch once the base PR is merged.
If automatic backport fails, it will create a comment.
### Adding new files
If you create a new file it needs to contain a license header. We encourage you to use the same license (GPL3+) as we do.
Copyright of Nextcloud GmbH is optional.
Source code of app:
```java/kotlin
/*
* Nextcloud Talk application
*
* @author Your Name
* Copyright (C) 2021 Your Name
* Copyright (C) 2021 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
```
XML (layout) file:
```xml
<!--
Nextcloud Talk application
@author Your Name
Copyright (C) 2021 Your Name
Copyright (C) 2021 Nextcloud GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
```
## File naming
The file naming patterns are inspired and based on [Ribot's Android Project And Code Guidelines](https://github.com/ribot/android-guidelines/blob/c1d8c9c904eb31bf01fe24aadb963b74281fe79a/project_and_code_guidelines.md).
### Menu files
Similar to layout files, menu files should match the name of the component. For example, if we are defining a menu file that is going to be used in the `UserProfileActivity`, then the name of the file should be `activity_user_profile.xml`. Same pattern applies for menus used in adapter view items, dialogs, etc.
| Component | Class Name | Menu Name |
| ---------------- | ---------------------- | ----------------------------- |
| Activity | `UserProfileActivity` | `activity_user_profile.xml` |
| Fragment | `SignUpFragment` | `fragment_sign_up.xml` |
| Dialog | `ChangePasswordDialog` | `dialog_change_password.xml` |
| AdapterView item | --- | `item_person.xml` |
| Partial layout | --- | `partial_stats_bar.xml` |
A good practice is to not include the word `menu` as part of the name because these files are already located in the `menu` directory. In case a component uses several menus in different places (via popup menus) then the resource name would be extended. For example, if the user profile activity has two popup menus for configuring the users settings and one for the handling group assignments then the file names for the menus would be: `activity_user_profile_user_settings.xml` and `activity_user_profile_group_assignments.xml`.
## Translations
We manage translations via [Transifex](https://www.transifex.com/nextcloud/nextcloud/talk-android/). So just request joining the translation team for Android on the site and start translating. All translations will then be automatically pushed to this repository, there is no need for any pull request for translations.
When submitting PRs with changed translations, please only submit changes to values/strings.xml and not changes to translated files. These will be overwritten by the next merge of transifex-but and would increase PR review efforts.
## Engineering practices
This section contains some general guidelines for new contributors, based on common issues flagged during code review.
### Approach to technical debt
TL;DR Non-Stop Litter Picking Party!
We recognize the importance of technical debt that can slow down development, make bug fixing difficult and
discourage future contributors.
We are mindful of the [Broken Windows Theory](https://en.wikipedia.org/wiki/Broken_windows_theory) and we'd like to
actively promote and encourage contributors to apply The Scout's Rule: *"Always leave the campground cleaner than
you found it"*. Simple, little improvements will sum up and will be very appreciated by Nextcloud team.
We also promise to actively support and mentor contributors that help us to improve code quality, as we understand
that this process is challenging and requires deep understanding of the application codebase.
### Dependency injection
TL;DR Avoid calling constructors inside constructors.
In effort to modernize the codebase we are applying [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection)
whenever possible. We use 2 approaches: automatic and manual.
We are using [Dagger 2](https://dagger.dev/) to inject dependencies into major Android components only:
* `Activity`
* `Fragment`
* `Controller`
* `Service`
* `BroadcastReceiver`
* `ContentProvider`
This process is fairly automatic, with `@Inject` annotation being sufficient to supply properly initialized
objects. Android lifecycle callbacks allow us to do most of the work without effort.
For other application sub-components we prefer to use constructor injection and manually provide required dependencies.
This combination allows us to benefit from automation when it provides most value, does not tie the rest of the code
to any specific framework and stimulates continuous code modernization through iterative refactoring of all minor
elements.
### Testing
TL;DR If we can't write a test for it, it's not good.
Test automation is challenging in mobile applications in general. We try to improve in this area
and thereof we'd ask contributors to be mindful of their code testability:
1. new code submitted to Nextcloud project should be provided with automatic tests
2. contributions to existing code that is currently not covered by automatic tests
should at least not make future efforts more challenging
3. whenever possible, testability should be improved even if the code is not covered by tests
# Releases
At the moment we are releasing the app in two app stores:
* [Google Play Store](https://play.google.com/store/apps/details?id=com.nextcloud.talk2)
* [F-Droid](https://f-droid.org/en/packages/com.nextcloud.talk2/)
## Types
We do differentiate between three different kinds of releases:
### Stable
Play store and f-droid releases for the masses.
Pull Requests that have been tested and reviewed can go to master. After the last alpha release is out in the wild and no mayor errors get reported (by users or in the developer console) the master branch is ready for the stable release phase.
So when we decide to go for a new release we freeze the master feature wise and a stable branch will be created.
### Release Candidate
_stable beta_ releases done via the Beta program of the Google Play store.
Whenever a PR is reviewed/approved we put it on master.
Before releasing a new stable version there is at least one release candidate. It is based on the current stable-branch. After a beta testing phase a stable version will be released, which is identical to the latest release candidate.
### Alpha Release
_alpha_ releases done via the Alpha program of the Google Play store.
Whenever a PR is reviewed/approved we put it on master.
Alpha releases are based on latest master and and we aim to release a new alpha version on a weekly basis.
### QA Release
Done as a standalone app that can be installed in parallel to the stable app.
Any PR gets a QA build so users and reporters are able to easily test the change (feature or bugfix).
## Version Name and number
### Stable / Release candidate
For _stable_ and _release candidate_ the version name follows the [semantic versioning schema](http://semver.org/) and the version number has several digits reserved to parts of the versioning schema inspired by the [jayway version numbering](https://www.jayway.com/2015/03/11/automatic-versioncode-generation-in-android-gradle/), where:
* 2 digits for beta/alpha code as in release candidates starting at '01' (1-50=Alpha / 51-89=RC / 90-99=stable)
* 2 digits for hot fix code
* 3 digits for minor version code
* n digits for mayor version code
![Version code schema](/docs/semantic_versioning_code.png "Semantic versioning code")
Examples for different versions:
version name|version code
---|---
1.0.0|```10000099```
8.12.2|```80120290```
9.8.4-Alpha18|```90080418```
11.2.0-rc1|```110020051```
Beware that beta releases for an upcoming version will always use the minor and hotfix version of the release they are targeting. So to make sure the version code of the upcoming stable release will always be higher stable releases set the 2 beta digits to '90'-'99' as seen above in the examples. For major versions, as we're not a library and thus 'incompatible API changes' is not something that happens, decisions are essentially marketing-based. If we deem a release to be very impactful, we might increase the major version number.
## Release cycle
* major releases are linked to the corresponding [server-releases](https://apps.nextcloud.com/apps/spreed/releases) with aligned release date and version number (server version = 11 = client version)
* feature releases are planned every ~2 months, with 6 weeks of developing and 2 weeks of stabilising
* after feature freeze a public release candidate on play store and f-droid is released
* ~2 weeks testing, bug fixing
* release final version on f-droid and play store
* bugfix releases (dot releases, e.g. 3.2.1) are released 4 weeks after stable version from the branch created with first stable release (stable-3.2).
Hotfixes as well as security fixes are released via bugfix releases (dot releases) but are released on demand in contrast to regular, scheduled bugfix releases.
To get an idea which PRs and issues will be part of the next release simply check our [milestone plan](https://github.com/nextcloud/talk-android/milestones)
## Release process
### Stable Release
Stable releases are based on the git [stable-*](https://github.com/nextcloud/talk-android/branches/all?query=stable-).
1. Bump the version name and version code in the [/app/build.gradle](https://github.com/nextcloud/talk-android/blob/master/app/build.gradle), see chapter 'Version Name and number'.
2. Create a [release/tag](https://github.com/nextcloud/talk-android/releases) in git. Tag name following the naming schema: ```stable-Mayor.Minor.Hotfix``` (e.g. stable-1.2.0) naming the version number following the [semantic versioning schema](http://semver.org/)
### Release Candidate Release
Release Candidate releases are based on the git [stable-*](https://github.com/nextcloud/talk-android/branches/all?query=stable-) and are before publishing stable releases.
1. Bump the version name and version code in the [/app/build.gradle](https://github.com/nextcloud/talk-android/blob/master/app/build.gradle), see below the version name and code concept.
2. Create a [release/tag](https://github.com/nextcloud/talk-android/releases) in git. Tag name following the naming schema: ```rc-Mayor.Minor.Hotfix-betaIncrement``` (e.g. rc-1.2.0-12) naming the version number following the [semantic versioning schema](http://semver.org/)
### Alpha Release
Release Candidate releases are based on the git [master](https://github.com/nextcloud/talk-android) and are done between stable releases.
1. Bump the version name and version code in the [/app/build.gradle](https://github.com/nextcloud/talk-android/blob/master/app/build.gradle), see below the version name and code concept.
2. Create a [release/tag](https://github.com/nextcloud/talk-android/releases) in git. Tag name following the naming schema: ```rc-Mayor.Minor.Hotfix-betaIncrement``` (e.g. rc-1.2.0-12) naming the version number following the [semantic versioning schema](http://semver.org/)

View file

@ -1,12 +1,6 @@
# Nextcloud Talk for Android
# [Nextcloud](https://nextcloud.com) Talk for Android :speech_balloon:
**Video & audio calls through Nextcloud on Android**
Nextcloud Talk is a fully on-premises audio/video and chat communication service. It features web and mobile apps and is designed to offer the highest degree of security while being easy to use.
Nextcloud Talk lowers the barrier for communication and lets your team connect any time, any where, on any device, with each other, customers or partners.
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/21a6fb22279e401baba31fb296b6f20e)](https://www.codacy.com/app/Nextcloud/talk-android?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=nextcloud/talk-android&amp;utm_campaign=Badge_Grade) [![irc](https://img.shields.io/badge/IRC-%23nextcloud--mobile%20on%20freenode-blue.svg)](https://webchat.freenode.net/?channels=nextcloud-mobile)
[![Build Status](https://drone.nextcloud.com/api/badges/nextcloud/talk-android/status.svg)](https://drone.nextcloud.com/nextcloud/talk-android) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/21a6fb22279e401baba31fb296b6f20e)](https://www.codacy.com/app/Nextcloud/talk-android?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=nextcloud/talk-android&amp;utm_campaign=Badge_Grade) [![Releases](https://img.shields.io/github/release/nextcloud/talk-android.svg)](https://github.com/nextcloud/talk-android/releases/latest)
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
alt="Download from Google Play"
@ -15,40 +9,68 @@ Nextcloud Talk lowers the barrier for communication and lets your team connect a
alt="Get it on F-Droid"
height="80">](https://f-droid.org/packages/com.nextcloud.talk2/)
Please note that Notifications won't work with the f-droid version due to missing Google Play Services.
Please note that Notifications won't work with the F-Droid version due to missing Google Play Services.
**Video & audio calls through Nextcloud on Android**
Nextcloud Talk is a fully on-premises audio/video and chat communication service. It features web and mobile apps and is designed to offer the highest degree of security while being easy to use.
Nextcloud Talk lowers the barrier for communication and lets your team connect any time, any where, on any device, with each other, customers or partners.
## Why is this so awesome? :sparkles:
## Why is this so awesome?
Because it is self hosted!!! Audio/video calls and text chat typically require a central server. Some projects go commendably far in trying to ensure they can't see the data, so nobody, not government, advertising company or somebody who broke in the servers, can follow conversations. But the servers still have to mediate every call and text message, allowing them to map out who talks to who and at what time. This 'metadata' [is as useful](https://www.wired.com/2015/03/data-and-goliath-nsa-metadata-spying-your-secrets/), if not more, to track people, than the full content, especially for mass surveillance purposes. Even if the data is not stored by the chat server, the hosting provider or a hacker could simply gather the data.
By hosting your own server, all meta data stays on your server and thus under your control!
If you have suggestions or problems, please [open an issue](https://github.com/nextcloud/talk-android/issues) or contribute directly :)
## Contribution Guidelines
## How to contribute :rocket:
If you want to [contribute](https://nextcloud.com/contribute/) to Nextcloud, you are very welcome:
- on [our public Talk team conversation](https://cloud.nextcloud.com/call/c7fz9qpr)
- our forum at https://help.nextcloud.com
- for translations of the app on [Transifex](https://www.transifex.com/nextcloud/nextcloud/android-talk/)
- opening issues and PRs (including a corresponding issue)
## Contribution Guidelines :scroll:
[GPLv3](https://github.com/nextcloud/talk-android/blob/master/LICENSE.txt). All contributions to this repository are considered to be licensed under the GNU GPLv3 or any later version.
Please read the [Code of Conduct](https://nextcloud.com/community/code-of-conduct/). This document offers some guidance to ensure Nextcloud participants can cooperate effectively in a positive and inspiring atmosphere, and to explain how together we can strengthen and support each other.
For more information please review the [guidelines for contributing](https://github.com/nextcloud/talk-android/blob/master/CONTRIBUTING.md) to this repository.
Please review the [guidelines for contributing](/CONTRIBUTING.md) to this repository.
### Testing
More information how to contribute: [https://nextcloud.com/contribute/](https://nextcloud.com/contribute/)
## Start contributing :hammer_and_wrench:
Make sure you read [SETUP.md](/SETUP.md) and [CONTRIBUTING.md](/CONTRIBUTING.md) before you start working on this project.
But basically: fork this repository and contribute back using pull requests to the master branch.
Easy starting points are also reviewing [pull requests](https://github.com/nextcloud/talk-android/pulls) and working on [starter issues](https://github.com/nextcloud/talk-android/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22).
### Testing :test_tube:
So you would like to contribute by testing? Awesome, we appreciate that very much.
To report a bug for the alpha or beta version, just create an issue on github like you would for the stable version and
provide the version number. Please remember that Google Services are necessary to receive push notifications.
#### Beta versions (Release Candidates)
#### Beta versions (Release Candidates) :package:
##### via Google Play
Sign up at [Google Play Beta channel](https://play.google.com/apps/testing/com.nextcloud.talk2) to get Release
Candidates via Google Play.
Sign up at [Google Play Beta channel](https://play.google.com/apps/testing/com.nextcloud.talk2) to get Release Candidates via Google Play.
##### via github
You can also get the Release Candidates at [github releases](https://github.com/nextcloud/talk-android/releases).
#### Alpha versions
##### via Google Play
To become an alpha tester you have to be signed up for the [Google Play Beta channel](https://play.google.com/apps/testing/com.nextcloud.talk2)
and additionally you have to join the [Alpha testing Google Group](https://groups.google.com/g/nextcloud-android-talk-alpha-testing).
After that you will receive the alpha versions via the Play Store (initially, this might take some minutes after
@ -56,45 +78,17 @@ After that you will receive the alpha versions via the Play Store (initially, th
If a beta was released that is newer than the alpha version, you will get the beta in the alpha channel.
##### via Download page
In addition to google play, the alpha and beta apps can also be obtained from the Nextcloud [Download page](https://download.nextcloud.com/android/talk-alpha/)
Please make sure to remember that these versions might contain bugs and you don't use them in production.
### Apply a license
## Support :rescue_worker_helmet:
All contributions to this repository are considered to be licensed under
the GNU GPLv3 or any later version.
If you need assistance or want to ask a question about the Talk Android app, you are welcome to [ask for community help](https://help.nextcloud.com/c/support/talk/52) in our forums. If you have found a bug, feel free to [open a new issue on GitHub](https://github.com/nextcloud/talk-android/issues). Keep in mind, that this repository only manages the Nextcloud Talk for Android app. If you find bugs or have problems with the server/backend, you should ask the [Nextcloud server team](https://github.com/nextcloud/server) for help!
Contributors to the Nextcloud Talk app retain their copyright. Therefore we recommend
to add following line to the header of a file, if you changed it substantially:
## Credits :scroll:
```
@copyright Copyright (c) <year> <your name> (<your email address>)
```
For further information on how to add or update the license header correctly please have a look at [our licensing HowTo][applyalicense].
### Sign your work
We use the Developer Certificate of Origin (DCO) as a additional safeguard
for the Nextcloud project. This is a well established and widely used
mechanism to assure contributors have confirmed their right to license
their contribution under the project's license.
Please read [developer-certificate-of-origin][dcofile].
If you can certify it, then just add a line to every git commit message:
````
Signed-off-by: Random J Developer <random@developer.example.org>
````
Use your real name (sorry, no pseudonyms or anonymous contributions).
If you set your `user.name` and `user.email` git configs, you can sign your
commit automatically with `git commit -s`. You can also use git [aliases](https://git-scm.com/book/tr/v2/Git-Basics-Git-Aliases)
like `git config --global alias.ci 'commit -s'`. Now you can commit with
`git ci` and the commit will be signed.
## Credits
### Ringtones
### Ringtones :bell:
- [Ringtones by Librem](https://soundcloud.com/feandesign/sets/librem-5-sounds)
author: [feandesign](https://soundcloud.com/feandesign)
@ -103,3 +97,7 @@ like `git config --global alias.ci 'commit -s'`. Now you can commit with
[dcofile]: https://github.com/nextcloud/talk-android/blob/master/contribute/developer-certificate-of-origin
[applyalicense]: https://github.com/nextcloud/talk-android/blob/master/contribute/HowToApplyALicense.md
## Remarks :scroll:
Google Play and the Google Play logo are trademarks of Google Inc.

95
SETUP.md Normal file
View file

@ -0,0 +1,95 @@
These instructions will help you to set up your development environment, get the source code of the Nextcloud Talk for Android app and build it by yourself. If you want to help developing the app take a look to the [contribution guidelines][0].
Sections 1) and 2) are common for any environment. The rest of the sections describe how to set up a project in different tool environments. Nowadays we recommend to use Android Studio (section 2), but you can also build the app from the command line (section 3).
If you have any problem, remove the 'talk-android' folder, start again from 1) and work your way down. If something still does not work as described here, please open a new issue describing exactly what you did, what happened, and what should have happened.
### 0. Common software dependencies.
There are some tools needed, no matter what is your specific IDE or build tool of preference.
[git][1] is used to access to the different versions of the Nextcloud's source code. Download and install the version appropriate for your operating system from [here][2]. Add the full path to the 'bin/' directory from your git installation into the PATH variable of your environment so that it can be used from any location.
[Android Studio][5] is currently the official Android IDE. Due to this, we recommend it as the IDE to use in your development environment. Follow the installation instructions [here][6].
We recommend to use the last version available in the stable channel of Android Studio updates.
The Android SDK is necessary to build the app. Install it via Android Studio itself:
```Settings``` → ```Appearance & Behavior``` → ```System Settings``` → ```Android SDK```
After installing it, add the full path to the directories 'tools/' and 'platform-tools/' from your Android SDK installation into the PATH variable of your environment.
Open the Android SDK Manager under Android Studio's settings
```Settings``` → ```Appearance & Behavior``` → ```System Settings``` → ```Android SDK```
To build the Nextcloud for Android app you will need to install at least the next SDK packages:
* Android SDK Tools and Android SDK Platform-Tools (already installed); upgrade to their last versions is usually a good idea.
* Android SDK Build-Tools 30.0.3.
* Android 11 (API 29), SDK Platform; needed to build the nextcloud app.
Install any other package you consider interesting, such as emulators.
After installing it, add the full path to the directories 'tools/' and 'platform-tools/' from your Android SDK installation into the PATH variable of your environment.
### 1. Fork and download the nextcloud/talk-android repository.
You will need [git][1] to access to the different versions of the Nextcloud's source code. The source code is hosted on GitHub and may be read by anybody, without a GitHub account. You will need one if you want to contribute to the development of the app with your own code.
The next steps will assume you have a GitHub account and that you will get the code from your own fork.
* In a web browser, go to https://github.com/nextcloud/talk-android, and click the 'Fork' button near the top right corner.
* Open a terminal and go on with the next steps in it.
* Clone your forked repository: ```git clone --recursive https://github.com/YOURGITHUBNAME/talk-android.git```.
* Move to the project folder with ```cd talk-android```.
* Pull any changes from your remote branch 'master': ```git pull origin master```
* Make official Nextcloud repo known as upstream: ```git remote add upstream https://github.com/nextcloud/talk-android.git```
* Make sure to get the latest changes from official talk-android/master branch: ```git pull upstream master```
At this point you can continue using different tools to build the project. Section 2 and 3 describe the existing alternatives.
### 2. Working with Android Studio.
To set up the project in Android Studio follow the next steps:
* Open Android Studio and select 'Open an Existing Project'. Browse through your file system to the folder 'talk-android' where the project is located. The file chooser will show an Android face as the folder icon, which you can select to reopen the project.
* Android Studio will try to build the project directly after importing it. To build it manually, just click the 'Play' button in the toolbar to build and run it in a mobile device or an emulator. The resulting APK file will be saved in the 'app/build/outputs/apk/' subdirectory in the project folder and being installed/launched in a configured emulator or if connected your physical device.
* Check Android Studio editor configuration for the project: ```Settings``` → ```Editor``` → ```Code Style``` → ```Scheme: Project``` and ```Enable EditorConfig support``` (should be enabled by default)
### 3. Working in a terminal with Gradle:
[Gradle][7] is the build system used by Android Studio to manage the building operations on Android apps. You do not need to install Gradle in your system, and Google recommends not to do it, but instead trusting on the [Gradle wrapper][8] included in the project.
* Open a terminal and go to the 'talk-android' directory that contains the repository.
* Run the 'clean' and 'build' tasks using the Gradle wrapper provided
- Windows: ```gradlew.bat clean assembleGplay``` or ```gradlew.bat clean assembleGeneric```
- Mac OS/Linux: ```./gradlew clean assembleGplay``` or ```./gradlew clean assembleGeneric```
The first time the Gradle wrapper is called, the correct Gradle version will be downloaded automatically. This requires a working Internet connection.
The generated APK file is saved in app/build/outputs/apk as app-generic-debug.apk
### 4. App flavours
The app is currently equipped to be built with three flavours:
* Generic - the regular build, released as Nextcloud Android app on F-Droid
* Gplay - with Google Stuff (Push notification), used for Google Play Store
* Qa - Build per pr for testing
[0]: https://github.com/nextcloud/talk-android/blob/master/CONTRIBUTING.md
[1]: https://git-scm.com/
[2]: https://git-scm.com/downloads
[5]: https://developer.android.com/studio
[6]: https://developer.android.com/studio/install
[7]: https://gradle.org/
[8]: https://docs.gradle.org/current/userguide/gradle_wrapper.html
### 5. Troubleshooting
#### 1. Compilation fails with "java.lang.OutOfMemoryError: Java heap space" error
The default settings for Gradle is to limit the compilation to 1GB of heap.
You can increase that value by :
- adding `org.gradle.jvmargs=-Xmx4G` to `gradle.properties`
- running gradlew(.bat) with this command line : `GRADLE_OPTS="-Xmx4G" ./gradlew clean build"

BIN
docs/branching.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

187
docs/branching.svg Normal file
View file

@ -0,0 +1,187 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 242 67" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
<g transform="matrix(0.899717,0,0,1,-4.44263,-39.6807)">
<rect x="5.338" y="65.381" width="267.046" height="2.651" style="fill:rgb(160,214,244);"/>
</g>
<g transform="matrix(0.181968,0,0,0.962499,30.0407,-22.0679)">
<rect x="5.338" y="65.381" width="267.046" height="2.651" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(0.0600657,0.0600657,-0.68059,0.68059,61.7667,-18.9328)">
<rect x="5.338" y="65.381" width="267.046" height="2.651" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(0.0600657,0.0600657,-0.68059,0.68059,85.7667,-18.9328)">
<rect x="5.338" y="65.381" width="267.046" height="2.651" style="fill:rgb(160,214,244);"/>
</g>
<g transform="matrix(0.0600657,0.0600657,-0.68059,0.68059,109.767,-18.9328)">
<rect x="5.338" y="65.381" width="267.046" height="2.651" style="fill:rgb(160,214,244);"/>
</g>
<g transform="matrix(1,0,0,1,-23.9737,-32.6124)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,1,-10.0582,-17.5925)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,1,13.9418,-17.5925)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,1,37.9418,-17.5925)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(0.181968,0,0,-0.962499,127.041,74.7538)">
<rect x="5.338" y="65.381" width="267.046" height="2.651" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(0.0600657,-0.0600657,-0.68059,-0.68059,158.767,71.6187)">
<rect x="5.338" y="65.381" width="267.046" height="2.651" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(-0.0600657,-0.0600657,0.68059,-0.68059,147.649,71.6187)">
<rect x="5.338" y="65.381" width="267.046" height="2.651" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,-1,86.9418,70.2784)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,-1,110.942,70.2784)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,-1,134.942,70.2784)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(0.181968,0,0,0.962499,114.481,-10.0519)">
<rect x="5.338" y="65.381" width="267.046" height="2.651" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(0.107632,0.107632,-0.68059,0.68059,133.513,-19.1867)">
<rect x="5.338" y="65.381" width="267.046" height="2.651" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(0.107632,0.107632,-0.68059,0.68059,158.513,-19.1867)">
<rect x="5.338" y="65.381" width="267.046" height="2.651" style="fill:rgb(160,214,244);"/>
</g>
<g transform="matrix(1,0,0,1,74.3818,-5.57655)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,1,98.3818,-5.57655)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,1,122.382,-5.57655)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,1,-0.0532516,-32.2944)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,1,23.9467,-32.2944)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,1,48.1519,-32.4357)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,1,72.1519,-32.4357)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(1,0,0,1,151.152,-32.4357)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:rgb(0,130,201);"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,-7.42174,-8.88109)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,16.4631,-8.5192)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,40.4631,-8.5192)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,64.8117,-8.66395)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,88.6966,-8.66395)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,91.0127,18.1884)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,115.042,18.1884)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,139,18.1884)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,103.534,-25.6005)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,127.564,-25.5281)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,151.593,-25.5281)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,167.734,-8.73633)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,54.534,6.10125)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,30.5044,6.10125)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(0.602812,0,0,0.602812,6.5471,6.246)">
<circle cx="41.673" cy="59.748" r="3.645" style="fill:white;"/>
</g>
<g transform="matrix(1,0,0,1,-10.3498,-27.2229)">
<path d="M25.165,48.294L25.165,48.716L22.8,48.716C22.796,48.61 22.814,48.509 22.851,48.411C22.911,48.25 23.008,48.091 23.14,47.935C23.273,47.779 23.465,47.598 23.715,47.393C24.104,47.074 24.367,46.821 24.504,46.635C24.641,46.449 24.709,46.272 24.709,46.106C24.709,45.932 24.647,45.785 24.522,45.666C24.398,45.546 24.235,45.486 24.035,45.486C23.823,45.486 23.654,45.55 23.527,45.677C23.4,45.804 23.336,45.979 23.334,46.204L22.883,46.158C22.914,45.821 23.03,45.564 23.232,45.387C23.434,45.211 23.705,45.122 24.045,45.122C24.388,45.122 24.66,45.218 24.86,45.408C25.06,45.599 25.161,45.835 25.161,46.116C25.161,46.259 25.131,46.4 25.073,46.538C25.014,46.677 24.917,46.822 24.781,46.975C24.645,47.128 24.419,47.338 24.103,47.605C23.84,47.827 23.67,47.977 23.596,48.056C23.521,48.135 23.459,48.214 23.41,48.294L25.165,48.294Z" style="fill-rule:nonzero;"/>
<rect x="25.883" y="48.216" width="0.5" height="0.5" style="fill-rule:nonzero;"/>
<path d="M27.026,46.951C27.026,46.528 27.069,46.187 27.156,45.929C27.243,45.671 27.373,45.472 27.545,45.332C27.716,45.192 27.932,45.122 28.193,45.122C28.385,45.122 28.553,45.161 28.698,45.238C28.843,45.316 28.963,45.427 29.057,45.573C29.151,45.719 29.226,45.896 29.279,46.105C29.333,46.314 29.36,46.596 29.36,46.951C29.36,47.371 29.317,47.71 29.23,47.968C29.144,48.226 29.015,48.425 28.843,48.566C28.672,48.707 28.455,48.777 28.193,48.777C27.848,48.777 27.577,48.654 27.38,48.406C27.144,48.108 27.026,47.623 27.026,46.951ZM27.477,46.951C27.477,47.539 27.546,47.93 27.684,48.124C27.821,48.319 27.991,48.416 28.193,48.416C28.395,48.416 28.564,48.318 28.702,48.123C28.839,47.928 28.908,47.537 28.908,46.951C28.908,46.362 28.839,45.97 28.702,45.777C28.564,45.583 28.393,45.486 28.188,45.486C27.986,45.486 27.825,45.572 27.705,45.743C27.553,45.961 27.477,46.364 27.477,46.951Z" style="fill-rule:nonzero;"/>
<rect x="30.053" y="48.216" width="0.5" height="0.5" style="fill-rule:nonzero;"/>
<path d="M31.196,46.951C31.196,46.528 31.239,46.187 31.326,45.929C31.413,45.671 31.543,45.472 31.715,45.332C31.886,45.192 32.102,45.122 32.363,45.122C32.555,45.122 32.723,45.161 32.868,45.238C33.013,45.316 33.133,45.427 33.227,45.573C33.321,45.719 33.395,45.896 33.449,46.105C33.503,46.314 33.53,46.596 33.53,46.951C33.53,47.371 33.487,47.71 33.4,47.968C33.314,48.226 33.185,48.425 33.013,48.566C32.842,48.707 32.625,48.777 32.363,48.777C32.018,48.777 31.747,48.654 31.55,48.406C31.314,48.108 31.196,47.623 31.196,46.951ZM31.647,46.951C31.647,47.539 31.716,47.93 31.854,48.124C31.991,48.319 32.161,48.416 32.363,48.416C32.565,48.416 32.734,48.318 32.872,48.123C33.009,47.928 33.078,47.537 33.078,46.951C33.078,46.362 33.009,45.97 32.872,45.777C32.734,45.583 32.563,45.486 32.358,45.486C32.156,45.486 31.995,45.572 31.874,45.743C31.723,45.961 31.647,46.364 31.647,46.951Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,61.4632,-26.3747)">
<path d="M25.165,48.294L25.165,48.716L22.8,48.716C22.796,48.61 22.814,48.509 22.851,48.411C22.911,48.25 23.008,48.091 23.14,47.935C23.273,47.779 23.465,47.598 23.715,47.393C24.104,47.074 24.367,46.821 24.504,46.635C24.641,46.449 24.709,46.272 24.709,46.106C24.709,45.932 24.647,45.785 24.522,45.666C24.398,45.546 24.235,45.486 24.035,45.486C23.823,45.486 23.654,45.55 23.527,45.677C23.4,45.804 23.336,45.979 23.334,46.204L22.883,46.158C22.914,45.821 23.03,45.564 23.232,45.387C23.434,45.211 23.705,45.122 24.045,45.122C24.388,45.122 24.66,45.218 24.86,45.408C25.06,45.599 25.161,45.835 25.161,46.116C25.161,46.259 25.131,46.4 25.073,46.538C25.014,46.677 24.917,46.822 24.781,46.975C24.645,47.128 24.419,47.338 24.103,47.605C23.84,47.827 23.67,47.977 23.596,48.056C23.521,48.135 23.459,48.214 23.41,48.294L25.165,48.294Z" style="fill-rule:nonzero;"/>
<rect x="25.883" y="48.216" width="0.5" height="0.5" style="fill-rule:nonzero;"/>
<path d="M28.681,48.716L28.242,48.716L28.242,45.916C28.136,46.017 27.997,46.118 27.825,46.219C27.654,46.32 27.499,46.395 27.363,46.446L27.363,46.021C27.608,45.905 27.823,45.765 28.007,45.601C28.191,45.437 28.321,45.277 28.398,45.122L28.681,45.122L28.681,48.716Z" style="fill-rule:nonzero;"/>
<rect x="30.053" y="48.216" width="0.5" height="0.5" style="fill-rule:nonzero;"/>
<path d="M31.196,46.951C31.196,46.528 31.239,46.187 31.326,45.929C31.413,45.671 31.543,45.472 31.715,45.332C31.886,45.192 32.102,45.122 32.363,45.122C32.555,45.122 32.723,45.161 32.868,45.238C33.013,45.316 33.133,45.427 33.227,45.573C33.321,45.719 33.395,45.896 33.449,46.105C33.503,46.314 33.53,46.596 33.53,46.951C33.53,47.371 33.487,47.71 33.4,47.968C33.314,48.226 33.185,48.425 33.013,48.566C32.842,48.707 32.625,48.777 32.363,48.777C32.018,48.777 31.747,48.654 31.55,48.406C31.314,48.108 31.196,47.623 31.196,46.951ZM31.647,46.951C31.647,47.539 31.716,47.93 31.854,48.124C31.991,48.319 32.161,48.416 32.363,48.416C32.565,48.416 32.734,48.318 32.872,48.123C33.009,47.928 33.078,47.537 33.078,46.951C33.078,46.362 33.009,45.97 32.872,45.777C32.734,45.583 32.563,45.486 32.358,45.486C32.156,45.486 31.995,45.572 31.874,45.743C31.723,45.961 31.647,46.364 31.647,46.951Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,121.946,-44.6107)">
<path d="M23.083,48.716L23.083,46.465L22.695,46.465L22.695,46.123L23.083,46.123L23.083,45.848C23.083,45.673 23.098,45.544 23.129,45.459C23.172,45.345 23.246,45.253 23.353,45.182C23.459,45.111 23.609,45.076 23.801,45.076C23.924,45.076 24.061,45.091 24.211,45.12L24.145,45.503C24.054,45.487 23.968,45.479 23.886,45.479C23.753,45.479 23.658,45.507 23.603,45.564C23.548,45.621 23.52,45.728 23.52,45.884L23.52,46.123L24.025,46.123L24.025,46.465L23.52,46.465L23.52,48.716L23.083,48.716Z" style="fill-rule:nonzero;"/>
<path d="M26.142,47.881L26.596,47.937C26.525,48.203 26.392,48.409 26.198,48.555C26.004,48.702 25.757,48.775 25.456,48.775C25.077,48.775 24.776,48.658 24.554,48.424C24.332,48.191 24.221,47.863 24.221,47.442C24.221,47.006 24.333,46.667 24.558,46.426C24.782,46.185 25.073,46.065 25.432,46.065C25.778,46.065 26.061,46.183 26.281,46.419C26.501,46.655 26.611,46.987 26.611,47.415C26.611,47.441 26.61,47.48 26.608,47.532L24.675,47.532C24.691,47.817 24.772,48.035 24.916,48.186C25.061,48.338 25.242,48.413 25.458,48.413C25.62,48.413 25.757,48.371 25.871,48.287C25.985,48.202 26.075,48.067 26.142,47.881ZM24.699,47.171L26.147,47.171C26.127,46.953 26.072,46.789 25.981,46.68C25.841,46.511 25.659,46.426 25.436,46.426C25.235,46.426 25.065,46.494 24.927,46.629C24.79,46.764 24.714,46.945 24.699,47.171Z" style="fill-rule:nonzero;"/>
<path d="M28.84,48.396C28.677,48.535 28.52,48.632 28.37,48.689C28.219,48.746 28.058,48.775 27.885,48.775C27.6,48.775 27.381,48.705 27.228,48.566C27.075,48.427 26.999,48.249 26.999,48.033C26.999,47.906 27.028,47.79 27.086,47.685C27.143,47.58 27.219,47.496 27.313,47.432C27.406,47.369 27.512,47.321 27.629,47.288C27.715,47.265 27.845,47.243 28.019,47.222C28.374,47.18 28.636,47.129 28.803,47.071C28.805,47.01 28.806,46.972 28.806,46.956C28.806,46.777 28.764,46.651 28.681,46.578C28.569,46.478 28.402,46.429 28.181,46.429C27.974,46.429 27.821,46.465 27.723,46.537C27.624,46.61 27.552,46.738 27.504,46.922L27.075,46.863C27.114,46.679 27.178,46.531 27.268,46.418C27.357,46.305 27.486,46.217 27.656,46.156C27.825,46.095 28.021,46.065 28.244,46.065C28.465,46.065 28.645,46.091 28.784,46.143C28.922,46.195 29.024,46.261 29.089,46.339C29.154,46.418 29.199,46.518 29.226,46.639C29.24,46.713 29.247,46.849 29.247,47.044L29.247,47.63C29.247,48.038 29.257,48.297 29.276,48.405C29.294,48.513 29.331,48.617 29.387,48.716L28.928,48.716C28.882,48.625 28.853,48.518 28.84,48.396ZM28.803,47.415C28.644,47.48 28.404,47.535 28.085,47.581C27.905,47.607 27.777,47.636 27.702,47.669C27.627,47.701 27.569,47.749 27.529,47.812C27.488,47.874 27.468,47.944 27.468,48.02C27.468,48.138 27.512,48.235 27.601,48.313C27.689,48.391 27.819,48.431 27.99,48.431C28.159,48.431 28.31,48.394 28.442,48.319C28.574,48.245 28.67,48.144 28.732,48.016C28.78,47.916 28.803,47.77 28.803,47.576L28.803,47.415Z" style="fill-rule:nonzero;"/>
<path d="M30.888,48.323L30.952,48.711C30.828,48.737 30.717,48.75 30.62,48.75C30.46,48.75 30.336,48.725 30.248,48.675C30.161,48.624 30.099,48.558 30.063,48.476C30.027,48.394 30.009,48.221 30.009,47.957L30.009,46.465L29.687,46.465L29.687,46.123L30.009,46.123L30.009,45.481L30.446,45.218L30.446,46.123L30.888,46.123L30.888,46.465L30.446,46.465L30.446,47.981C30.446,48.107 30.454,48.187 30.469,48.223C30.485,48.259 30.51,48.287 30.545,48.308C30.58,48.33 30.63,48.34 30.695,48.34C30.744,48.34 30.808,48.335 30.888,48.323Z" style="fill-rule:nonzero;"/>
<path d="M33.017,48.716L33.017,48.335C32.815,48.628 32.541,48.775 32.194,48.775C32.041,48.775 31.898,48.746 31.766,48.687C31.633,48.628 31.535,48.555 31.47,48.466C31.406,48.377 31.361,48.269 31.335,48.14C31.317,48.054 31.308,47.917 31.308,47.73L31.308,46.123L31.747,46.123L31.747,47.561C31.747,47.791 31.756,47.946 31.774,48.025C31.802,48.141 31.861,48.232 31.95,48.298C32.04,48.363 32.15,48.396 32.282,48.396C32.414,48.396 32.538,48.363 32.653,48.295C32.769,48.228 32.851,48.136 32.899,48.019C32.947,47.903 32.971,47.734 32.971,47.513L32.971,46.123L33.41,46.123L33.41,48.716L33.017,48.716Z" style="fill-rule:nonzero;"/>
<path d="M34.094,48.716L34.094,46.123L34.489,46.123L34.489,46.516C34.59,46.333 34.683,46.211 34.769,46.153C34.854,46.094 34.948,46.065 35.051,46.065C35.199,46.065 35.349,46.112 35.502,46.206L35.351,46.614C35.244,46.551 35.136,46.519 35.029,46.519C34.933,46.519 34.846,46.548 34.77,46.606C34.693,46.663 34.639,46.744 34.606,46.846C34.558,47.002 34.533,47.173 34.533,47.359L34.533,48.716L34.094,48.716Z" style="fill-rule:nonzero;"/>
<path d="M37.539,47.881L37.993,47.937C37.921,48.203 37.788,48.409 37.595,48.555C37.401,48.702 37.154,48.775 36.852,48.775C36.473,48.775 36.173,48.658 35.95,48.424C35.728,48.191 35.617,47.863 35.617,47.442C35.617,47.006 35.729,46.667 35.954,46.426C36.179,46.185 36.47,46.065 36.828,46.065C37.175,46.065 37.458,46.183 37.678,46.419C37.897,46.655 38.007,46.987 38.007,47.415C38.007,47.441 38.006,47.48 38.005,47.532L36.071,47.532C36.087,47.817 36.168,48.035 36.313,48.186C36.458,48.338 36.638,48.413 36.855,48.413C37.016,48.413 37.154,48.371 37.268,48.287C37.381,48.202 37.472,48.067 37.539,47.881ZM36.096,47.171L37.543,47.171C37.524,46.953 37.469,46.789 37.377,46.68C37.237,46.511 37.056,46.426 36.833,46.426C36.631,46.426 36.461,46.494 36.324,46.629C36.186,46.764 36.11,46.945 36.096,47.171Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,106.142,-10.4205)">
<path d="M23.383,48.716L22.976,48.716L22.976,45.137L23.415,45.137L23.415,46.414C23.601,46.181 23.837,46.065 24.125,46.065C24.285,46.065 24.436,46.097 24.578,46.161C24.721,46.226 24.838,46.316 24.93,46.432C25.022,46.549 25.094,46.689 25.146,46.853C25.198,47.018 25.224,47.194 25.224,47.381C25.224,47.825 25.114,48.169 24.894,48.411C24.675,48.654 24.411,48.775 24.103,48.775C23.797,48.775 23.557,48.647 23.383,48.391L23.383,48.716ZM23.378,47.4C23.378,47.711 23.421,47.936 23.505,48.074C23.644,48.3 23.831,48.413 24.067,48.413C24.259,48.413 24.425,48.33 24.565,48.163C24.705,47.996 24.775,47.748 24.775,47.417C24.775,47.079 24.708,46.829 24.573,46.668C24.439,46.507 24.277,46.426 24.086,46.426C23.894,46.426 23.728,46.51 23.588,46.676C23.448,46.843 23.378,47.085 23.378,47.4Z" style="fill-rule:nonzero;"/>
<path d="M27.458,48.716L27.458,48.335C27.256,48.628 26.982,48.775 26.635,48.775C26.482,48.775 26.339,48.746 26.207,48.687C26.074,48.628 25.976,48.555 25.911,48.466C25.847,48.377 25.802,48.269 25.776,48.14C25.758,48.054 25.749,47.917 25.749,47.73L25.749,46.123L26.188,46.123L26.188,47.561C26.188,47.791 26.197,47.946 26.215,48.025C26.243,48.141 26.302,48.232 26.391,48.298C26.481,48.363 26.591,48.396 26.723,48.396C26.855,48.396 26.979,48.363 27.094,48.295C27.21,48.228 27.292,48.136 27.34,48.019C27.388,47.903 27.412,47.734 27.412,47.513L27.412,46.123L27.851,46.123L27.851,48.716L27.458,48.716Z" style="fill-rule:nonzero;"/>
<path d="M28.459,48.931L28.886,48.995C28.904,49.126 28.954,49.222 29.035,49.283C29.144,49.364 29.293,49.405 29.482,49.405C29.685,49.405 29.842,49.364 29.953,49.283C30.064,49.201 30.139,49.087 30.178,48.941C30.2,48.851 30.211,48.663 30.209,48.377C30.017,48.603 29.778,48.716 29.492,48.716C29.135,48.716 28.859,48.588 28.664,48.33C28.469,48.073 28.371,47.765 28.371,47.405C28.371,47.158 28.416,46.93 28.505,46.72C28.595,46.511 28.725,46.35 28.895,46.236C29.065,46.122 29.265,46.065 29.494,46.065C29.8,46.065 30.052,46.189 30.251,46.436L30.251,46.123L30.656,46.123L30.656,48.365C30.656,48.768 30.615,49.054 30.533,49.223C30.451,49.391 30.32,49.524 30.142,49.622C29.964,49.72 29.745,49.768 29.484,49.768C29.175,49.768 28.925,49.699 28.735,49.56C28.544,49.421 28.452,49.211 28.459,48.931ZM28.823,47.373C28.823,47.714 28.89,47.962 29.025,48.118C29.16,48.274 29.33,48.352 29.533,48.352C29.735,48.352 29.904,48.275 30.041,48.119C30.178,47.964 30.246,47.72 30.246,47.388C30.246,47.071 30.176,46.831 30.035,46.67C29.894,46.509 29.724,46.429 29.526,46.429C29.33,46.429 29.164,46.508 29.028,46.667C28.891,46.825 28.823,47.061 28.823,47.373Z" style="fill-rule:nonzero;"/>
<path d="M31.437,48.716L31.437,46.463L31.047,46.463L31.047,46.123L31.437,46.123L31.437,45.872C31.437,45.615 31.493,45.418 31.603,45.281C31.714,45.144 31.889,45.076 32.128,45.076C32.289,45.076 32.438,45.095 32.575,45.132L32.507,45.503C32.42,45.489 32.342,45.481 32.27,45.481C32.119,45.481 32.015,45.511 31.96,45.572C31.905,45.632 31.877,45.76 31.877,45.955L31.877,46.123L32.38,46.123L32.38,46.463L31.877,46.463L31.877,48.716L31.437,48.716ZM32.712,45.642L32.712,45.137L33.151,45.137L33.151,45.642L32.712,45.642ZM32.712,48.716L32.712,46.123L33.151,46.123L33.151,48.716L32.712,48.716Z" style="fill-rule:nonzero;"/>
<path d="M33.527,48.716L34.475,47.369L33.598,46.123L34.147,46.123L34.545,46.731C34.62,46.847 34.68,46.944 34.726,47.022C34.798,46.914 34.864,46.819 34.924,46.736L35.361,46.123L35.886,46.123L34.99,47.344L35.954,48.716L35.414,48.716L34.882,47.911L34.741,47.693L34.059,48.716L33.527,48.716Z" style="fill-rule:nonzero;"/>
<path d="M28.94,53.88L28.532,53.88L28.532,50.301L28.972,50.301L28.972,51.578C29.157,51.345 29.394,51.228 29.682,51.228C29.842,51.228 29.993,51.261 30.135,51.325C30.277,51.389 30.395,51.479 30.486,51.596C30.578,51.712 30.65,51.853 30.703,52.017C30.755,52.181 30.781,52.357 30.781,52.544C30.781,52.989 30.671,53.332 30.451,53.575C30.231,53.817 29.968,53.938 29.66,53.938C29.354,53.938 29.114,53.811 28.94,53.555L28.94,53.88ZM28.935,52.564C28.935,52.875 28.977,53.099 29.062,53.238C29.2,53.464 29.387,53.577 29.623,53.577C29.816,53.577 29.982,53.494 30.122,53.327C30.261,53.16 30.331,52.911 30.331,52.581C30.331,52.242 30.264,51.993 30.13,51.831C29.996,51.67 29.833,51.59 29.643,51.59C29.451,51.59 29.285,51.673 29.145,51.84C29.005,52.007 28.935,52.248 28.935,52.564Z" style="fill-rule:nonzero;"/>
<path d="M33.007,53.56C32.844,53.698 32.688,53.796 32.537,53.853C32.387,53.91 32.225,53.938 32.053,53.938C31.768,53.938 31.549,53.869 31.396,53.73C31.243,53.59 31.166,53.413 31.166,53.196C31.166,53.069 31.195,52.953 31.253,52.848C31.311,52.743 31.387,52.659 31.48,52.596C31.574,52.532 31.679,52.484 31.796,52.452C31.883,52.429 32.013,52.407 32.187,52.386C32.542,52.343 32.803,52.293 32.971,52.234C32.972,52.174 32.973,52.136 32.973,52.12C32.973,51.94 32.932,51.814 32.849,51.741C32.736,51.642 32.569,51.592 32.348,51.592C32.141,51.592 31.989,51.628 31.89,51.701C31.792,51.773 31.719,51.901 31.672,52.085L31.242,52.027C31.281,51.843 31.345,51.694 31.435,51.581C31.525,51.468 31.654,51.381 31.823,51.32C31.992,51.259 32.189,51.228 32.412,51.228C32.633,51.228 32.813,51.254 32.951,51.307C33.089,51.359 33.191,51.424 33.256,51.503C33.321,51.582 33.367,51.682 33.393,51.802C33.408,51.877 33.415,52.012 33.415,52.207L33.415,52.793C33.415,53.202 33.424,53.46 33.443,53.569C33.462,53.677 33.499,53.78 33.554,53.88L33.095,53.88C33.05,53.789 33.02,53.682 33.007,53.56ZM32.971,52.579C32.811,52.644 32.572,52.699 32.253,52.745C32.072,52.771 31.944,52.8 31.87,52.832C31.795,52.865 31.737,52.913 31.696,52.975C31.656,53.038 31.635,53.107 31.635,53.184C31.635,53.301 31.68,53.399 31.768,53.477C31.857,53.555 31.987,53.594 32.158,53.594C32.327,53.594 32.477,53.557 32.609,53.483C32.741,53.409 32.838,53.308 32.9,53.179C32.947,53.08 32.971,52.933 32.971,52.74L32.971,52.579Z" style="fill-rule:nonzero;"/>
<path d="M35.788,52.93L36.22,52.986C36.173,53.284 36.052,53.517 35.858,53.686C35.663,53.854 35.424,53.938 35.141,53.938C34.786,53.938 34.501,53.822 34.285,53.59C34.07,53.359 33.962,53.026 33.962,52.593C33.962,52.313 34.008,52.068 34.101,51.858C34.194,51.648 34.335,51.491 34.525,51.386C34.714,51.281 34.92,51.228 35.143,51.228C35.425,51.228 35.655,51.3 35.834,51.442C36.013,51.584 36.128,51.787 36.179,52.049L35.751,52.115C35.711,51.94 35.639,51.809 35.535,51.722C35.432,51.634 35.307,51.59 35.161,51.59C34.939,51.59 34.759,51.669 34.621,51.828C34.483,51.986 34.414,52.238 34.414,52.581C34.414,52.929 34.48,53.182 34.614,53.34C34.747,53.498 34.921,53.577 35.136,53.577C35.309,53.577 35.453,53.524 35.568,53.418C35.684,53.313 35.757,53.15 35.788,52.93Z" style="fill-rule:nonzero;"/>
<path d="M36.599,53.88L36.599,50.301L37.038,50.301L37.038,52.342L38.078,51.287L38.647,51.287L37.656,52.249L38.747,53.88L38.205,53.88L37.348,52.554L37.038,52.852L37.038,53.88L36.599,53.88Z" style="fill-rule:nonzero;"/>
<path d="M39.096,54.873L39.096,51.287L39.497,51.287L39.497,51.624C39.591,51.492 39.698,51.393 39.816,51.327C39.935,51.261 40.079,51.228 40.248,51.228C40.47,51.228 40.665,51.285 40.834,51.399C41.004,51.513 41.131,51.674 41.218,51.881C41.304,52.089 41.347,52.316 41.347,52.564C41.347,52.829 41.299,53.068 41.204,53.28C41.109,53.493 40.971,53.656 40.789,53.769C40.608,53.882 40.417,53.938 40.217,53.938C40.07,53.938 39.939,53.907 39.822,53.846C39.706,53.784 39.61,53.706 39.536,53.611L39.536,54.873L39.096,54.873ZM39.494,52.598C39.494,52.932 39.562,53.178 39.697,53.338C39.832,53.497 39.995,53.577 40.187,53.577C40.383,53.577 40.55,53.494 40.689,53.329C40.828,53.164 40.898,52.908 40.898,52.561C40.898,52.231 40.83,51.984 40.694,51.819C40.558,51.655 40.396,51.573 40.207,51.573C40.02,51.573 39.854,51.66 39.71,51.835C39.566,52.01 39.494,52.264 39.494,52.598Z" style="fill-rule:nonzero;"/>
<path d="M41.713,52.583C41.713,52.103 41.847,51.748 42.114,51.516C42.337,51.324 42.608,51.228 42.929,51.228C43.286,51.228 43.577,51.345 43.803,51.579C44.029,51.812 44.143,52.135 44.143,52.547C44.143,52.88 44.092,53.143 43.992,53.334C43.892,53.525 43.747,53.674 43.555,53.78C43.364,53.885 43.155,53.938 42.929,53.938C42.566,53.938 42.273,53.822 42.049,53.589C41.825,53.357 41.713,53.021 41.713,52.583ZM42.165,52.583C42.165,52.915 42.237,53.164 42.382,53.329C42.527,53.494 42.709,53.577 42.929,53.577C43.147,53.577 43.329,53.494 43.474,53.328C43.618,53.162 43.691,52.909 43.691,52.569C43.691,52.248 43.618,52.005 43.472,51.84C43.327,51.675 43.146,51.592 42.929,51.592C42.709,51.592 42.527,51.674 42.382,51.839C42.237,52.003 42.165,52.251 42.165,52.583Z" style="fill-rule:nonzero;"/>
<path d="M44.653,53.88L44.653,51.287L45.048,51.287L45.048,51.68C45.149,51.496 45.242,51.375 45.328,51.316C45.413,51.258 45.507,51.228 45.61,51.228C45.758,51.228 45.908,51.276 46.061,51.37L45.91,51.778C45.803,51.714 45.695,51.683 45.588,51.683C45.492,51.683 45.406,51.711 45.329,51.769C45.253,51.827 45.198,51.907 45.165,52.01C45.117,52.166 45.092,52.337 45.092,52.522L45.092,53.88L44.653,53.88Z" style="fill-rule:nonzero;"/>
<path d="M47.282,53.487L47.346,53.875C47.222,53.901 47.111,53.914 47.014,53.914C46.854,53.914 46.73,53.889 46.643,53.838C46.555,53.788 46.493,53.721 46.457,53.639C46.421,53.557 46.403,53.384 46.403,53.121L46.403,51.629L46.081,51.629L46.081,51.287L46.403,51.287L46.403,50.645L46.84,50.381L46.84,51.287L47.282,51.287L47.282,51.629L46.84,51.629L46.84,53.145C46.84,53.27 46.848,53.351 46.863,53.387C46.879,53.422 46.904,53.451 46.939,53.472C46.974,53.493 47.024,53.504 47.089,53.504C47.138,53.504 47.202,53.498 47.282,53.487Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,200.844,-23.8867)">
<path d="M24.929,48.716L24.929,46.123L25.322,46.123L25.322,46.487C25.403,46.36 25.511,46.258 25.646,46.181C25.782,46.103 25.935,46.065 26.108,46.065C26.3,46.065 26.457,46.105 26.58,46.184C26.703,46.264 26.79,46.376 26.84,46.519C27.045,46.216 27.312,46.065 27.641,46.065C27.898,46.065 28.096,46.136 28.234,46.278C28.373,46.421 28.442,46.64 28.442,46.936L28.442,48.716L28.005,48.716L28.005,47.083C28.005,46.907 27.991,46.781 27.962,46.703C27.934,46.626 27.882,46.564 27.807,46.516C27.732,46.469 27.644,46.446 27.543,46.446C27.361,46.446 27.21,46.506 27.089,46.628C26.969,46.749 26.909,46.943 26.909,47.21L26.909,48.716L26.469,48.716L26.469,47.032C26.469,46.836 26.433,46.69 26.362,46.592C26.29,46.495 26.173,46.446 26.01,46.446C25.886,46.446 25.772,46.478 25.667,46.543C25.562,46.608 25.486,46.704 25.439,46.829C25.392,46.954 25.368,47.135 25.368,47.371L25.368,48.716L24.929,48.716Z" style="fill-rule:nonzero;"/>
<path d="M30.786,48.396C30.623,48.535 30.466,48.632 30.316,48.689C30.165,48.746 30.004,48.775 29.831,48.775C29.546,48.775 29.327,48.705 29.174,48.566C29.021,48.427 28.945,48.249 28.945,48.033C28.945,47.906 28.974,47.79 29.031,47.685C29.089,47.58 29.165,47.496 29.258,47.432C29.352,47.369 29.457,47.321 29.575,47.288C29.661,47.265 29.791,47.243 29.965,47.222C30.32,47.18 30.581,47.129 30.749,47.071C30.751,47.01 30.751,46.972 30.751,46.956C30.751,46.777 30.71,46.651 30.627,46.578C30.515,46.478 30.348,46.429 30.126,46.429C29.92,46.429 29.767,46.465 29.669,46.537C29.57,46.61 29.497,46.738 29.45,46.922L29.02,46.863C29.059,46.679 29.124,46.531 29.213,46.418C29.303,46.305 29.432,46.217 29.601,46.156C29.771,46.095 29.967,46.065 30.19,46.065C30.411,46.065 30.591,46.091 30.729,46.143C30.868,46.195 30.969,46.261 31.035,46.339C31.1,46.418 31.145,46.518 31.171,46.639C31.186,46.713 31.193,46.849 31.193,47.044L31.193,47.63C31.193,48.038 31.203,48.297 31.221,48.405C31.24,48.513 31.277,48.617 31.332,48.716L30.873,48.716C30.828,48.625 30.799,48.518 30.786,48.396ZM30.749,47.415C30.589,47.48 30.35,47.535 30.031,47.581C29.851,47.607 29.723,47.636 29.648,47.669C29.573,47.701 29.515,47.749 29.475,47.812C29.434,47.874 29.414,47.944 29.414,48.02C29.414,48.138 29.458,48.235 29.547,48.313C29.635,48.391 29.765,48.431 29.936,48.431C30.105,48.431 30.256,48.394 30.388,48.319C30.519,48.245 30.616,48.144 30.678,48.016C30.725,47.916 30.749,47.77 30.749,47.576L30.749,47.415Z" style="fill-rule:nonzero;"/>
<path d="M31.699,47.942L32.133,47.874C32.158,48.048 32.226,48.182 32.337,48.274C32.449,48.367 32.604,48.413 32.805,48.413C33.006,48.413 33.156,48.372 33.254,48.29C33.351,48.208 33.4,48.112 33.4,48.001C33.4,47.902 33.357,47.823 33.271,47.766C33.211,47.727 33.061,47.678 32.822,47.618C32.499,47.536 32.276,47.466 32.152,47.406C32.027,47.347 31.933,47.265 31.868,47.16C31.804,47.055 31.772,46.939 31.772,46.812C31.772,46.696 31.798,46.589 31.851,46.491C31.904,46.392 31.976,46.311 32.067,46.246C32.136,46.195 32.229,46.152 32.347,46.117C32.465,46.082 32.591,46.065 32.726,46.065C32.93,46.065 33.109,46.094 33.262,46.153C33.416,46.211 33.53,46.291 33.603,46.391C33.676,46.491 33.727,46.625 33.754,46.792L33.325,46.851C33.305,46.718 33.249,46.613 33.155,46.538C33.061,46.464 32.929,46.426 32.758,46.426C32.556,46.426 32.412,46.46 32.326,46.526C32.24,46.593 32.197,46.671 32.197,46.761C32.197,46.818 32.215,46.869 32.25,46.914C32.286,46.962 32.342,47.001 32.419,47.032C32.463,47.048 32.592,47.085 32.807,47.144C33.118,47.227 33.335,47.295 33.458,47.348C33.581,47.401 33.677,47.478 33.747,47.579C33.817,47.679 33.852,47.805 33.852,47.954C33.852,48.101 33.809,48.239 33.724,48.368C33.638,48.498 33.515,48.598 33.354,48.669C33.193,48.739 33.011,48.775 32.807,48.775C32.47,48.775 32.213,48.705 32.037,48.565C31.86,48.425 31.747,48.217 31.699,47.942Z" style="fill-rule:nonzero;"/>
<path d="M35.334,48.323L35.397,48.711C35.274,48.737 35.163,48.75 35.065,48.75C34.906,48.75 34.782,48.725 34.694,48.675C34.606,48.624 34.545,48.558 34.509,48.476C34.473,48.394 34.455,48.221 34.455,47.957L34.455,46.465L34.133,46.465L34.133,46.123L34.455,46.123L34.455,45.481L34.892,45.218L34.892,46.123L35.334,46.123L35.334,46.465L34.892,46.465L34.892,47.981C34.892,48.107 34.9,48.187 34.915,48.223C34.931,48.259 34.956,48.287 34.991,48.308C35.026,48.33 35.076,48.34 35.141,48.34C35.19,48.34 35.254,48.335 35.334,48.323Z" style="fill-rule:nonzero;"/>
<path d="M37.539,47.881L37.993,47.937C37.921,48.203 37.788,48.409 37.595,48.555C37.401,48.702 37.154,48.775 36.852,48.775C36.473,48.775 36.173,48.658 35.95,48.424C35.728,48.191 35.617,47.863 35.617,47.442C35.617,47.006 35.729,46.667 35.954,46.426C36.179,46.185 36.47,46.065 36.828,46.065C37.175,46.065 37.458,46.183 37.678,46.419C37.897,46.655 38.007,46.987 38.007,47.415C38.007,47.441 38.006,47.48 38.005,47.532L36.071,47.532C36.087,47.817 36.168,48.035 36.313,48.186C36.458,48.338 36.638,48.413 36.855,48.413C37.016,48.413 37.154,48.371 37.268,48.287C37.381,48.202 37.472,48.067 37.539,47.881ZM36.096,47.171L37.543,47.171C37.524,46.953 37.469,46.789 37.377,46.68C37.237,46.511 37.056,46.426 36.833,46.426C36.631,46.426 36.461,46.494 36.324,46.629C36.186,46.764 36.11,46.945 36.096,47.171Z" style="fill-rule:nonzero;"/>
<path d="M38.539,48.716L38.539,46.123L38.935,46.123L38.935,46.516C39.036,46.333 39.129,46.211 39.215,46.153C39.3,46.094 39.394,46.065 39.497,46.065C39.645,46.065 39.795,46.112 39.948,46.206L39.797,46.614C39.689,46.551 39.582,46.519 39.475,46.519C39.379,46.519 39.292,46.548 39.216,46.606C39.139,46.663 39.085,46.744 39.052,46.846C39.003,47.002 38.979,47.173 38.979,47.359L38.979,48.716L38.539,48.716Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,27.6507,3.16152)">
<path d="M25.165,48.294L25.165,48.716L22.8,48.716C22.796,48.61 22.814,48.509 22.851,48.411C22.911,48.25 23.008,48.091 23.14,47.935C23.273,47.779 23.465,47.598 23.715,47.393C24.104,47.074 24.367,46.821 24.504,46.635C24.641,46.449 24.709,46.272 24.709,46.106C24.709,45.932 24.647,45.785 24.522,45.666C24.398,45.546 24.235,45.486 24.035,45.486C23.823,45.486 23.654,45.55 23.527,45.677C23.4,45.804 23.336,45.979 23.334,46.204L22.883,46.158C22.914,45.821 23.03,45.564 23.232,45.387C23.434,45.211 23.705,45.122 24.045,45.122C24.388,45.122 24.66,45.218 24.86,45.408C25.06,45.599 25.161,45.835 25.161,46.116C25.161,46.259 25.131,46.4 25.073,46.538C25.014,46.677 24.917,46.822 24.781,46.975C24.645,47.128 24.419,47.338 24.103,47.605C23.84,47.827 23.67,47.977 23.596,48.056C23.521,48.135 23.459,48.214 23.41,48.294L25.165,48.294Z" style="fill-rule:nonzero;"/>
<rect x="25.883" y="48.216" width="0.5" height="0.5" style="fill-rule:nonzero;"/>
<path d="M27.026,46.951C27.026,46.528 27.069,46.187 27.156,45.929C27.243,45.671 27.373,45.472 27.545,45.332C27.716,45.192 27.932,45.122 28.193,45.122C28.385,45.122 28.553,45.161 28.698,45.238C28.843,45.316 28.963,45.427 29.057,45.573C29.151,45.719 29.226,45.896 29.279,46.105C29.333,46.314 29.36,46.596 29.36,46.951C29.36,47.371 29.317,47.71 29.23,47.968C29.144,48.226 29.015,48.425 28.843,48.566C28.672,48.707 28.455,48.777 28.193,48.777C27.848,48.777 27.577,48.654 27.38,48.406C27.144,48.108 27.026,47.623 27.026,46.951ZM27.477,46.951C27.477,47.539 27.546,47.93 27.684,48.124C27.821,48.319 27.991,48.416 28.193,48.416C28.395,48.416 28.564,48.318 28.702,48.123C28.839,47.928 28.908,47.537 28.908,46.951C28.908,46.362 28.839,45.97 28.702,45.777C28.564,45.583 28.393,45.486 28.188,45.486C27.986,45.486 27.825,45.572 27.705,45.743C27.553,45.961 27.477,46.364 27.477,46.951Z" style="fill-rule:nonzero;"/>
<rect x="30.053" y="48.216" width="0.5" height="0.5" style="fill-rule:nonzero;"/>
<path d="M31.025,48.716L31.972,47.369L31.096,46.123L31.645,46.123L32.043,46.731C32.118,46.847 32.178,46.944 32.224,47.022C32.295,46.914 32.361,46.819 32.421,46.736L32.858,46.123L33.383,46.123L32.487,47.344L33.452,48.716L32.912,48.716L32.38,47.911L32.238,47.693L31.557,48.716L31.025,48.716Z" style="fill-rule:nonzero;"/>
</g>
<g transform="matrix(1,0,0,1,112.469,15.3188)">
<path d="M25.165,48.294L25.165,48.716L22.8,48.716C22.796,48.61 22.814,48.509 22.851,48.411C22.911,48.25 23.008,48.091 23.14,47.935C23.273,47.779 23.465,47.598 23.715,47.393C24.104,47.074 24.367,46.821 24.504,46.635C24.641,46.449 24.709,46.272 24.709,46.106C24.709,45.932 24.647,45.785 24.522,45.666C24.398,45.546 24.235,45.486 24.035,45.486C23.823,45.486 23.654,45.55 23.527,45.677C23.4,45.804 23.336,45.979 23.334,46.204L22.883,46.158C22.914,45.821 23.03,45.564 23.232,45.387C23.434,45.211 23.705,45.122 24.045,45.122C24.388,45.122 24.66,45.218 24.86,45.408C25.06,45.599 25.161,45.835 25.161,46.116C25.161,46.259 25.131,46.4 25.073,46.538C25.014,46.677 24.917,46.822 24.781,46.975C24.645,47.128 24.419,47.338 24.103,47.605C23.84,47.827 23.67,47.977 23.596,48.056C23.521,48.135 23.459,48.214 23.41,48.294L25.165,48.294Z" style="fill-rule:nonzero;"/>
<rect x="25.883" y="48.216" width="0.5" height="0.5" style="fill-rule:nonzero;"/>
<path d="M28.681,48.716L28.242,48.716L28.242,45.916C28.136,46.017 27.997,46.118 27.825,46.219C27.654,46.32 27.499,46.395 27.363,46.446L27.363,46.021C27.608,45.905 27.823,45.765 28.007,45.601C28.191,45.437 28.321,45.277 28.398,45.122L28.681,45.122L28.681,48.716Z" style="fill-rule:nonzero;"/>
<rect x="30.053" y="48.216" width="0.5" height="0.5" style="fill-rule:nonzero;"/>
<path d="M31.025,48.716L31.972,47.369L31.096,46.123L31.645,46.123L32.043,46.731C32.118,46.847 32.178,46.944 32.224,47.022C32.295,46.914 32.361,46.819 32.421,46.736L32.858,46.123L33.383,46.123L32.487,47.344L33.452,48.716L32.912,48.716L32.38,47.911L32.238,47.693L31.557,48.716L31.025,48.716Z" style="fill-rule:nonzero;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB