diff --git a/.editorconfig b/.editorconfig index f44e7c16737..52065f8fe26 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,3 +10,6 @@ insert_final_newline = true indent_style = space indent_size = 4 trim_trailing_whitespace = true + +[{*.json,*.yml}] +indent_size = 2 diff --git a/.env.example b/.env.example index 7dfca241e34..0ed277fe832 100644 --- a/.env.example +++ b/.env.example @@ -1,10 +1,13 @@ APP_ENV=production APP_DEBUG=false APP_URL=http://localhost -APP_KEY=SomeRandomString +APP_TIMEZONE=UTC +APP_KEY= +DEBUGBAR_ENABLED=false DB_DRIVER=mysql DB_HOST=localhost +DB_UNIX_SOCKET=null DB_DATABASE=cachet DB_USERNAME=homestead DB_PASSWORD=secret @@ -14,11 +17,14 @@ DB_PREFIX=null CACHE_DRIVER=file SESSION_DRIVER=file QUEUE_DRIVER=sync + +CACHET_BEACON=true CACHET_EMOJI=false +CACHET_AUTO_TWITTER=true -MAIL_DRIVER=smtp -MAIL_HOST=mailtrap.io -MAIL_PORT=2525 +MAIL_DRIVER=log +MAIL_HOST=null +MAIL_PORT=null MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ADDRESS=null @@ -30,3 +36,9 @@ REDIS_DATABASE=null REDIS_PORT=null GITHUB_TOKEN=null + +NEXMO_KEY=null +NEXMO_SECRET=null +NEXMO_SMS_FROM=Cachet + +TRUSTED_PROXIES= diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..98caa82825c --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at james@alt-three.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000000..ccf9365d7aa --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,94 @@ +# Contribution Guidelines + +## Thank you + +Firstly, thank you for taking an interest in Cachet and for reading this guide. + +## Creating issues + +We track feature requests and bug reports on the [issue tracker](https://github.com/cachethq/Cachet/issues). Please send support requests to our support email; [support@alt-three.com](mailto:support@alt-three.com?subject=Cachet%20Support). + +**Always be respectful.** Organisation members reserve the right to lock topics if they feel necessary. + +## Languages + +This project accepts **English translations** only. Translations will be updated automatically through the [CrowdIn](https://translate.cachethq.io) integration. + +Please submit alternative translations to the [Cachet CrowdIn](https://translate.cachethq.io) project. CrowdIn will automatically send a Pull Request with your updates in. + +## Coding Standards + +Please try to follow existing coding standards. [StyleCI](https://styleci.io) will analyse and fix any discrepancies in coding standards. + +## Introduction into Git and GitHub + +If you are new to Git, GitHub and the whole open source software community, welcome! Here are some resources for getting started and understanding what it's all about. + +- [Try Git](https://try.github.io/levels/1/challenges/1) by Code School +- [GitHub Help](https://help.github.com) + +If you're not fond of the command line, you can get one of GitHub's free GUI desktop apps: + +- [GitHub for Mac](https://github.com/blog/1510-installing-git-from-github-for-mac) +- [GitHub for Windows](https://github.com/blog/1127-github-for-windows) + +If you're feeling adventurous, you can become a Git & GitHub master with the [Git Path on Code School](https://www.codeschool.com/paths/git). + +## .editorconfig + +You should also make use of the [.editorconfig](/.editorconfig) file found within the root of the repository. It'll make sure that your editor is setup with the same file settings. + +## Ways to help: + +Start by becoming familiar with Cachet. If you're already using Cachet, that's a great head start. If not, check out the latest [demo](https://dev.cachethq.io) and have a play. You can also download and install Cachet locally to familiarise yourself that way. + +You don't have to be a developer to help improve Cachet, infact there are lots of ways that you can help us. + +### Spread the word + +There are a lot of people who don't know about Cachet or what a status page is and how important it can be. [Tweet about Cachet](https://twitter.com/CachetHQ). Write blog posts about your success (or failures, we're not perfect) with Cachet and share what you took away from it. + +### Help with Documentation + +Cachet is in use around the world. Cachet speaks multiple languages. Our documentation doesn't and can be hard to understand for non-English speaking people. Documentation should be easy to understand and we need your help to make this possible. Check out [CachetHQ/Docs](https://github.com/CachetHQ/Docs) to contribute to our documentation. + +### As a non-developer/non-designer + +We're always looking for new [translations](#translations). + +Of course bug reports, feature requests and [documentation](https://docs.cachethq.io) are always appreciated. + +### As a designer + +As Cachet gains new features, the design and ideas that were once a perfect fit need updating and in some cases designing from scratch. This is where you come in! Fancy giving Cachet a lick of paint? Sweet! + +You'll need to install Node.js with NPM or Yarn. + +To get started you can do the following: + +1. Install Node.js and our dev dependencies. +2. Run `npm run dev` +3. Make your changes to the SCSS files in `./resources/assets/sass/` + +If you're making a lot of changes, you'll find that running `npm run watch` will make life easier for you! + +When you're happy with your changes, please run `npm run prod` to minify the assets. + +### As a developer + +Built using [Laravel](https://laravel.com). + +We use these extra dependencies to develop Cachet: + +- Node.js +- NPM or Yarn +- Composer +- Git + +Once cloned to your local machine, you'll need some demo data! Run `php artisan cachet:seed` to get the demo installation ready for action. + +### #YOLO JUST SUBMIT A PR + +_A great idea taken from https://github.com/metabase/metabase/blob/master/docs/contributing.md#yolo-just-submit-a-pr._ + +> If you come up with something really cool, and want to share it with us, just submit a PR. If it hasn't gone through the above process, we probably won't merge it as is, but if it's compelling, we're more than willing to help you via code review, design review and generally OCD nitpicking so that it fits into the rest of our codebase. diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000000..cb0cea613ce --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,5 @@ +# These are supported funding model platforms + +github: + - jbrooksuk + - cachethq diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE deleted file mode 100644 index 40c97cf9bd8..00000000000 --- a/.github/ISSUE_TEMPLATE +++ /dev/null @@ -1,20 +0,0 @@ -Before submitting your issue, please make sure that you've checked the checkboxes below. - -- [ ] I am running the [latest release](https://github.com/CachetHQ/Cachet/releases/latest) version of Cachet. -- [ ] I am running at least PHP 5.5.9. *You can check this by running `php -v`.* -- [ ] I have ran `rm -rf bootstrap/cache/*`. - -### Expected behaviour - -*Please describe what you're expecting to see happen.* - -### Actual behaviour - -*Please describe what you're actually seeing happen.* - -### Steps to reproduce - -*If your issue requires any specific steps to reproduce, please outline them here.* - -1. First step -2. Second step diff --git a/.gitignore b/.gitignore index 51669198bab..96cbe1660fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,12 @@ +/node_modules +/public/hot +/public/storage +/storage/*.key +/vendor +/.idea +/.vagrant +Homestead.json +Homestead.yaml +npm-debug.log .env -node_modules -phpunit.xml -vendor +package-lock.json diff --git a/.travis.yml b/.travis.yml index cf51d22d5c7..8d0b77fd695 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,38 @@ language: php +dist: trusty +sudo: false -php: - - 5.5.9 - - 5.5 - - 5.6 - - 7.0 - - hhvm +branches: + except: + - l10n_2.3 + - l10n_2.4 -sudo: false +before_install: + - cp .env.example .env -install: travis_retry composer install --no-interaction --no-scripts --prefer-source +install: + - travis_retry composer install --no-interaction --no-suggest -script: vendor/bin/phpunit +jobs: + include: +# - stage: Security check +# script: +# - phpenv config-rm xdebug.ini || true +# - wget https://get.sensiolabs.org/security-checker.phar +# - php security-checker.phar security:check ./composer.lock +# php: 7.1 + - stage: Unit tests + script: + - phpenv config-rm xdebug.ini || true + - vendor/bin/phpunit + php: 7.1 + - stage: Unit tests + script: + - phpenv config-rm xdebug.ini || true + - vendor/bin/phpunit + php: 7.2 + - stage: Unit tests + script: + - phpenv config-rm xdebug.ini || true + - vendor/bin/phpunit + php: 7.3 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 452151f214e..00000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,76 +0,0 @@ -# Contribution Guidelines - -## Creating issues - -Feature requests and bug reports should be made by using the [issue tracker](https://github.com/cachethq/Cachet/issues). Support questions should be directed to our support email; [support@alt-three.com](mailto:support@alt-three.com?subject=Cachet Support). - -**Always be respectful.** Organization members reserve the right to lock topics if they feel necessary. - -## Languages - -Any non-English translations must be made on the [Cachet CrowdIn](https://translate.cachethq.io) project. This makes syncing translations much easier. - -## Coding Standards - -Please follow existing coding standards: - -```php - + + + Cachet Logo + +

-[![StyleCI](https://styleci.io/repos/26730195/shield)](https://styleci.io/repos/26730195/) -[![Build Status](https://img.shields.io/travis/CachetHQ/Cachet/master.svg?style=flat-square)](https://travis-ci.org/CachetHQ/Cachet) -[![Software License](https://img.shields.io/badge/license-BSD3-brightgreen.svg?style=flat-square)](LICENSE) -[![Crowdin](https://d322cqt584bo4o.cloudfront.net/cachet/localized.svg)](http://translate.cachethq.io/project/cachet) -[![Packagist](https://img.shields.io/packagist/v/cachethq/cachet.svg?style=flat-square)](https://packagist.org/packages/cachethq/cachet) +Cachet, the open-source status page system. -![Screenshot](https://cachethq.io/img/main-interface.jpg) +## Cachet 3.x Announcement -Cachet is a beautiful and powerful open source status page system, a free replacement to services such as StatusPage.io, Status.io and others. +We are shifting our attention and resources to Cachet 3.x and will no longer be supporting the 2.x version. -## Supporting Cachet - -Cachet is a BSD-3-licensed open source project. If you'd like to support future development, check out the [Cachet Patreon campaign](https://patreon.com/jbrooksuk). +For more information on the Cachet rebuild and our plans for 3.x, you can read the announcement [here](https://github.com/CachetHQ/Cachet/discussions/4342). ## Features -- List your services components -- Log incidents -- Apply custom CSS to the status page +- List your service components +- Report incidents +- Customise the look of your status page - Markdown support for incident messages -- JSON API -- Translated into eleven languages +- A powerful JSON API - Metrics -- Cross-database support: MySQL, PostgreSQL and SQLite -- Subscriber notifications via Email -- Two factor authentication, with Google Authenticator - -## Usage in production - -The `master` branch of this repository is a development branch and **should not** be used in production. Instead, please check out the latest tag release. +- Multi-lingual +- Subscriber notifications via email +- Two factor authentication ## Requirements -- PHP 5.5.9+ or newer -- Apache or Nginx server +- PHP 7.1.3 – 7.3 +- HTTP server with PHP support (e.g.: Apache, Nginx, Caddy) - [Composer](https://getcomposer.org) - -## How to contribute - -We're always looking for contributions that improve Cachet. It's easy to get started and you don't even need to know how to write a single line of code! - -### Contributing as a non-developer/non-designer - -If you're one of the more linguistically talented people in the world who can speak and write more than just English, we're always looking for new [translations](#translations). - -Of course bug reports, feature requests and [documentation](https://docs.cachethq.io) are always being sought after. - -### Contributing as a designer - -As Cachet gains new features, the design and ideas that were once a perfect fit need updating and in some cases designing from scratch. This is where you come in! Fancy giving Cachet a lick of paint? Sweet! - -You'll need to install Node.js, Bower and Gulp. - -To get started you can do the following: - -1. Install Node.js and our dev dependencies. -2. Modify the SCSS files in `./resources/assets/sass/` -3. Run `gulp` - -If you're making a lot of changes, you'll find that running `gulp watch` will really help you out! - -### Contributing as a developer - -Built using [Laravel](https://laravel.com), Cachet is very easy to jump into. Have a look around you'll find it surprisingly easy! - -These extra dependencies are required to develop Cachet: - -- Node.js -- Gulp -- Git - -Once cloned to your local machine, you'll need some demo data! Simply run `php artisan cachet:seed` to get the demo installation on the go. +- A supported database: MariaDB, MySQL, PostgreSQL or SQLite ## Installation, Upgrades and Documentation -You can now find our documentation at [https://docs.cachethq.io](https://docs.cachethq.io). +You can find documentation at [https://docs.cachethq.io](https://docs.cachethq.io). -- [Installing Cachet](https://docs.cachethq.io/docs/installing-cachet) -- [Getting started with Docker](https://docs.cachethq.io/docs/get-started-with-docker) -- [Getting started with Vagrant](https://docs.cachethq.io/docs/get-started-with-vagrant) +Here are some useful quick links: -### Demo Account +- [Installing Cachet](https://docs.cachethq.io/installation/) +- [Getting started with Docker](https://docs.cachethq.io/installation/docker) -To test out the demo, you may login to the [Dashboard](https://demo.cachethq.io/dashboard) with the following: +### Demo -- **Username:** test or test@test.com -- **Password:** test123 +To test out the demo, you can log in to the [Cachet dashboard](https://demo.cachethq.io/dashboard) with the following credentials: -The demo is reset every half hour. +- **Username:** `test` or `test@example.com` +- **Password:** `test123` -### Release Notes - -All releases are listed on the [Releases page](https://github.com/CachetHQ/Cachet/releases) of the [Cachet GitHub repository](https://github.com/CachetHQ/Cachet). On the Releases page, you can also find the release notes for each release. - -## Translations - -A special thank you to our [translators](https://crowdin.com/project/cachet/activity_stream), who have allowed us to share Cachet with the world. If you'd like to contribute translations, please check out our [CrowdIn project](https://crowdin.com/project/cachet). +> **Note** +> The demo will automatically reset every 30 minutes. ## Security Vulnerabilities -If you discover a security vulnerability within Cachet, please send an e-mail to us at support@alt-three.com. All security vulnerabilities will be promptly addressed. - -## Installations - -We offer a paid installation service, which starts at $99 but is subject to change, dependant on your setup and infrastructure. - -To find out more, email us at support@alt-three.com +If you discover a security vulnerability within Cachet, please send an e-mail to [support@cachethq.io](mailto:support@cachethq.io?Cachet%20Security%20Vulnerability). All security vulnerabilities are reviewed on a case-by-case basis. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..5459a341d89 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,17 @@ +# Security Policy + +**PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, [SEE BELOW](#reporting-a-vulnerability).** + +## Supported Versions + +Use this section to tell people about which versions of your project are +currently being supported with security updates. + +| Version | Supported | +| ------- | ------------------ | +| 2.4 | :white_check_mark: | +| < 2.4 | :x: | + +## Reporting a Vulnerability + +If you discover a security vulnerability within Cachet, please email James Brooks at james@cachethq.io. All security vulnerabilities will be promptly addressed. diff --git a/VERSION b/VERSION index c2417c3ed03..005119baaa0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.3.7-dev +2.4.1 diff --git a/app/Bus/Commands/Component/AddComponentCommand.php b/app/Bus/Commands/Component/CreateComponentCommand.php similarity index 57% rename from app/Bus/Commands/Component/AddComponentCommand.php rename to app/Bus/Commands/Component/CreateComponentCommand.php index a50e725d79d..4244f42cbc6 100644 --- a/app/Bus/Commands/Component/AddComponentCommand.php +++ b/app/Bus/Commands/Component/CreateComponentCommand.php @@ -11,7 +11,12 @@ namespace CachetHQ\Cachet\Bus\Commands\Component; -final class AddComponentCommand +/** + * This is the create component command class. + * + * @author James Brooks + */ +final class CreateComponentCommand { /** * The component name. @@ -62,6 +67,20 @@ final class AddComponentCommand */ public $enabled; + /** + * JSON meta data for the component. + * + * @var array|null + */ + public $meta; + + /** + * Tags string. + * + * @var string + */ + public $tags; + /** * The validation rules. * @@ -69,28 +88,32 @@ final class AddComponentCommand */ public $rules = [ 'name' => 'required|string', - 'description' => 'string', - 'status' => 'int|min:1|max:4', - 'link' => 'url', - 'order' => 'int', - 'group_id' => 'int', - 'enabled' => 'bool', + 'description' => 'nullable|string', + 'status' => 'required|int|min:0|max:4', + 'link' => 'nullable|url', + 'order' => 'nullable|int', + 'group_id' => 'nullable|int', + 'enabled' => 'nullable|bool', + 'meta' => 'nullable|array', + 'tags' => 'nullable|string', ]; /** * Create a new add component command instance. * - * @param string $name - * @param string $description - * @param int $status - * @param string $link - * @param int $order - * @param int $group_id - * @param bool $enabled + * @param string $name + * @param string $description + * @param int $status + * @param string $link + * @param int $order + * @param int $group_id + * @param bool $enabled + * @param array|null $meta + * @param string|null $tags * * @return void */ - public function __construct($name, $description, $status, $link, $order, $group_id, $enabled) + public function __construct($name, $description, $status, $link, $order, $group_id, $enabled, $meta, $tags = null) { $this->name = $name; $this->description = $description; @@ -99,5 +122,7 @@ public function __construct($name, $description, $status, $link, $order, $group_ $this->order = $order; $this->group_id = $group_id; $this->enabled = $enabled; + $this->meta = $meta; + $this->tags = $tags; } } diff --git a/app/Bus/Commands/Component/UpdateComponentCommand.php b/app/Bus/Commands/Component/UpdateComponentCommand.php index 17c5d12c489..9909339754c 100644 --- a/app/Bus/Commands/Component/UpdateComponentCommand.php +++ b/app/Bus/Commands/Component/UpdateComponentCommand.php @@ -25,90 +25,120 @@ final class UpdateComponentCommand /** * The component name. * - * @var string + * @var string|null */ public $name; /** * The component description. * - * @var string + * @var string|null */ public $description; /** * The component status. * - * @var int + * @var int|null */ public $status; /** * The component link. * - * @var string + * @var string|null */ public $link; /** * The component order. * - * @var int + * @var int|null */ public $order; /** * The component group. * - * @var int + * @var int|null */ public $group_id; /** * Is the component enabled? * - * @var bool + * @var bool|null */ public $enabled; + /** + * JSON meta data for the component. + * + * @var array|null + */ + public $meta; + + /** + * The tags. + * + * @var string|null + */ + public $tags; + + /** + * If this is true, we won't notify subscribers of the change. + * + * @var bool + */ + public $silent; + /** * The validation rules. * * @var string[] */ public $rules = [ - 'name' => 'string', - 'description' => 'string', - 'status' => 'int|min:1|max:4', - 'link' => 'url', - 'order' => 'int', - 'group_id' => 'int', - 'enabled' => 'bool', + 'name' => 'nullable|string', + 'description' => 'nullable|string', + 'status' => 'nullable|int|min:0|max:4', + 'link' => 'nullable|url', + 'order' => 'nullable|int', + 'group_id' => 'nullable|int', + 'enabled' => 'nullable|bool', + 'meta' => 'nullable|array', + 'silent' => 'nullable|bool', ]; /** * Create a new update component command instance. * * @param \CachetHQ\Cachet\Models\Component $component - * @param string $name - * @param string $description - * @param int $status - * @param string $link - * @param int $order - * @param int $group_id - * @param bool $enabled + * @param string|null $name + * @param string|null $description + * @param int|null $status + * @param string|null $link + * @param int|null $order + * @param int|null $group_id + * @param bool|null $enabled + * @param array|null $meta + * @param string|null $tags + * @param bool $silent * * @return void */ - public function __construct(Component $component, $name, $description, $status, $link, $order, $group_id, $enabled) + public function __construct(Component $component, $name = null, $description = null, $status = null, $link = null, $order = null, $group_id = null, $enabled = null, $meta = null, $tags = null, $silent = null) { $this->component = $component; $this->name = $name; $this->description = $description; - $this->status = (int) $status; + $this->status = $status; $this->link = $link; $this->order = $order; $this->group_id = $group_id; $this->enabled = $enabled; + $this->meta = $meta; + $this->tags = $tags; + $this->silent = $silent; + $this->tags = $tags; } } diff --git a/app/Bus/Commands/ComponentGroup/AddComponentGroupCommand.php b/app/Bus/Commands/ComponentGroup/CreateComponentGroupCommand.php similarity index 70% rename from app/Bus/Commands/ComponentGroup/AddComponentGroupCommand.php rename to app/Bus/Commands/ComponentGroup/CreateComponentGroupCommand.php index e68f24fd09d..7bec1b5d666 100644 --- a/app/Bus/Commands/ComponentGroup/AddComponentGroupCommand.php +++ b/app/Bus/Commands/ComponentGroup/CreateComponentGroupCommand.php @@ -12,11 +12,11 @@ namespace CachetHQ\Cachet\Bus\Commands\ComponentGroup; /** - * This is the add component group command. + * This is the create component group command. * * @author James Brooks */ -final class AddComponentGroupCommand +final class CreateComponentGroupCommand { /** * The component group name. @@ -39,6 +39,13 @@ final class AddComponentGroupCommand */ public $collapsed; + /** + * Is the component visible to public? + * + * @var int + */ + public $visible; + /** * The validation rules. * @@ -46,8 +53,9 @@ final class AddComponentGroupCommand */ public $rules = [ 'name' => 'required|string', - 'order' => 'int', - 'collapsed' => 'int|between:0,3', + 'order' => 'required|int', + 'collapsed' => 'required|int|between:0,4', + 'visible' => 'required|bool', ]; /** @@ -56,13 +64,15 @@ final class AddComponentGroupCommand * @param string $name * @param int $order * @param int $collapsed + * @param int $visible * * @return void */ - public function __construct($name, $order, $collapsed) + public function __construct($name, $order, $collapsed, $visible) { $this->name = $name; $this->order = (int) $order; $this->collapsed = $collapsed; + $this->visible = (int) $visible; } } diff --git a/app/Bus/Commands/ComponentGroup/UpdateComponentGroupCommand.php b/app/Bus/Commands/ComponentGroup/UpdateComponentGroupCommand.php index a20c4944855..1067ef22fc0 100644 --- a/app/Bus/Commands/ComponentGroup/UpdateComponentGroupCommand.php +++ b/app/Bus/Commands/ComponentGroup/UpdateComponentGroupCommand.php @@ -48,15 +48,23 @@ final class UpdateComponentGroupCommand */ public $collapsed; + /** + * Is the component visible to public? + * + * @var int + */ + public $visible; + /** * The validation rules. * * @var string[] */ public $rules = [ - 'name' => 'string', - 'order' => 'int', - 'collapsed' => 'int|between:0,3', + 'name' => 'nullable|string', + 'order' => 'nullable|int', + 'collapsed' => 'nullable|int|between:0,4', + 'visible' => 'nullable|bool', ]; /** @@ -66,14 +74,16 @@ final class UpdateComponentGroupCommand * @param string $name * @param int $order * @param int $collapsed + * @param int $visible * * @return void */ - public function __construct(ComponentGroup $group, $name, $order, $collapsed) + public function __construct(ComponentGroup $group, $name, $order, $collapsed, $visible) { $this->group = $group; $this->name = $name; $this->order = (int) $order; $this->collapsed = $collapsed; + $this->visible = (int) $visible; } } diff --git a/app/Bus/Commands/Incident/ReportIncidentCommand.php b/app/Bus/Commands/Incident/CreateIncidentCommand.php similarity index 61% rename from app/Bus/Commands/Incident/ReportIncidentCommand.php rename to app/Bus/Commands/Incident/CreateIncidentCommand.php index 4e1e972f94d..4f94f2f890d 100644 --- a/app/Bus/Commands/Incident/ReportIncidentCommand.php +++ b/app/Bus/Commands/Incident/CreateIncidentCommand.php @@ -11,7 +11,13 @@ namespace CachetHQ\Cachet\Bus\Commands\Incident; -final class ReportIncidentCommand +/** + * This is the create incident command. + * + * @author Joseph Cohen + * @author James Brooks + */ +final class CreateIncidentCommand { /** * The incident name. @@ -63,11 +69,18 @@ final class ReportIncidentCommand public $notify; /** - * The date at which the incident occurred. + * Whether to stick the incident on top. + * + * @var bool + */ + public $stickied; + + /** + * The date at which the incident occurred at. * * @var string|null */ - public $incident_date; + public $occurred_at; /** * A given incident template. @@ -83,6 +96,13 @@ final class ReportIncidentCommand */ public $template_vars; + /** + * Meta key/value pairs. + * + * @var array + */ + public $meta = []; + /** * The validation rules. * @@ -91,17 +111,19 @@ final class ReportIncidentCommand public $rules = [ 'name' => 'required|string', 'status' => 'required|int|min:0|max:4', - 'message' => 'string', - 'visible' => 'bool', - 'component_id' => 'int|required_with:component_status', - 'component_status' => 'int|min:1|max:4|required_with:component_id', - 'notify' => 'bool', - 'incident_date' => 'string', - 'template' => 'string', + 'message' => 'nullable|string', + 'visible' => 'nullable|bool', + 'component_id' => 'nullable|required_with:component_status|int', + 'component_status' => 'nullable|required_with:component_id|int|min:0|max:4', + 'notify' => 'nullable|bool', + 'stickied' => 'required|bool', + 'occurred_at' => 'nullable|string', + 'template' => 'nullable|string', + 'meta' => 'nullable|array', ]; /** - * Create a new report incident command instance. + * Create a new create incident command instance. * * @param string $name * @param int $status @@ -110,13 +132,15 @@ final class ReportIncidentCommand * @param int $component_id * @param int $component_status * @param bool $notify - * @param string|null $incident_date + * @param bool $stickied + * @param string|null $occurred_at * @param string|null $template - * @param array|null $template_vars + * @param array $template_vars + * @param array $meta * * @return void */ - public function __construct($name, $status, $message, $visible, $component_id, $component_status, $notify, $incident_date, $template, array $template_vars = null) + public function __construct($name, $status, $message, $visible, $component_id, $component_status, $notify, $stickied, $occurred_at, $template, array $template_vars = [], array $meta = []) { $this->name = $name; $this->status = $status; @@ -125,8 +149,10 @@ public function __construct($name, $status, $message, $visible, $component_id, $ $this->component_id = $component_id; $this->component_status = $component_status; $this->notify = $notify; - $this->incident_date = $incident_date; + $this->stickied = $stickied; + $this->occurred_at = $occurred_at; $this->template = $template; $this->template_vars = $template_vars; + $this->meta = $meta; } } diff --git a/app/Bus/Commands/Incident/ReportMaintenanceCommand.php b/app/Bus/Commands/Incident/ReportMaintenanceCommand.php deleted file mode 100644 index 3b44aa10694..00000000000 --- a/app/Bus/Commands/Incident/ReportMaintenanceCommand.php +++ /dev/null @@ -1,73 +0,0 @@ - 'required|string', - 'message' => 'string', - 'notify' => 'bool', - 'timestamp' => 'string', - ]; - - /** - * Create a new report maintenance command instance. - * - * @param string $name - * @param string $message - * @param bool $notify - * @param string $timestamp - * - * @return void - */ - public function __construct($name, $message, $notify, $timestamp) - { - $this->name = $name; - $this->message = $message; - $this->notify = $notify; - $this->timestamp = $timestamp; - } -} diff --git a/app/Bus/Commands/Incident/UpdateIncidentCommand.php b/app/Bus/Commands/Incident/UpdateIncidentCommand.php index 2d5f2c73191..1328b37ca91 100644 --- a/app/Bus/Commands/Incident/UpdateIncidentCommand.php +++ b/app/Bus/Commands/Incident/UpdateIncidentCommand.php @@ -13,6 +13,13 @@ use CachetHQ\Cachet\Models\Incident; +/** + * This is the update incident command. + * + * @author James Brooks + * @author Joseph Cohem + * @author Graham Campbell + */ final class UpdateIncidentCommand { /** @@ -72,11 +79,18 @@ final class UpdateIncidentCommand public $notify; /** - * The date that the incident occurred on. + * Whether to stick the incident on top. * - * @var string + * @var bool */ - public $incident_date; + public $stickied; + + /** + * The timestamp that the incident occurred at. + * + * @var string|null + */ + public $occurred_at; /** * A given incident template. @@ -92,20 +106,30 @@ final class UpdateIncidentCommand */ public $template_vars; + /** + * Meta key/value pairs. + * + * @var array + */ + public $meta = []; + /** * The validation rules. * * @var string[] */ public $rules = [ - 'name' => 'string', - 'status' => 'int|min:0|max:4', - 'message' => 'string', - 'visible' => 'bool', - 'component_id' => 'int', - 'component_status' => 'int|min:1|max:4|required_with:component_id', - 'notify' => 'bool', - 'template' => 'string', + 'name' => 'nullable|string', + 'status' => 'nullable|int|min:0|max:4', + 'message' => 'nullable|string', + 'visible' => 'nullable|bool', + 'component_id' => 'nullable|int', + 'component_status' => 'nullable|int|min:0|max:4|required_with:component_id', + 'notify' => 'nullable|bool', + 'stickied' => 'nullable|bool', + 'occurred_at' => 'nullable|string', + 'template' => 'nullable|string', + 'meta' => 'nullable|array', ]; /** @@ -119,13 +143,15 @@ final class UpdateIncidentCommand * @param int $component_id * @param int $component_status * @param bool $notify - * @param string|null $incident_date + * @param bool $stickied + * @param string|null $occurred_at * @param string|null $template - * @param array|null $template_vars + * @param array $template_vars + * @param array $meta * * @return void */ - public function __construct(Incident $incident, $name, $status, $message, $visible, $component_id, $component_status, $notify, $incident_date, $template, array $template_vars = null) + public function __construct(Incident $incident, $name, $status, $message, $visible, $component_id, $component_status, $notify, $stickied, $occurred_at, $template, array $template_vars = [], array $meta = []) { $this->incident = $incident; $this->name = $name; @@ -135,8 +161,10 @@ public function __construct(Incident $incident, $name, $status, $message, $visib $this->component_id = $component_id; $this->component_status = $component_status; $this->notify = $notify; - $this->incident_date = $incident_date; + $this->stickied = $stickied; + $this->occurred_at = $occurred_at; $this->template = $template; $this->template_vars = $template_vars; + $this->meta = $meta; } } diff --git a/app/Bus/Commands/IncidentUpdate/CreateIncidentUpdateCommand.php b/app/Bus/Commands/IncidentUpdate/CreateIncidentUpdateCommand.php new file mode 100644 index 00000000000..caa65a75797 --- /dev/null +++ b/app/Bus/Commands/IncidentUpdate/CreateIncidentUpdateCommand.php @@ -0,0 +1,97 @@ + + */ +final class CreateIncidentUpdateCommand +{ + /** + * The incident. + * + * @var \CachetHQ\Cachet\Models\Incident + */ + public $incident; + + /** + * The incident status. + * + * @var int + */ + public $status; + + /** + * The incident message. + * + * @var string + */ + public $message; + /** + * The incident component. + * + * @var int + */ + public $component_id; + + /** + * The component status. + * + * @var int + */ + public $component_status; + /** + * The user. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'incident' => 'required', + 'status' => 'required|int|min:1|max:4', + 'message' => 'required|string', + 'component_id' => 'nullable|required_with:component_status|int', + 'component_status' => 'nullable|required_with:component_id|int|min:0|max:4', + 'user' => 'required', + ]; + + /** + * Create a new report incident update command instance. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * @param string $status + * @param string $message + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(Incident $incident, $status, $message, $component_id, $component_status, User $user) + { + $this->incident = $incident; + $this->status = $status; + $this->message = $message; + $this->component_id = $component_id; + $this->component_status = $component_status; + $this->user = $user; + } +} diff --git a/app/Bus/Commands/IncidentUpdate/RemoveIncidentUpdateCommand.php b/app/Bus/Commands/IncidentUpdate/RemoveIncidentUpdateCommand.php new file mode 100644 index 00000000000..7440e3529dd --- /dev/null +++ b/app/Bus/Commands/IncidentUpdate/RemoveIncidentUpdateCommand.php @@ -0,0 +1,41 @@ + + */ +final class RemoveIncidentUpdateCommand +{ + /** + * The incident update to remove. + * + * @var \CachetHQ\Cachet\Models\IncidentUpdate + */ + public $incidentUpdate; + + /** + * Create a new remove incident update command instance. + * + * @param \CachetHQ\Cachet\Models\IncidentUpdate $incidentUpdate + * + * @return void + */ + public function __construct(IncidentUpdate $incidentUpdate) + { + $this->incidentUpdate = $incidentUpdate; + } +} diff --git a/app/Bus/Commands/IncidentUpdate/UpdateIncidentUpdateCommand.php b/app/Bus/Commands/IncidentUpdate/UpdateIncidentUpdateCommand.php new file mode 100644 index 00000000000..12d363ad17e --- /dev/null +++ b/app/Bus/Commands/IncidentUpdate/UpdateIncidentUpdateCommand.php @@ -0,0 +1,79 @@ + + */ +final class UpdateIncidentUpdateCommand +{ + /** + * The incident update. + * + * @var \CachetHQ\Cachet\Models\IncidentUpdate + */ + public $update; + + /** + * The incident status. + * + * @var int + */ + public $status; + + /** + * The incident message. + * + * @var string + */ + public $message; + + /** + * The user. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'status' => 'nullable|int|min:1|max:4', + 'message' => 'nullable|string', + ]; + + /** + * Create a new update incident update command instance. + * + * @param \CachetHQ\Cachet\Models\IncidentUpdate $update + * @param string $status + * @param string $message + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(IncidentUpdate $update, $status, $message, User $user) + { + $this->update = $update; + $this->status = $status; + $this->message = $message; + $this->user = $user; + } +} diff --git a/app/Bus/Commands/Metric/AddMetricCommand.php b/app/Bus/Commands/Metric/CreateMetricCommand.php similarity index 74% rename from app/Bus/Commands/Metric/AddMetricCommand.php rename to app/Bus/Commands/Metric/CreateMetricCommand.php index d1dd254696d..01e31ed3901 100644 --- a/app/Bus/Commands/Metric/AddMetricCommand.php +++ b/app/Bus/Commands/Metric/CreateMetricCommand.php @@ -11,7 +11,13 @@ namespace CachetHQ\Cachet\Bus\Commands\Metric; -final class AddMetricCommand +/** + * This is the create metric command class. + * + * @author Joseph Cohen + * @author James Brooks + */ +final class CreateMetricCommand { /** * The metric name. @@ -83,6 +89,13 @@ final class AddMetricCommand */ public $order; + /** + * The visibility of the metric. + * + * @var int + */ + public $visible; + /** * The validation rules. * @@ -91,15 +104,15 @@ final class AddMetricCommand public $rules = [ 'name' => 'required|string', 'suffix' => 'required|string', - 'description' => 'string', - 'display_chart' => 'bool', - 'default_value' => 'int', - 'calc_type' => 'int', - 'display_chart' => 'int', - 'places' => 'int|between:0,4', - 'default_view' => 'int|between:0,3', - 'threshold' => 'numeric|between:0,10', - 'order' => 'int', + 'description' => 'nullable|string', + 'default_value' => 'required|int', + 'calc_type' => 'required|int', + 'display_chart' => 'nullable|int', + 'places' => 'nullable|int|between:0,4', + 'default_view' => 'required|int|between:0,3', + 'threshold' => 'required|int', + 'order' => 'nullable|int', + 'visible' => 'required|int|between:0,2', ]; /** @@ -115,10 +128,11 @@ final class AddMetricCommand * @param int $default_view * @param int $threshold * @param int $order + * @param int $visible * * @return void */ - public function __construct($name, $suffix, $description, $default_value, $calc_type, $display_chart, $places, $default_view, $threshold, $order = 0) + public function __construct($name, $suffix, $description, $default_value, $calc_type, $display_chart, $places, $default_view, $threshold, $order = 0, $visible = 1) { $this->name = $name; $this->suffix = $suffix; @@ -130,5 +144,6 @@ public function __construct($name, $suffix, $description, $default_value, $calc_ $this->default_view = $default_view; $this->threshold = $threshold; $this->order = $order; + $this->visible = $visible; } } diff --git a/app/Bus/Commands/Metric/AddMetricPointCommand.php b/app/Bus/Commands/Metric/CreateMetricPointCommand.php similarity index 75% rename from app/Bus/Commands/Metric/AddMetricPointCommand.php rename to app/Bus/Commands/Metric/CreateMetricPointCommand.php index ae339585ba3..3555f1945da 100644 --- a/app/Bus/Commands/Metric/AddMetricPointCommand.php +++ b/app/Bus/Commands/Metric/CreateMetricPointCommand.php @@ -13,7 +13,13 @@ use CachetHQ\Cachet\Models\Metric; -final class AddMetricPointCommand +/** + * This is the create metric point command class. + * + * @author Joseph Cohen + * @author James Brooks + */ +final class CreateMetricPointCommand { /** * The metric to add. @@ -32,7 +38,7 @@ final class AddMetricPointCommand /** * The metric point created at. * - * @var string + * @var int */ public $created_at; @@ -42,8 +48,8 @@ final class AddMetricPointCommand * @var string[] */ public $rules = [ - 'value' => 'numeric', - 'created_at' => 'string', + 'value' => 'required|numeric', + 'created_at' => 'nullable|int', ]; /** @@ -51,7 +57,7 @@ final class AddMetricPointCommand * * @param \CachetHQ\Cachet\Models\Metric $metric * @param int $value - * @param string $created_at + * @param int $created_at * * @return void */ diff --git a/app/Bus/Commands/Metric/UpdateMetricCommand.php b/app/Bus/Commands/Metric/UpdateMetricCommand.php index 1bf6cd26881..535837f4ad2 100644 --- a/app/Bus/Commands/Metric/UpdateMetricCommand.php +++ b/app/Bus/Commands/Metric/UpdateMetricCommand.php @@ -92,23 +92,30 @@ final class UpdateMetricCommand */ public $order; + /** + * The visibility of the metric. + * + * @var int + */ + public $visible; + /** * The validation rules. * * @var string[] */ public $rules = [ - 'name' => 'string', - 'suffix' => 'string', - 'description' => 'string', - 'display_chart' => 'bool', - 'default_value' => 'numeric', - 'calc_type' => 'int|in:0,1', - 'display_chart' => 'int', - 'places' => 'numeric|between:0,4', - 'default_view' => 'numeric|between:0,4', - 'threshold' => 'numeric|between:0,10', - 'order' => 'int', + 'name' => 'nullable|string', + 'suffix' => 'nullable|string', + 'description' => 'nullable|string', + 'default_value' => 'nullable|numeric', + 'calc_type' => 'nullable|int|in:0,1', + 'display_chart' => 'nullable|int', + 'places' => 'nullable|numeric|between:0,4', + 'default_view' => 'nullable|numeric|between:0,4', + 'threshold' => 'nullable|int', + 'order' => 'nullable|int', + 'visible' => 'nullable|int|between:0,2', ]; /** @@ -125,10 +132,11 @@ final class UpdateMetricCommand * @param int $default_view * @param int $threshold * @param int|null $order + * @param int $visible * * @return void */ - public function __construct(Metric $metric, $name, $suffix, $description, $default_value, $calc_type, $display_chart, $places, $default_view, $threshold, $order = null) + public function __construct(Metric $metric, $name, $suffix, $description, $default_value, $calc_type, $display_chart, $places, $default_view, $threshold, $order = null, $visible = null) { $this->metric = $metric; $this->name = $name; @@ -141,5 +149,6 @@ public function __construct(Metric $metric, $name, $suffix, $description, $defau $this->default_view = $default_view; $this->threshold = $threshold; $this->order = $order; + $this->visible = $visible; } } diff --git a/app/Bus/Commands/Metric/UpdateMetricPointCommand.php b/app/Bus/Commands/Metric/UpdateMetricPointCommand.php index 34bff77270c..0d976df94c7 100644 --- a/app/Bus/Commands/Metric/UpdateMetricPointCommand.php +++ b/app/Bus/Commands/Metric/UpdateMetricPointCommand.php @@ -55,8 +55,8 @@ final class UpdateMetricPointCommand * @var string[] */ public $rules = [ - 'value' => 'numeric', - 'created_at' => 'string', + 'value' => 'nullable|numeric', + 'created_at' => 'nullable|string', ]; /** diff --git a/app/Bus/Commands/Schedule/CreateScheduleCommand.php b/app/Bus/Commands/Schedule/CreateScheduleCommand.php new file mode 100644 index 00000000000..d40d68df148 --- /dev/null +++ b/app/Bus/Commands/Schedule/CreateScheduleCommand.php @@ -0,0 +1,108 @@ + + */ +final class CreateScheduleCommand +{ + /** + * The schedule name. + * + * @var string + */ + public $name; + + /** + * The schedule message. + * + * @var string + */ + public $message; + + /** + * The schedule status. + * + * @var int + */ + public $status; + + /** + * The schedule date. + * + * @var string + */ + public $scheduled_at; + + /** + * The completed at date. + * + * @var string + */ + public $completed_at; + + /** + * The components affected by the schedule. + * + * @var array + */ + public $components; + + /** + * Whether to notify that the incident was reported. + * + * @var bool + */ + public $notify; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'name' => 'required|string', + 'message' => 'nullable|string', + 'status' => 'required|int|min:0|max:2', + 'scheduled_at' => 'required|string', + 'completed_at' => 'nullable|string', + 'components' => 'nullable|array', + 'notify' => 'nullable|bool', + ]; + + /** + * Create a new create schedule command instance. + * + * @param string $name + * @param string $message + * @param int $status + * @param string $scheduled_at + * @param string $completed_at + * @param array $components + * @param bool $notify + * + * @return void + */ + public function __construct($name, $message, $status, $scheduled_at, $completed_at, $components, $notify) + { + $this->name = $name; + $this->message = $message; + $this->status = $status; + $this->scheduled_at = $scheduled_at; + $this->completed_at = $completed_at; + $this->components = $components; + $this->notify = $notify; + } +} diff --git a/app/Bus/Commands/Schedule/DeleteScheduleCommand.php b/app/Bus/Commands/Schedule/DeleteScheduleCommand.php new file mode 100644 index 00000000000..572dcf52d80 --- /dev/null +++ b/app/Bus/Commands/Schedule/DeleteScheduleCommand.php @@ -0,0 +1,50 @@ + + */ +final class DeleteScheduleCommand +{ + /** + * The schedule to delete. + * + * @var \CachetHQ\Cachet\Models\Schedule + */ + public $schedule; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'schedule' => 'required', + ]; + + /** + * Create a new delete schedule command instance. + * + * @param \CachetHQ\Cachet\Models\Schedule $schedule + * + * @return void + */ + public function __construct(Schedule $schedule) + { + $this->schedule = $schedule; + } +} diff --git a/app/Bus/Commands/Schedule/UpdateScheduleCommand.php b/app/Bus/Commands/Schedule/UpdateScheduleCommand.php new file mode 100644 index 00000000000..bfe100d47a8 --- /dev/null +++ b/app/Bus/Commands/Schedule/UpdateScheduleCommand.php @@ -0,0 +1,110 @@ + + */ +final class UpdateScheduleCommand +{ + /** + * The schedule to update. + * + * @param \CachetHQ\Cachet\Models\Schedule + */ + public $schedule; + + /** + * The schedule name. + * + * @var string + */ + public $name; + + /** + * The schedule message. + * + * @var string + */ + public $message; + + /** + * The schedule status. + * + * @var int + */ + public $status; + + /** + * The schedule date. + * + * @var string + */ + public $scheduled_at; + + /** + * The completed at date. + * + * @var string + */ + public $completed_at; + + /** + * The components affected by the schedule. + * + * @var array + */ + public $components; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'schedule' => 'required', + 'name' => 'nullable|string', + 'message' => 'nullable|string', + 'status' => 'nullable|int|min:0|max:2', + 'scheduled_at' => 'nullable|string', + 'completed_at' => 'nullable|string', + 'components' => 'nullable|array', + ]; + + /** + * Create a new update schedule command instance. + * + * @param \CachetHQ\Cachet\Models\Schedule $schedule + * @param string $name + * @param string $message + * @param int $status + * @param string $scheduled_at + * @param string $completed_at + * @param array $components + * + * @return void + */ + public function __construct(Schedule $schedule, $name, $message, $status, $scheduled_at, $completed_at, array $components = []) + { + $this->schedule = $schedule; + $this->name = $name; + $this->message = $message; + $this->status = $status; + $this->scheduled_at = $scheduled_at; + $this->completed_at = $completed_at; + $this->components = $components; + } +} diff --git a/app/Bus/Commands/System/Config/UpdateConfigCommand.php b/app/Bus/Commands/System/Config/UpdateConfigCommand.php new file mode 100644 index 00000000000..9fb21610e1d --- /dev/null +++ b/app/Bus/Commands/System/Config/UpdateConfigCommand.php @@ -0,0 +1,39 @@ + + */ +final class UpdateConfigCommand +{ + /** + * This is the config key/values array. + * + * @var array + */ + public $values; + + /** + * Create a new update config command instance. + * + * @param array $values + * + * @return void + */ + public function __construct($values) + { + $this->values = $values; + } +} diff --git a/app/Bus/Commands/User/AddTeamMemberCommand.php b/app/Bus/Commands/User/CreateUserCommand.php similarity index 82% rename from app/Bus/Commands/User/AddTeamMemberCommand.php rename to app/Bus/Commands/User/CreateUserCommand.php index 655b73427c0..fad590d3baf 100644 --- a/app/Bus/Commands/User/AddTeamMemberCommand.php +++ b/app/Bus/Commands/User/CreateUserCommand.php @@ -11,7 +11,12 @@ namespace CachetHQ\Cachet\Bus\Commands\User; -final class AddTeamMemberCommand +/** + * This is the create user command. + * + * @author James Brooks + */ +final class CreateUserCommand { /** * The user username. @@ -47,9 +52,9 @@ final class AddTeamMemberCommand * @var string[] */ public $rules = [ - 'name' => 'required|string', - 'password' => 'string', - 'level' => 'int', + 'username' => 'required|string', + 'password' => 'required|string', + 'level' => 'required|int', ]; /** diff --git a/app/Bus/Commands/User/InviteTeamMemberCommand.php b/app/Bus/Commands/User/InviteUserCommand.php similarity index 74% rename from app/Bus/Commands/User/InviteTeamMemberCommand.php rename to app/Bus/Commands/User/InviteUserCommand.php index 7fd4b5dfd8a..49f16d9a615 100644 --- a/app/Bus/Commands/User/InviteTeamMemberCommand.php +++ b/app/Bus/Commands/User/InviteUserCommand.php @@ -11,7 +11,12 @@ namespace CachetHQ\Cachet\Bus\Commands\User; -final class InviteTeamMemberCommand +/** + * This is the invite user command. + * + * @author James Brooks + */ +final class InviteUserCommand { /** * The invite emails. @@ -26,11 +31,11 @@ final class InviteTeamMemberCommand * @var string[] */ public $rules = [ - 'emails' => 'required|array|email', + 'emails.*' => 'required|email', ]; /** - * Create a new invite team member command instance. + * Create a new invite user command instance. * * @param string[] $emails * diff --git a/app/Bus/Commands/User/SignupUserCommand.php b/app/Bus/Commands/User/SignupUserCommand.php index 7cbf782c63c..cfba31f5d60 100644 --- a/app/Bus/Commands/User/SignupUserCommand.php +++ b/app/Bus/Commands/User/SignupUserCommand.php @@ -48,9 +48,9 @@ final class SignupUserCommand */ public $rules = [ 'username' => 'required|string', - 'password' => 'string', + 'password' => 'required|string', 'email' => 'required|string|email', - 'level' => 'int', + 'level' => 'required|int', ]; /** diff --git a/app/Bus/Events/User/UserWasAddedEvent.php b/app/Bus/Commands/User/WelcomeUserCommand.php similarity index 68% rename from app/Bus/Events/User/UserWasAddedEvent.php rename to app/Bus/Commands/User/WelcomeUserCommand.php index fffe48fb7ce..65f805e5c85 100644 --- a/app/Bus/Events/User/UserWasAddedEvent.php +++ b/app/Bus/Commands/User/WelcomeUserCommand.php @@ -9,21 +9,26 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Bus\Events\User; +namespace CachetHQ\Cachet\Bus\Commands\User; use CachetHQ\Cachet\Models\User; -final class UserWasAddedEvent implements UserEventInterface +/** + * This is the welcome user command. + * + * @author James Brooks + */ +final class WelcomeUserCommand { /** - * The user that has been added. + * The user. * * @var \CachetHQ\Cachet\Models\User */ public $user; /** - * Create a new user was added event instance. + * Create a new welcome user command instance. * * @param \CachetHQ\Cachet\Models\User $user * diff --git a/app/Bus/Events/ActionInterface.php b/app/Bus/Events/ActionInterface.php new file mode 100644 index 00000000000..ae1bc1c8a54 --- /dev/null +++ b/app/Bus/Events/ActionInterface.php @@ -0,0 +1,28 @@ + + * @author James Brooks + */ +interface ActionInterface +{ + /** + * Get the event action. + * + * @return array + */ + public function getAction(); +} diff --git a/app/Bus/Events/Beacon/BeaconEventInterface.php b/app/Bus/Events/Beacon/BeaconEventInterface.php new file mode 100644 index 00000000000..672fde7da28 --- /dev/null +++ b/app/Bus/Events/Beacon/BeaconEventInterface.php @@ -0,0 +1,24 @@ + + */ +interface BeaconEventInterface extends EventInterface +{ + // +} diff --git a/app/Bus/Events/Beacon/BeaconFailedToSendEvent.php b/app/Bus/Events/Beacon/BeaconFailedToSendEvent.php new file mode 100644 index 00000000000..932dab30d9d --- /dev/null +++ b/app/Bus/Events/Beacon/BeaconFailedToSendEvent.php @@ -0,0 +1,30 @@ + + */ +final class BeaconFailedToSendEvent implements BeaconEventInterface +{ + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Beacon failed to send.'; + } +} diff --git a/app/Bus/Events/Beacon/BeaconWasSentEvent.php b/app/Bus/Events/Beacon/BeaconWasSentEvent.php new file mode 100644 index 00000000000..919f338f9c9 --- /dev/null +++ b/app/Bus/Events/Beacon/BeaconWasSentEvent.php @@ -0,0 +1,30 @@ + + */ +final class BeaconWasSentEvent implements BeaconEventInterface +{ + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Beacon was sent.'; + } +} diff --git a/app/Bus/Events/Component/ComponentEventInterface.php b/app/Bus/Events/Component/ComponentEventInterface.php index 147c999c043..281a811f790 100644 --- a/app/Bus/Events/Component/ComponentEventInterface.php +++ b/app/Bus/Events/Component/ComponentEventInterface.php @@ -13,6 +13,12 @@ use CachetHQ\Cachet\Bus\Events\EventInterface; +/** + * This is the component event interface. + * + * @author Graham Campbell + * @author James Brooks + */ interface ComponentEventInterface extends EventInterface { // diff --git a/app/Bus/Events/Component/ComponentStatusWasChangedEvent.php b/app/Bus/Events/Component/ComponentStatusWasChangedEvent.php new file mode 100644 index 00000000000..4c987409b65 --- /dev/null +++ b/app/Bus/Events/Component/ComponentStatusWasChangedEvent.php @@ -0,0 +1,102 @@ + + */ +final class ComponentStatusWasChangedEvent implements ActionInterface, ComponentEventInterface +{ + /** + * The user who changed the component. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The component that was changed. + * + * @var \CachetHQ\Cachet\Models\Component + */ + public $component; + + /** + * The original status of the component. + * + * @var int + */ + public $original_status; + + /** + * The new status of the component. + * + * @var int + */ + public $new_status; + + /** + * If silent, we won't notify. + * + * @var bool + */ + public $silent; + + /** + * Create a new component was updated event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * @param \CachetHQ\Cachet\Models\Component $component + * @param int $original_status + * @param int $new_status + * @param bool $silent + * + * @return void + */ + public function __construct(User $user, Component $component, $original_status, $new_status, $silent) + { + $this->user = $user; + $this->component = $component; + $this->original_status = $original_status; + $this->new_status = $new_status; + $this->silent = $silent; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Component status was changed.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/Component/ComponentWasAddedEvent.php b/app/Bus/Events/Component/ComponentWasAddedEvent.php deleted file mode 100644 index 7c892a78f83..00000000000 --- a/app/Bus/Events/Component/ComponentWasAddedEvent.php +++ /dev/null @@ -1,36 +0,0 @@ -component = $component; - } -} diff --git a/app/Bus/Events/Component/ComponentWasCreatedEvent.php b/app/Bus/Events/Component/ComponentWasCreatedEvent.php new file mode 100644 index 00000000000..29b00da5950 --- /dev/null +++ b/app/Bus/Events/Component/ComponentWasCreatedEvent.php @@ -0,0 +1,75 @@ + + */ +final class ComponentWasCreatedEvent implements ActionInterface, ComponentEventInterface +{ + /** + * The user who added the component. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The component that was added. + * + * @var \CachetHQ\Cachet\Models\Component + */ + public $component; + + /** + * Create a new component was added event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * @param \CachetHQ\Cachet\Models\Component $component + * + * @return void + */ + public function __construct(User $user, Component $component) + { + $this->user = $user; + $this->component = $component; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Component was added.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/Component/ComponentWasRemovedEvent.php b/app/Bus/Events/Component/ComponentWasRemovedEvent.php index f44839d347a..02dc3e64910 100644 --- a/app/Bus/Events/Component/ComponentWasRemovedEvent.php +++ b/app/Bus/Events/Component/ComponentWasRemovedEvent.php @@ -11,10 +11,24 @@ namespace CachetHQ\Cachet\Bus\Events\Component; +use CachetHQ\Cachet\Bus\Events\ActionInterface; use CachetHQ\Cachet\Models\Component; +use CachetHQ\Cachet\Models\User; -final class ComponentWasRemovedEvent implements ComponentEventInterface +/** + * This is the component was removed event class. + * + * @author James Brooks + */ +final class ComponentWasRemovedEvent implements ActionInterface, ComponentEventInterface { + /** + * The user who removed the component. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + /** * The component that was removed. * @@ -25,12 +39,37 @@ final class ComponentWasRemovedEvent implements ComponentEventInterface /** * Create a new component was removed event instance. * + * @param \CachetHQ\Cachet\Models\User $user * @param \CachetHQ\Cachet\Models\Component $component * * @return void */ - public function __construct(Component $component) + public function __construct(User $user, Component $component) { + $this->user = $user; $this->component = $component; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Component was removed.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } } diff --git a/app/Bus/Events/Component/ComponentWasUpdatedEvent.php b/app/Bus/Events/Component/ComponentWasUpdatedEvent.php index b5857251342..3349e4642fc 100644 --- a/app/Bus/Events/Component/ComponentWasUpdatedEvent.php +++ b/app/Bus/Events/Component/ComponentWasUpdatedEvent.php @@ -11,10 +11,25 @@ namespace CachetHQ\Cachet\Bus\Events\Component; +use CachetHQ\Cachet\Bus\Events\ActionInterface; use CachetHQ\Cachet\Models\Component; +use CachetHQ\Cachet\Models\User; -final class ComponentWasUpdatedEvent implements ComponentEventInterface +/** + * This is the component was updated event class. + * + * @author James Brooks + * @author Graham Campbell + */ +final class ComponentWasUpdatedEvent implements ActionInterface, ComponentEventInterface { + /** + * The user who updated the component. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + /** * The component that was updated. * @@ -25,12 +40,37 @@ final class ComponentWasUpdatedEvent implements ComponentEventInterface /** * Create a new component was updated event instance. * + * @param \CachetHQ\Cachet\Models\User $user * @param \CachetHQ\Cachet\Models\Component $component * * @return void */ - public function __construct(Component $component) + public function __construct(User $user, Component $component) { + $this->user = $user; $this->component = $component; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Component was updated.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } } diff --git a/app/Bus/Events/ComponentGroup/ComponentGroupEventInterface.php b/app/Bus/Events/ComponentGroup/ComponentGroupEventInterface.php index 99d92b77dc8..6e40f0ee24c 100644 --- a/app/Bus/Events/ComponentGroup/ComponentGroupEventInterface.php +++ b/app/Bus/Events/ComponentGroup/ComponentGroupEventInterface.php @@ -13,6 +13,12 @@ use CachetHQ\Cachet\Bus\Events\EventInterface; +/** + * This is the component group event interface. + * + * @author Graham Campbell + * @author James Brooks + */ interface ComponentGroupEventInterface extends EventInterface { // diff --git a/app/Bus/Events/ComponentGroup/ComponentGroupWasAddedEvent.php b/app/Bus/Events/ComponentGroup/ComponentGroupWasAddedEvent.php deleted file mode 100644 index 2d8479fe3f1..00000000000 --- a/app/Bus/Events/ComponentGroup/ComponentGroupWasAddedEvent.php +++ /dev/null @@ -1,36 +0,0 @@ -group = $group; - } -} diff --git a/app/Bus/Events/ComponentGroup/ComponentGroupWasCreatedEvent.php b/app/Bus/Events/ComponentGroup/ComponentGroupWasCreatedEvent.php new file mode 100644 index 00000000000..97ad605786e --- /dev/null +++ b/app/Bus/Events/ComponentGroup/ComponentGroupWasCreatedEvent.php @@ -0,0 +1,75 @@ + + */ +final class ComponentGroupWasCreatedEvent implements ActionInterface, ComponentGroupEventInterface +{ + /** + * The user who added the component group. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The component group that was added. + * + * @var \CachetHQ\Cachet\Models\ComponentGroup + */ + public $group; + + /** + * Create a new component group was added event instance. + * + * @param \CachetHQ\Cachet\Models\User $group + * @param \CachetHQ\Cachet\Models\ComponentGroup $group + * + * @return void + */ + public function __construct(User $user, ComponentGroup $group) + { + $this->user = $user; + $this->group = $group; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Component Group was added.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/ComponentGroup/ComponentGroupWasRemovedEvent.php b/app/Bus/Events/ComponentGroup/ComponentGroupWasRemovedEvent.php index 275449cef38..1bf33fb0862 100644 --- a/app/Bus/Events/ComponentGroup/ComponentGroupWasRemovedEvent.php +++ b/app/Bus/Events/ComponentGroup/ComponentGroupWasRemovedEvent.php @@ -11,10 +11,19 @@ namespace CachetHQ\Cachet\Bus\Events\ComponentGroup; +use CachetHQ\Cachet\Bus\Events\ActionInterface; use CachetHQ\Cachet\Models\ComponentGroup; +use CachetHQ\Cachet\Models\User; -final class ComponentGroupWasRemovedEvent implements ComponentGroupEventInterface +final class ComponentGroupWasRemovedEvent implements ActionInterface, ComponentGroupEventInterface { + /** + * The user who removed the component group. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + /** * The component group that was removed. * @@ -25,12 +34,37 @@ final class ComponentGroupWasRemovedEvent implements ComponentGroupEventInterfac /** * Create a new component group was removed event instance. * + * @param \CachetHQ\Cachet\Models\User $user * @param \CachetHQ\Cachet\Models\ComponentGroup $group * * @return void */ - public function __construct(ComponentGroup $group) + public function __construct(User $user, ComponentGroup $group) { + $this->user = $user; $this->group = $group; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Component Group was removed.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } } diff --git a/app/Bus/Events/ComponentGroup/ComponentGroupWasUpdatedEvent.php b/app/Bus/Events/ComponentGroup/ComponentGroupWasUpdatedEvent.php index 19138f75c5b..5942f00c8b8 100644 --- a/app/Bus/Events/ComponentGroup/ComponentGroupWasUpdatedEvent.php +++ b/app/Bus/Events/ComponentGroup/ComponentGroupWasUpdatedEvent.php @@ -11,10 +11,19 @@ namespace CachetHQ\Cachet\Bus\Events\ComponentGroup; +use CachetHQ\Cachet\Bus\Events\ActionInterface; use CachetHQ\Cachet\Models\ComponentGroup; +use CachetHQ\Cachet\Models\User; -final class ComponentGroupWasUpdatedEvent implements ComponentGroupEventInterface +final class ComponentGroupWasUpdatedEvent implements ActionInterface, ComponentGroupEventInterface { + /** + * The user who updated the component group. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + /** * The component group that was updated. * @@ -25,12 +34,37 @@ final class ComponentGroupWasUpdatedEvent implements ComponentGroupEventInterfac /** * Create a new component group was updated event instance. * + * @param \CachetHQ\Cachet\Models\User $user * @param \CachetHQ\Cachet\Models\ComponentGroup $group * * @return void */ - public function __construct(ComponentGroup $group) + public function __construct(User $user, ComponentGroup $group) { + $this->user = $user; $this->group = $group; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Component Group was updated.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } } diff --git a/app/Bus/Events/EventInterface.php b/app/Bus/Events/EventInterface.php index 53013dfdb3a..41a58b735b7 100644 --- a/app/Bus/Events/EventInterface.php +++ b/app/Bus/Events/EventInterface.php @@ -11,6 +11,12 @@ namespace CachetHQ\Cachet\Bus\Events; +/** + * This is the event interface. + * + * @author Graham Campbell + * @author James Brooks + */ interface EventInterface { // diff --git a/app/Bus/Events/Incident/IncidentEventInterface.php b/app/Bus/Events/Incident/IncidentEventInterface.php index a4cb6054f88..31418b55781 100644 --- a/app/Bus/Events/Incident/IncidentEventInterface.php +++ b/app/Bus/Events/Incident/IncidentEventInterface.php @@ -13,6 +13,12 @@ use CachetHQ\Cachet\Bus\Events\EventInterface; +/** + * This is the incident event interface. + * + * @author Graham Campbell + * @author James Brooks + */ interface IncidentEventInterface extends EventInterface { // diff --git a/app/Bus/Events/Incident/IncidentWasCreatedEvent.php b/app/Bus/Events/Incident/IncidentWasCreatedEvent.php new file mode 100644 index 00000000000..c43d672b0c6 --- /dev/null +++ b/app/Bus/Events/Incident/IncidentWasCreatedEvent.php @@ -0,0 +1,79 @@ +user = $user; + $this->incident = $incident; + $this->notify = $notify; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Incident was reported.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/Incident/IncidentWasRemovedEvent.php b/app/Bus/Events/Incident/IncidentWasRemovedEvent.php index ef6890b03ed..78a95f76127 100644 --- a/app/Bus/Events/Incident/IncidentWasRemovedEvent.php +++ b/app/Bus/Events/Incident/IncidentWasRemovedEvent.php @@ -11,10 +11,19 @@ namespace CachetHQ\Cachet\Bus\Events\Incident; +use CachetHQ\Cachet\Bus\Events\ActionInterface; use CachetHQ\Cachet\Models\Incident; +use CachetHQ\Cachet\Models\User; -final class IncidentWasRemovedEvent implements IncidentEventInterface +final class IncidentWasRemovedEvent implements ActionInterface, IncidentEventInterface { + /** + * The user who removed the event. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + /** * The incident that has been removed. * @@ -25,12 +34,37 @@ final class IncidentWasRemovedEvent implements IncidentEventInterface /** * Create a new incident was removed event instance. * + * @param \CachetHQ\Cachet\Models\User $user * @param \CachetHQ\Cachet\Models\Incident $incident * * @return void */ - public function __construct(Incident $incident) + public function __construct(User $user, Incident $incident) { + $this->user = $user; $this->incident = $incident; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Incident was removed.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } } diff --git a/app/Bus/Events/Incident/IncidentWasReportedEvent.php b/app/Bus/Events/Incident/IncidentWasReportedEvent.php deleted file mode 100644 index a93e7b02a29..00000000000 --- a/app/Bus/Events/Incident/IncidentWasReportedEvent.php +++ /dev/null @@ -1,36 +0,0 @@ -incident = $incident; - } -} diff --git a/app/Bus/Events/Incident/IncidentWasUpdatedEvent.php b/app/Bus/Events/Incident/IncidentWasUpdatedEvent.php index 251bc781beb..7aa11322af1 100644 --- a/app/Bus/Events/Incident/IncidentWasUpdatedEvent.php +++ b/app/Bus/Events/Incident/IncidentWasUpdatedEvent.php @@ -11,10 +11,19 @@ namespace CachetHQ\Cachet\Bus\Events\Incident; +use CachetHQ\Cachet\Bus\Events\ActionInterface; use CachetHQ\Cachet\Models\Incident; +use CachetHQ\Cachet\Models\User; -final class IncidentWasUpdatedEvent implements IncidentEventInterface +final class IncidentWasUpdatedEvent implements ActionInterface, IncidentEventInterface { + /** + * The user who updated the event. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + /** * The incident that has been updated. * @@ -25,12 +34,37 @@ final class IncidentWasUpdatedEvent implements IncidentEventInterface /** * Create a new incident has updated event instance. * + * @param \CachetHQ\Cachet\Models\User $user * @param \CachetHQ\Cachet\Models\Incident $incident * * @return void */ - public function __construct(Incident $incident) + public function __construct(User $user, Incident $incident) { + $this->user = $user; $this->incident = $incident; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Incident was updated.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } } diff --git a/app/Bus/Events/Incident/MaintenanceWasScheduledEvent.php b/app/Bus/Events/Incident/MaintenanceWasScheduledEvent.php deleted file mode 100644 index 2bf29381762..00000000000 --- a/app/Bus/Events/Incident/MaintenanceWasScheduledEvent.php +++ /dev/null @@ -1,36 +0,0 @@ -incident = $incident; - } -} diff --git a/app/Bus/Events/IncidentUpdate/IncidentUpdateEventInterface.php b/app/Bus/Events/IncidentUpdate/IncidentUpdateEventInterface.php new file mode 100644 index 00000000000..9f1687afccb --- /dev/null +++ b/app/Bus/Events/IncidentUpdate/IncidentUpdateEventInterface.php @@ -0,0 +1,24 @@ + + */ +interface IncidentUpdateEventInterface extends EventInterface +{ + // +} diff --git a/app/Bus/Events/IncidentUpdate/IncidentUpdateWasRemovedEvent.php b/app/Bus/Events/IncidentUpdate/IncidentUpdateWasRemovedEvent.php new file mode 100644 index 00000000000..8618457fac2 --- /dev/null +++ b/app/Bus/Events/IncidentUpdate/IncidentUpdateWasRemovedEvent.php @@ -0,0 +1,75 @@ + + */ +final class IncidentUpdateWasRemovedEvent implements ActionInterface, IncidentUpdateEventInterface +{ + /** + * The user who removed the incident update. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The incident update that has been removed. + * + * @var \CachetHQ\Cachet\Models\IncidentUpdate + */ + public $update; + + /** + * Create a new incident update was removed event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * @param \CachetHQ\Cachet\Models\IncidentUpdate $update + * + * @return void + */ + public function __construct(User $user, IncidentUpdate $update) + { + $this->user = $user; + $this->update = $update; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Incident Update was removed.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/IncidentUpdate/IncidentUpdateWasReportedEvent.php b/app/Bus/Events/IncidentUpdate/IncidentUpdateWasReportedEvent.php new file mode 100644 index 00000000000..52dadf88102 --- /dev/null +++ b/app/Bus/Events/IncidentUpdate/IncidentUpdateWasReportedEvent.php @@ -0,0 +1,75 @@ + + */ +final class IncidentUpdateWasReportedEvent implements ActionInterface, IncidentUpdateEventInterface +{ + /** + * The user who reported the incident update. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The incident update that has been reported. + * + * @var \CachetHQ\Cachet\Models\IncidentUpdate + */ + public $update; + + /** + * Create a new incident update was reported event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * @param \CachetHQ\Cachet\Models\IncidentUpdate $update + * + * @return void + */ + public function __construct(User $user, IncidentUpdate $update) + { + $this->user = $user; + $this->update = $update; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Incident Update was reported.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/IncidentUpdate/IncidentUpdateWasUpdatedEvent.php b/app/Bus/Events/IncidentUpdate/IncidentUpdateWasUpdatedEvent.php new file mode 100644 index 00000000000..20e3782d73e --- /dev/null +++ b/app/Bus/Events/IncidentUpdate/IncidentUpdateWasUpdatedEvent.php @@ -0,0 +1,74 @@ + + */ +final class IncidentUpdateWasUpdatedEvent implements ActionInterface, IncidentUpdateEventInterface +{ + /** + * The user who updated the incident update. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The incident update that has been updated. + * + * @var \CachetHQ\Cachet\Models\IncidentUpdate + */ + public $update; + + /** + * Create a new incident update was updated event instance. + * + * @param \CachetHQ\Cachet\Models\IncidentUpdate $update + * + * @return void + */ + public function __construct(User $user, IncidentUpdate $update) + { + $this->user = $user; + $this->update = $update; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Incident Update was updated.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/Invite/InviteEventInterface.php b/app/Bus/Events/Invite/InviteEventInterface.php index 35ccfc44ac6..63c199706b5 100644 --- a/app/Bus/Events/Invite/InviteEventInterface.php +++ b/app/Bus/Events/Invite/InviteEventInterface.php @@ -13,6 +13,12 @@ use CachetHQ\Cachet\Bus\Events\EventInterface; +/** + * This is the invite event interface. + * + * @author Graham Campbell + * @author James Brooks + */ interface InviteEventInterface extends EventInterface { // diff --git a/app/Bus/Events/Invite/InviteWasClaimedEvent.php b/app/Bus/Events/Invite/InviteWasClaimedEvent.php index b8a3c77d246..02f950ee52d 100644 --- a/app/Bus/Events/Invite/InviteWasClaimedEvent.php +++ b/app/Bus/Events/Invite/InviteWasClaimedEvent.php @@ -31,4 +31,14 @@ public function __construct(Invite $invite) { $this->invite = $invite; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Invite was claimed.'; + } } diff --git a/app/Bus/Events/Metric/MetricEventInterface.php b/app/Bus/Events/Metric/MetricEventInterface.php index 104a381a37e..631b4549208 100644 --- a/app/Bus/Events/Metric/MetricEventInterface.php +++ b/app/Bus/Events/Metric/MetricEventInterface.php @@ -13,6 +13,12 @@ use CachetHQ\Cachet\Bus\Events\EventInterface; +/** + * This is the metric event interface. + * + * @author Graham Campbell + * @author James Brooks + */ interface MetricEventInterface extends EventInterface { // diff --git a/app/Bus/Events/Metric/MetricPointWasAddedEvent.php b/app/Bus/Events/Metric/MetricPointWasAddedEvent.php deleted file mode 100644 index 7de09cf24fb..00000000000 --- a/app/Bus/Events/Metric/MetricPointWasAddedEvent.php +++ /dev/null @@ -1,36 +0,0 @@ -metricPoint = $metricPoint; - } -} diff --git a/app/Bus/Events/Metric/MetricPointWasCreatedEvent.php b/app/Bus/Events/Metric/MetricPointWasCreatedEvent.php new file mode 100644 index 00000000000..7137b8c119c --- /dev/null +++ b/app/Bus/Events/Metric/MetricPointWasCreatedEvent.php @@ -0,0 +1,75 @@ + + */ +final class MetricPointWasCreatedEvent implements ActionInterface, MetricEventInterface +{ + /** + * The user who added the metric point. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The metric point that was added. + * + * @var \CachetHQ\Cachet\Models\MetricPoint + */ + public $metricPoint; + + /** + * Create a new metric point was added event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * @param \CachetHQ\Cachet\Models\MetricPoint $metricPoint + * + * @return void + */ + public function __construct(User $user, MetricPoint $metricPoint) + { + $this->user = $user; + $this->metricPoint = $metricPoint; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Metric Point was added.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/Metric/MetricPointWasRemovedEvent.php b/app/Bus/Events/Metric/MetricPointWasRemovedEvent.php index 2d0b76ee341..85718a41d5d 100644 --- a/app/Bus/Events/Metric/MetricPointWasRemovedEvent.php +++ b/app/Bus/Events/Metric/MetricPointWasRemovedEvent.php @@ -11,10 +11,19 @@ namespace CachetHQ\Cachet\Bus\Events\Metric; +use CachetHQ\Cachet\Bus\Events\ActionInterface; use CachetHQ\Cachet\Models\MetricPoint; +use CachetHQ\Cachet\Models\User; -final class MetricPointWasRemovedEvent implements MetricEventInterface +final class MetricPointWasRemovedEvent implements ActionInterface, MetricEventInterface { + /** + * The user who removed the metric point. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + /** * The metric point that was removed. * @@ -25,12 +34,37 @@ final class MetricPointWasRemovedEvent implements MetricEventInterface /** * Create a new metric point was removed event instance. * + * @param \CachetHQ\Cachet\Models\User $user * @param \CachetHQ\Cachet\Models\MetricPoint $memtricPoint * * @return void */ - public function __construct(MetricPoint $metricPoint) + public function __construct(User $user, MetricPoint $metricPoint) { + $this->user = $user; $this->metricPoint = $metricPoint; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Metric Point was removed.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } } diff --git a/app/Bus/Events/Metric/MetricPointWasUpdatedEvent.php b/app/Bus/Events/Metric/MetricPointWasUpdatedEvent.php index 35e97f5d543..b61a595d111 100644 --- a/app/Bus/Events/Metric/MetricPointWasUpdatedEvent.php +++ b/app/Bus/Events/Metric/MetricPointWasUpdatedEvent.php @@ -11,10 +11,19 @@ namespace CachetHQ\Cachet\Bus\Events\Metric; +use CachetHQ\Cachet\Bus\Events\ActionInterface; use CachetHQ\Cachet\Models\MetricPoint; +use CachetHQ\Cachet\Models\User; -final class MetricPointWasUpdatedEvent implements MetricEventInterface +final class MetricPointWasUpdatedEvent implements ActionInterface, MetricEventInterface { + /** + * The user who updated the metric point. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + /** * The metric point that was updated. * @@ -25,12 +34,37 @@ final class MetricPointWasUpdatedEvent implements MetricEventInterface /** * Create a new metric point was updated event instance. * + * @param \CachetHQ\Cachet\Models\User $user * @param \CachetHQ\Cachet\Models\MetricPoint $metricPoint * * @return void */ - public function __construct(MetricPoint $metricPoint) + public function __construct(User $user, MetricPoint $metricPoint) { + $this->user = $user; $this->metricPoint = $metricPoint; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Metric Point was updated.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } } diff --git a/app/Bus/Events/Metric/MetricWasAddedEvent.php b/app/Bus/Events/Metric/MetricWasAddedEvent.php deleted file mode 100644 index 9d495c6eff9..00000000000 --- a/app/Bus/Events/Metric/MetricWasAddedEvent.php +++ /dev/null @@ -1,36 +0,0 @@ -metric = $metric; - } -} diff --git a/app/Bus/Events/Metric/MetricWasCreatedEvent.php b/app/Bus/Events/Metric/MetricWasCreatedEvent.php new file mode 100644 index 00000000000..f3e123b8e5c --- /dev/null +++ b/app/Bus/Events/Metric/MetricWasCreatedEvent.php @@ -0,0 +1,75 @@ + + */ +final class MetricWasCreatedEvent implements ActionInterface, MetricEventInterface +{ + /** + * The user who added the metric. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The metric that was added. + * + * @var \CachetHQ\Cachet\Models\Metric + */ + public $metric; + + /** + * Create a new metric was added event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * @param \CachetHQ\Cachet\Models\Metric $metric + * + * @return void + */ + public function __construct(User $user, Metric $metric) + { + $this->user = $user; + $this->metric = $metric; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Metric was added.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/Metric/MetricWasRemovedEvent.php b/app/Bus/Events/Metric/MetricWasRemovedEvent.php index 67061cf11d6..7193f307f95 100644 --- a/app/Bus/Events/Metric/MetricWasRemovedEvent.php +++ b/app/Bus/Events/Metric/MetricWasRemovedEvent.php @@ -11,10 +11,19 @@ namespace CachetHQ\Cachet\Bus\Events\Metric; +use CachetHQ\Cachet\Bus\Events\ActionInterface; use CachetHQ\Cachet\Models\Metric; +use CachetHQ\Cachet\Models\User; -final class MetricWasRemovedEvent implements MetricEventInterface +final class MetricWasRemovedEvent implements ActionInterface, MetricEventInterface { + /** + * The user who removed the metric. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + /** * The metric that was removed. * @@ -25,12 +34,37 @@ final class MetricWasRemovedEvent implements MetricEventInterface /** * Create a new metric was removed event instance. * + * @param \CachetHQ\Cachet\Models\User $user * @param \CachetHQ\Cachet\Models\Metric $metric * * @return void */ - public function __construct(Metric $metric) + public function __construct(User $user, Metric $metric) { + $this->user = $user; $this->metric = $metric; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Metric was removed.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } } diff --git a/app/Bus/Events/Metric/MetricWasUpdatedEvent.php b/app/Bus/Events/Metric/MetricWasUpdatedEvent.php index dd400eb33af..48b1dc9cc6a 100644 --- a/app/Bus/Events/Metric/MetricWasUpdatedEvent.php +++ b/app/Bus/Events/Metric/MetricWasUpdatedEvent.php @@ -11,10 +11,19 @@ namespace CachetHQ\Cachet\Bus\Events\Metric; +use CachetHQ\Cachet\Bus\Events\ActionInterface; use CachetHQ\Cachet\Models\Metric; +use CachetHQ\Cachet\Models\User; -final class MetricWasUpdatedEvent implements MetricEventInterface +final class MetricWasUpdatedEvent implements ActionInterface, MetricEventInterface { + /** + * The user who update the metric. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + /** * The metric that was updated. * @@ -25,12 +34,37 @@ final class MetricWasUpdatedEvent implements MetricEventInterface /** * Create a new metric was updated event instance. * + * @param \CachetHQ\Cachet\Models\User $user * @param \CachetHQ\Cachet\Models\Metric $metric * * @return void */ - public function __construct(Metric $metric) + public function __construct(User $user, Metric $metric) { + $this->user = $user; $this->metric = $metric; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Metric was updated.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } } diff --git a/app/Bus/Events/Schedule/ScheduleEventInterface.php b/app/Bus/Events/Schedule/ScheduleEventInterface.php new file mode 100644 index 00000000000..cd23ed511bc --- /dev/null +++ b/app/Bus/Events/Schedule/ScheduleEventInterface.php @@ -0,0 +1,24 @@ + + */ +interface ScheduleEventInterface extends EventInterface +{ + // +} diff --git a/app/Bus/Events/Schedule/ScheduleWasCreatedEvent.php b/app/Bus/Events/Schedule/ScheduleWasCreatedEvent.php new file mode 100644 index 00000000000..2438658d71b --- /dev/null +++ b/app/Bus/Events/Schedule/ScheduleWasCreatedEvent.php @@ -0,0 +1,84 @@ + + */ +final class ScheduleWasCreatedEvent implements ActionInterface, ScheduleEventInterface +{ + /** + * The user that created the schedule. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The schedule that has been created. + * + * @var \CachetHQ\Cachet\Models\Schedule + */ + public $schedule; + + /** + * Whether to notify that the incident was reported. + * + * @var bool + */ + public $notify; + + /** + * Create a new schedule was created event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * @param \CachetHQ\Cachet\Models\Schedule $schedule + * @param bool notify + * + * @return void + */ + public function __construct(User $user, Schedule $schedule, $notify = false) + { + $this->user = $user; + $this->schedule = $schedule; + $this->notify = $notify; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Schedule was created.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/Schedule/ScheduleWasRemovedEvent.php b/app/Bus/Events/Schedule/ScheduleWasRemovedEvent.php new file mode 100644 index 00000000000..525c77f7959 --- /dev/null +++ b/app/Bus/Events/Schedule/ScheduleWasRemovedEvent.php @@ -0,0 +1,75 @@ + + */ +final class ScheduleWasRemovedEvent implements ActionInterface, ScheduleEventInterface +{ + /** + * The user that removed the schedule. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The schedule that has been removed. + * + * @var \CachetHQ\Cachet\Models\Schedule + */ + public $schedule; + + /** + * Create a new schedule was removed event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * @param \CachetHQ\Cachet\Models\Schedule $schedule + * + * @return void + */ + public function __construct(User $user, Schedule $schedule) + { + $this->user = $user; + $this->schedule = $schedule; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Schedule was removed.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/Schedule/ScheduleWasUpdatedEvent.php b/app/Bus/Events/Schedule/ScheduleWasUpdatedEvent.php new file mode 100644 index 00000000000..18fc46aaf5d --- /dev/null +++ b/app/Bus/Events/Schedule/ScheduleWasUpdatedEvent.php @@ -0,0 +1,75 @@ + + */ +final class ScheduleWasUpdatedEvent implements ActionInterface, ScheduleEventInterface +{ + /** + * The user that created the schedule. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The schedule that has been updated. + * + * @var \CachetHQ\Cachet\Models\Schedule + */ + public $schedule; + + /** + * Create a new schedule was updated event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * @param \CachetHQ\Cachet\Models\Schedule $schedule + * + * @return void + */ + public function __construct(User $user, Schedule $schedule) + { + $this->user = $user; + $this->schedule = $schedule; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Schedule was updated.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/Subscriber/SubscriberEventInterface.php b/app/Bus/Events/Subscriber/SubscriberEventInterface.php index 24ed5b5af6d..d8ec141182e 100644 --- a/app/Bus/Events/Subscriber/SubscriberEventInterface.php +++ b/app/Bus/Events/Subscriber/SubscriberEventInterface.php @@ -13,6 +13,12 @@ use CachetHQ\Cachet\Bus\Events\EventInterface; +/** + * This is the subscriber event interface. + * + * @author Graham Campbell + * @author James Brooks + */ interface SubscriberEventInterface extends EventInterface { // diff --git a/app/Bus/Events/Subscriber/SubscriberHasSubscribedEvent.php b/app/Bus/Events/Subscriber/SubscriberHasSubscribedEvent.php index c48668f53e6..2dc68624d19 100644 --- a/app/Bus/Events/Subscriber/SubscriberHasSubscribedEvent.php +++ b/app/Bus/Events/Subscriber/SubscriberHasSubscribedEvent.php @@ -33,4 +33,14 @@ public function __construct(Subscriber $subscriber) { $this->subscriber = $subscriber; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Subscriber has subscribed.'; + } } diff --git a/app/Bus/Events/Subscriber/SubscriberHasUnsubscribedEvent.php b/app/Bus/Events/Subscriber/SubscriberHasUnsubscribedEvent.php index 2d35fc2a3ee..4e67f5c8883 100644 --- a/app/Bus/Events/Subscriber/SubscriberHasUnsubscribedEvent.php +++ b/app/Bus/Events/Subscriber/SubscriberHasUnsubscribedEvent.php @@ -33,4 +33,14 @@ public function __construct(Subscriber $subscriber) { $this->subscriber = $subscriber; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Subscriber has unsubscribed.'; + } } diff --git a/app/Bus/Events/Subscriber/SubscriberHasUpdatedSubscriptionsEvent.php b/app/Bus/Events/Subscriber/SubscriberHasUpdatedSubscriptionsEvent.php index 12f6e1ec195..8f6c71b8bd4 100644 --- a/app/Bus/Events/Subscriber/SubscriberHasUpdatedSubscriptionsEvent.php +++ b/app/Bus/Events/Subscriber/SubscriberHasUpdatedSubscriptionsEvent.php @@ -38,4 +38,14 @@ public function __construct(Subscriber $subscriber) { $this->subscriber = $subscriber; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Subscriber has updated subscription.'; + } } diff --git a/app/Bus/Events/Subscriber/SubscriberHasVerifiedEvent.php b/app/Bus/Events/Subscriber/SubscriberHasVerifiedEvent.php index b0ed5a7d26e..b621dda139f 100644 --- a/app/Bus/Events/Subscriber/SubscriberHasVerifiedEvent.php +++ b/app/Bus/Events/Subscriber/SubscriberHasVerifiedEvent.php @@ -33,4 +33,14 @@ public function __construct(Subscriber $subscriber) { $this->subscriber = $subscriber; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'Subscriber has verified.'; + } } diff --git a/app/Bus/Events/System/SystemCheckedForUpdatesEvent.php b/app/Bus/Events/System/SystemCheckedForUpdatesEvent.php new file mode 100644 index 00000000000..98481777d9e --- /dev/null +++ b/app/Bus/Events/System/SystemCheckedForUpdatesEvent.php @@ -0,0 +1,30 @@ + + */ +final class SystemCheckedForUpdatesEvent implements SystemEventInterface +{ + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'System checked for updated.'; + } +} diff --git a/app/Bus/Events/System/SystemEventInterface.php b/app/Bus/Events/System/SystemEventInterface.php new file mode 100644 index 00000000000..d195fa5899c --- /dev/null +++ b/app/Bus/Events/System/SystemEventInterface.php @@ -0,0 +1,24 @@ + + */ +interface SystemEventInterface extends EventInterface +{ + // +} diff --git a/app/Bus/Events/System/SystemWasInstalledEvent.php b/app/Bus/Events/System/SystemWasInstalledEvent.php new file mode 100644 index 00000000000..cfc47ea2fc0 --- /dev/null +++ b/app/Bus/Events/System/SystemWasInstalledEvent.php @@ -0,0 +1,30 @@ + + */ +final class SystemWasInstalledEvent implements SystemEventInterface +{ + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'System was installed.'; + } +} diff --git a/app/Bus/Events/System/SystemWasResetEvent.php b/app/Bus/Events/System/SystemWasResetEvent.php new file mode 100644 index 00000000000..b96763f401f --- /dev/null +++ b/app/Bus/Events/System/SystemWasResetEvent.php @@ -0,0 +1,30 @@ + + */ +final class SystemWasResetEvent implements SystemEventInterface +{ + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'System was reset.'; + } +} diff --git a/app/Bus/Events/System/SystemWasUpdatedEvent.php b/app/Bus/Events/System/SystemWasUpdatedEvent.php new file mode 100644 index 00000000000..faf0cf07e1a --- /dev/null +++ b/app/Bus/Events/System/SystemWasUpdatedEvent.php @@ -0,0 +1,30 @@ + + */ +final class SystemWasUpdatedEvent implements SystemEventInterface +{ + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'System was updated.'; + } +} diff --git a/app/Bus/Events/User/UserAcceptedInviteEvent.php b/app/Bus/Events/User/UserAcceptedInviteEvent.php new file mode 100644 index 00000000000..6148c3dc62d --- /dev/null +++ b/app/Bus/Events/User/UserAcceptedInviteEvent.php @@ -0,0 +1,75 @@ + + */ +final class UserAcceptedInviteEvent implements ActionInterface, UserEventInterface +{ + /** + * The user that accepted the invite. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * The invite that the user accepted. + * + * @var \CachetHQ\Cachet\Models\Invite + */ + public $invite; + + /** + * Create a new user accepted invite event class. + * + * @param \CachetHQ\Cachet\Models\User $user + * @param \CachetHQ\Cachet\Models\Invite $invite + * + * @return void + */ + public function __construct(User $user, Invite $invite) + { + $this->user = $user; + $this->invite = $invite; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User accepted invite.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/User/UserDisabledTwoAuthEvent.php b/app/Bus/Events/User/UserDisabledTwoAuthEvent.php new file mode 100644 index 00000000000..a7646dbaae7 --- /dev/null +++ b/app/Bus/Events/User/UserDisabledTwoAuthEvent.php @@ -0,0 +1,65 @@ + + */ +final class UserDisabledTwoAuthEvent implements ActionInterface, UserEventInterface +{ + /** + * The user that disabled two auth. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * Create a new user disabled two auth event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User disabled two-factor authentication.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/User/UserEnabledTwoAuthEvent.php b/app/Bus/Events/User/UserEnabledTwoAuthEvent.php new file mode 100644 index 00000000000..9a13d045d30 --- /dev/null +++ b/app/Bus/Events/User/UserEnabledTwoAuthEvent.php @@ -0,0 +1,65 @@ + + */ +final class UserEnabledTwoAuthEvent implements ActionInterface, UserEventInterface +{ + /** + * The user that enabled two auth. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * Create a new user enabled two auth event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User enabled two-factor authentication.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/User/UserEventInterface.php b/app/Bus/Events/User/UserEventInterface.php index f36a4819a54..be886a83430 100644 --- a/app/Bus/Events/User/UserEventInterface.php +++ b/app/Bus/Events/User/UserEventInterface.php @@ -13,6 +13,12 @@ use CachetHQ\Cachet\Bus\Events\EventInterface; +/** + * This is the user event interface. + * + * @author Graham Campbell + * @author James Brooks + */ interface UserEventInterface extends EventInterface { // diff --git a/app/Bus/Events/User/UserFailedTwoAuthEvent.php b/app/Bus/Events/User/UserFailedTwoAuthEvent.php new file mode 100644 index 00000000000..6fa1b015375 --- /dev/null +++ b/app/Bus/Events/User/UserFailedTwoAuthEvent.php @@ -0,0 +1,65 @@ + + */ +final class UserFailedTwoAuthEvent implements ActionInterface, UserEventInterface +{ + /** + * The user that failed two auth. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * Create a new user failed two auth event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User failed two-factor authentication.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/User/UserLoggedInEvent.php b/app/Bus/Events/User/UserLoggedInEvent.php new file mode 100644 index 00000000000..06aafe4419d --- /dev/null +++ b/app/Bus/Events/User/UserLoggedInEvent.php @@ -0,0 +1,65 @@ + + */ +final class UserLoggedInEvent implements ActionInterface, UserEventInterface +{ + /** + * The user that logged in. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * Create a new user logged in event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User logged in.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/User/UserLoggedOutEvent.php b/app/Bus/Events/User/UserLoggedOutEvent.php new file mode 100644 index 00000000000..98370606bef --- /dev/null +++ b/app/Bus/Events/User/UserLoggedOutEvent.php @@ -0,0 +1,65 @@ + + */ +final class UserLoggedOutEvent implements ActionInterface, UserEventInterface +{ + /** + * The user that logged out. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * Create a new user logged out event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User logged out.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/User/UserPassedTwoAuthEvent.php b/app/Bus/Events/User/UserPassedTwoAuthEvent.php new file mode 100644 index 00000000000..640938e5a68 --- /dev/null +++ b/app/Bus/Events/User/UserPassedTwoAuthEvent.php @@ -0,0 +1,65 @@ + + */ +final class UserPassedTwoAuthEvent implements ActionInterface, UserEventInterface +{ + /** + * The user that passed two auth. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * Create a new user passed two auth event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User passed two-factor authentication.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/User/UserRegeneratedApiTokenEvent.php b/app/Bus/Events/User/UserRegeneratedApiTokenEvent.php new file mode 100644 index 00000000000..6dee91094fc --- /dev/null +++ b/app/Bus/Events/User/UserRegeneratedApiTokenEvent.php @@ -0,0 +1,65 @@ + + */ +final class UserRegeneratedApiTokenEvent implements ActionInterface, UserEventInterface +{ + /** + * The user that regenerated their api token. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * Create a new user regenerated api token event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User regenerated api token.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/User/UserWasCreatedEvent.php b/app/Bus/Events/User/UserWasCreatedEvent.php new file mode 100644 index 00000000000..a013352a583 --- /dev/null +++ b/app/Bus/Events/User/UserWasCreatedEvent.php @@ -0,0 +1,65 @@ + + */ +final class UserWasCreatedEvent implements ActionInterface, UserEventInterface +{ + /** + * The user that has been added. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * Create a new user was added event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User was created.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Events/User/UserWasInvitedEvent.php b/app/Bus/Events/User/UserWasInvitedEvent.php index 4bcada2f5d6..c2a65db9c18 100644 --- a/app/Bus/Events/User/UserWasInvitedEvent.php +++ b/app/Bus/Events/User/UserWasInvitedEvent.php @@ -13,10 +13,17 @@ use CachetHQ\Cachet\Models\Invite; +/** + * This is the user was invited event class. + * + * @author Joseph Cohen + * @author Graham Campbell + * @author James Brooks + */ final class UserWasInvitedEvent implements UserEventInterface { /** - * The invite that has been added. + * The invite that has been created. * * @var \CachetHQ\Cachet\Models\Invite */ @@ -33,4 +40,14 @@ public function __construct(Invite $invite) { $this->invite = $invite; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User was invited.'; + } } diff --git a/app/Bus/Events/User/UserWasRemovedEvent.php b/app/Bus/Events/User/UserWasRemovedEvent.php index d7504e495ef..d44213403e5 100644 --- a/app/Bus/Events/User/UserWasRemovedEvent.php +++ b/app/Bus/Events/User/UserWasRemovedEvent.php @@ -11,9 +11,10 @@ namespace CachetHQ\Cachet\Bus\Events\User; +use CachetHQ\Cachet\Bus\Events\ActionInterface; use CachetHQ\Cachet\Models\User; -final class UserWasRemovedEvent implements UserEventInterface +final class UserWasRemovedEvent implements ActionInterface, UserEventInterface { /** * The user that has been removed. @@ -33,4 +34,27 @@ public function __construct(User $user) { $this->user = $user; } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User was removed.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } } diff --git a/app/Bus/Events/User/UserWasWelcomedEvent.php b/app/Bus/Events/User/UserWasWelcomedEvent.php new file mode 100644 index 00000000000..3f163cc5b6a --- /dev/null +++ b/app/Bus/Events/User/UserWasWelcomedEvent.php @@ -0,0 +1,65 @@ + + */ +final class UserWasWelcomedEvent implements ActionInterface, UserEventInterface +{ + /** + * The user. + * + * @var \CachetHQ\Cachet\Models\User + */ + public $user; + + /** + * Create a new user was welcomed event instance. + * + * @param \CachetHQ\Cachet\Models\User $user + * + * @return void + */ + public function __construct(User $user) + { + $this->user = $user; + } + + /** + * Get the event description. + * + * @return string + */ + public function __toString() + { + return 'User was welcomed.'; + } + + /** + * Get the event action. + * + * @return array + */ + public function getAction() + { + return [ + 'user' => $this->user, + 'description' => (string) $this, + ]; + } +} diff --git a/app/Bus/Exceptions/Component/ComponentExceptionInterface.php b/app/Bus/Exceptions/Component/ComponentExceptionInterface.php new file mode 100644 index 00000000000..211d81f7a71 --- /dev/null +++ b/app/Bus/Exceptions/Component/ComponentExceptionInterface.php @@ -0,0 +1,24 @@ + + */ +interface ComponentExceptionInterface extends ExceptionInterface +{ + // +} diff --git a/app/Bus/Exceptions/ComponentGroup/ComponentGroup.php b/app/Bus/Exceptions/ComponentGroup/ComponentGroup.php new file mode 100644 index 00000000000..8ca6edd05ee --- /dev/null +++ b/app/Bus/Exceptions/ComponentGroup/ComponentGroup.php @@ -0,0 +1,24 @@ + + */ +interface ComponentGroup extends ExceptionInterface +{ + // +} diff --git a/app/Bus/Exceptions/Incident/IncidentExceptionInterface.php b/app/Bus/Exceptions/Incident/IncidentExceptionInterface.php new file mode 100644 index 00000000000..f6aa9be71da --- /dev/null +++ b/app/Bus/Exceptions/Incident/IncidentExceptionInterface.php @@ -0,0 +1,24 @@ + + */ +interface IncidentExceptionInterface extends ExceptionInterface +{ + // +} diff --git a/app/Bus/Exceptions/Incident/InvalidIncidentTimestampException.php b/app/Bus/Exceptions/Incident/InvalidIncidentTimestampException.php new file mode 100644 index 00000000000..8d5d8708cd0 --- /dev/null +++ b/app/Bus/Exceptions/Incident/InvalidIncidentTimestampException.php @@ -0,0 +1,24 @@ + + */ +class InvalidIncidentTimestampException extends Exception implements IncidentExceptionInterface +{ + // +} diff --git a/app/Bus/Exceptions/IncidentUpdate/IncidentUpdateExceptionInterface.php b/app/Bus/Exceptions/IncidentUpdate/IncidentUpdateExceptionInterface.php new file mode 100644 index 00000000000..3abb87db89f --- /dev/null +++ b/app/Bus/Exceptions/IncidentUpdate/IncidentUpdateExceptionInterface.php @@ -0,0 +1,24 @@ + + */ +interface IncidentUpdateExceptionInterface extends ExceptionInterface +{ + // +} diff --git a/app/Bus/Exceptions/Metric/MetricExceptionInterface.php b/app/Bus/Exceptions/Metric/MetricExceptionInterface.php new file mode 100644 index 00000000000..51dd0f44860 --- /dev/null +++ b/app/Bus/Exceptions/Metric/MetricExceptionInterface.php @@ -0,0 +1,24 @@ + + */ +interface MetricExceptionInterface extends ExceptionInterface +{ + // +} diff --git a/app/Bus/Exceptions/MetricPoint/MetricPointExceptionInterface.php b/app/Bus/Exceptions/MetricPoint/MetricPointExceptionInterface.php new file mode 100644 index 00000000000..a0fe628cfa0 --- /dev/null +++ b/app/Bus/Exceptions/MetricPoint/MetricPointExceptionInterface.php @@ -0,0 +1,24 @@ + + */ +interface MetricPointExceptionInterface extends ExceptionInterface +{ + // +} diff --git a/app/Bus/Exceptions/Schedule/ScheduleExceptionInterface.php b/app/Bus/Exceptions/Schedule/ScheduleExceptionInterface.php new file mode 100644 index 00000000000..61059820f36 --- /dev/null +++ b/app/Bus/Exceptions/Schedule/ScheduleExceptionInterface.php @@ -0,0 +1,24 @@ + + */ +interface ScheduleExceptionInterface extends ExceptionInterface +{ + // +} diff --git a/app/Bus/Exceptions/Subscriber/SubscriberExceptionInterface.php b/app/Bus/Exceptions/Subscriber/SubscriberExceptionInterface.php new file mode 100644 index 00000000000..afee3735b88 --- /dev/null +++ b/app/Bus/Exceptions/Subscriber/SubscriberExceptionInterface.php @@ -0,0 +1,24 @@ + + */ +interface SubscriberExceptionInterface extends ExceptionInterface +{ + // +} diff --git a/app/Bus/Exceptions/User/UserExceptionInterface.php b/app/Bus/Exceptions/User/UserExceptionInterface.php new file mode 100644 index 00000000000..e0b3d8aed1c --- /dev/null +++ b/app/Bus/Exceptions/User/UserExceptionInterface.php @@ -0,0 +1,24 @@ + + */ +interface UserExceptionInterface extends ExceptionInterface +{ + // +} diff --git a/app/Bus/Handlers/Commands/Component/AddComponentCommandHandler.php b/app/Bus/Handlers/Commands/Component/AddComponentCommandHandler.php deleted file mode 100644 index 538d6391912..00000000000 --- a/app/Bus/Handlers/Commands/Component/AddComponentCommandHandler.php +++ /dev/null @@ -1,59 +0,0 @@ -filter($command)); - - event(new ComponentWasAddedEvent($component)); - - return $component; - } - - /** - * Filter the command data. - * - * @param \CachetHQ\Cachet\Bus\Commands\Incident\AddComponentCommand $command - * - * @return array - */ - protected function filter(AddComponentCommand $command) - { - $params = [ - 'name' => $command->name, - 'description' => $command->description, - 'link' => $command->link, - 'status' => $command->status, - 'enabled' => $command->enabled, - 'order' => $command->order, - 'group_id' => $command->group_id, - ]; - - return array_filter($params, function ($val) { - return $val !== null; - }); - } -} diff --git a/app/Bus/Handlers/Commands/Component/CreateComponentCommandHandler.php b/app/Bus/Handlers/Commands/Component/CreateComponentCommandHandler.php new file mode 100644 index 00000000000..867f49fbeaa --- /dev/null +++ b/app/Bus/Handlers/Commands/Component/CreateComponentCommandHandler.php @@ -0,0 +1,94 @@ + + */ +class CreateComponentCommandHandler +{ + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new remove component command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + + /** + * Handle the add component command. + * + * @param \CachetHQ\Cachet\Bus\Commands\Component\CreateComponentCommand $command + * + * @return \CachetHQ\Cachet\Models\Component + */ + public function handle(CreateComponentCommand $command) + { + $component = Component::create($this->filter($command)); + + // Sync the tags into the component. + if ($command->tags) { + collect(preg_split('/ ?, ?/', $command->tags))->filter()->map(function ($tag) { + return trim($tag); + })->pipe(function ($tags) use ($component) { + $component->attachTags($tags); + }); + } + + event(new ComponentWasCreatedEvent($this->auth->user(), $component)); + + return $component; + } + + /** + * Filter the command data. + * + * @param \CachetHQ\Cachet\Bus\Commands\Component\CreateComponentCommand $command + * + * @return array + */ + protected function filter(CreateComponentCommand $command) + { + $params = [ + 'name' => $command->name, + 'description' => $command->description, + 'link' => $command->link, + 'status' => $command->status, + 'enabled' => $command->enabled, + 'order' => $command->order, + 'group_id' => $command->group_id, + 'meta' => $command->meta, + ]; + + return array_filter($params, function ($val) { + return $val !== null; + }); + } +} diff --git a/app/Bus/Handlers/Commands/Component/RemoveComponentCommandHandler.php b/app/Bus/Handlers/Commands/Component/RemoveComponentCommandHandler.php index 80451e2753d..78e0acd7191 100644 --- a/app/Bus/Handlers/Commands/Component/RemoveComponentCommandHandler.php +++ b/app/Bus/Handlers/Commands/Component/RemoveComponentCommandHandler.php @@ -13,9 +13,29 @@ use CachetHQ\Cachet\Bus\Commands\Component\RemoveComponentCommand; use CachetHQ\Cachet\Bus\Events\Component\ComponentWasRemovedEvent; +use Illuminate\Contracts\Auth\Guard; class RemoveComponentCommandHandler { + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new remove component command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + /** * Handle the remove component command. * @@ -27,7 +47,7 @@ public function handle(RemoveComponentCommand $command) { $component = $command->component; - event(new ComponentWasRemovedEvent($component)); + event(new ComponentWasRemovedEvent($this->auth->user(), $component)); $component->delete(); } diff --git a/app/Bus/Handlers/Commands/Component/UpdateComponentCommandHandler.php b/app/Bus/Handlers/Commands/Component/UpdateComponentCommandHandler.php index 1660f41f071..f0ad1e44faa 100644 --- a/app/Bus/Handlers/Commands/Component/UpdateComponentCommandHandler.php +++ b/app/Bus/Handlers/Commands/Component/UpdateComponentCommandHandler.php @@ -12,11 +12,32 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\Component; use CachetHQ\Cachet\Bus\Commands\Component\UpdateComponentCommand; +use CachetHQ\Cachet\Bus\Events\Component\ComponentStatusWasChangedEvent; use CachetHQ\Cachet\Bus\Events\Component\ComponentWasUpdatedEvent; use CachetHQ\Cachet\Models\Component; +use Illuminate\Contracts\Auth\Guard; class UpdateComponentCommandHandler { + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new update component command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + /** * Handle the update component command. * @@ -27,10 +48,24 @@ class UpdateComponentCommandHandler public function handle(UpdateComponentCommand $command) { $component = $command->component; + $originalStatus = $component->status; + + if ($command->status && (int) $originalStatus !== (int) $command->status) { + event(new ComponentStatusWasChangedEvent($this->auth->user(), $component, $originalStatus, $command->status, $command->silent)); + } $component->update($this->filter($command)); - event(new ComponentWasUpdatedEvent($component)); + // Sync the tags into the component. + if ($command->tags) { + collect(preg_split('/ ?, ?/', $command->tags))->filter()->map(function ($tag) { + return trim($tag); + })->pipe(function ($tags) use ($component) { + $component->syncTags($tags); + }); + } + + event(new ComponentWasUpdatedEvent($this->auth->user(), $component)); return $component; } @@ -38,7 +73,7 @@ public function handle(UpdateComponentCommand $command) /** * Filter the command data. * - * @param \CachetHQ\Cachet\Bus\Commands\Incident\UpdateComponentCommand $command + * @param \CachetHQ\Cachet\Bus\Commands\Component\UpdateComponentCommand $command * * @return array */ @@ -52,6 +87,7 @@ protected function filter(UpdateComponentCommand $command) 'enabled' => $command->enabled, 'order' => $command->order, 'group_id' => $command->group_id, + 'meta' => $command->meta, ]; return array_filter($params, function ($val) { diff --git a/app/Bus/Handlers/Commands/ComponentGroup/AddComponentGroupCommandHandler.php b/app/Bus/Handlers/Commands/ComponentGroup/AddComponentGroupCommandHandler.php deleted file mode 100644 index 9066df51243..00000000000 --- a/app/Bus/Handlers/Commands/ComponentGroup/AddComponentGroupCommandHandler.php +++ /dev/null @@ -1,39 +0,0 @@ - $command->name, - 'order' => $command->order, - 'collapsed' => $command->collapsed, - ]); - - event(new ComponentGroupWasAddedEvent($group)); - - return $group; - } -} diff --git a/app/Bus/Handlers/Commands/ComponentGroup/CreateComponentGroupCommandHandler.php b/app/Bus/Handlers/Commands/ComponentGroup/CreateComponentGroupCommandHandler.php new file mode 100644 index 00000000000..2169025baab --- /dev/null +++ b/app/Bus/Handlers/Commands/ComponentGroup/CreateComponentGroupCommandHandler.php @@ -0,0 +1,60 @@ +auth = $auth; + } + + /** + * Handle the create component group command. + * + * @param \CachetHQ\Cachet\Bus\Commands\ComponentGroup\CreateComponentGroupCommand $command + * + * @return \CachetHQ\Cachet\Models\ComponentGroup + */ + public function handle(CreateComponentGroupCommand $command) + { + $group = ComponentGroup::create([ + 'name' => $command->name, + 'order' => $command->order, + 'collapsed' => $command->collapsed, + 'visible' => $command->visible, + ]); + + event(new ComponentGroupWasCreatedEvent($this->auth->user(), $group)); + + return $group; + } +} diff --git a/app/Bus/Handlers/Commands/ComponentGroup/RemoveComponentGroupCommandHandler.php b/app/Bus/Handlers/Commands/ComponentGroup/RemoveComponentGroupCommandHandler.php index d74301494f5..eef3b14e930 100644 --- a/app/Bus/Handlers/Commands/ComponentGroup/RemoveComponentGroupCommandHandler.php +++ b/app/Bus/Handlers/Commands/ComponentGroup/RemoveComponentGroupCommandHandler.php @@ -13,9 +13,29 @@ use CachetHQ\Cachet\Bus\Commands\ComponentGroup\RemoveComponentGroupCommand; use CachetHQ\Cachet\Bus\Events\ComponentGroup\ComponentGroupWasRemovedEvent; +use Illuminate\Contracts\Auth\Guard; class RemoveComponentGroupCommandHandler { + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new remove component group command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + /** * Handle the remove component group command. * @@ -27,7 +47,7 @@ public function handle(RemoveComponentGroupCommand $command) { $group = $command->group; - event(new ComponentGroupWasRemovedEvent($group)); + event(new ComponentGroupWasRemovedEvent($this->auth->user(), $group)); // Remove the group id from all component. $group->components->map(function ($component) { diff --git a/app/Bus/Handlers/Commands/ComponentGroup/UpdateComponentGroupCommandHandler.php b/app/Bus/Handlers/Commands/ComponentGroup/UpdateComponentGroupCommandHandler.php index 4ea401869f4..394b73c9340 100644 --- a/app/Bus/Handlers/Commands/ComponentGroup/UpdateComponentGroupCommandHandler.php +++ b/app/Bus/Handlers/Commands/ComponentGroup/UpdateComponentGroupCommandHandler.php @@ -13,9 +13,29 @@ use CachetHQ\Cachet\Bus\Commands\ComponentGroup\UpdateComponentGroupCommand; use CachetHQ\Cachet\Bus\Events\ComponentGroup\ComponentGroupWasUpdatedEvent; +use Illuminate\Contracts\Auth\Guard; class UpdateComponentGroupCommandHandler { + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new update component command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + /** * Handle the update component group command. * @@ -28,7 +48,7 @@ public function handle(UpdateComponentGroupCommand $command) $group = $command->group; $group->update($this->filter($command)); - event(new ComponentGroupWasUpdatedEvent($group)); + event(new ComponentGroupWasUpdatedEvent($this->auth->user(), $group)); return $group; } @@ -46,6 +66,7 @@ protected function filter(UpdateComponentGroupCommand $command) 'name' => $command->name, 'order' => $command->order, 'collapsed' => $command->collapsed, + 'visible' => $command->visible, ]; return array_filter($params, function ($val) { diff --git a/app/Bus/Handlers/Commands/Incident/CreateIncidentCommandHandler.php b/app/Bus/Handlers/Commands/Incident/CreateIncidentCommandHandler.php new file mode 100644 index 00000000000..2b3bcf77b8b --- /dev/null +++ b/app/Bus/Handlers/Commands/Incident/CreateIncidentCommandHandler.php @@ -0,0 +1,198 @@ + + */ +class CreateIncidentCommandHandler +{ + use StoresMeta; + + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * The date factory instance. + * + * @var \CachetHQ\Cachet\Services\Dates\DateFactory + */ + protected $dates; + + protected $twigConfig; + + /** + * Create a new create incident command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * @param \CachetHQ\Cachet\Services\Dates\DateFactory $dates + * + * @return void + */ + public function __construct(Guard $auth, DateFactory $dates) + { + $this->auth = $auth; + $this->dates = $dates; + + $this->twigConfig = config('cachet.twig'); + } + + /** + * Handle the create incident command. + * + * @param \CachetHQ\Cachet\Bus\Commands\Incident\CreateIncidentCommand $command + * + * @return \CachetHQ\Cachet\Models\Incident + */ + public function handle(CreateIncidentCommand $command) + { + $data = [ + 'user_id' => $this->auth->user()->id, + 'name' => $command->name, + 'status' => $command->status, + 'visible' => $command->visible, + 'stickied' => $command->stickied, + ]; + + if ($template = IncidentTemplate::where('slug', '=', $command->template)->first()) { + $data['message'] = $this->parseTemplate($template, $command); + } else { + $data['message'] = $command->message; + } + + // Link with the component. + if ($command->component_id) { + $data['component_id'] = $command->component_id; + } + + // The incident occurred at a different time. + if ($occurredAt = $command->occurred_at) { + if ($date = $this->dates->create('Y-m-d H:i', $occurredAt)) { + $data['occurred_at'] = $date; + } else { + throw new InvalidIncidentTimestampException("Unable to pass timestamp {$occurredAt}"); + } + } else { + $data['occurred_at'] = Carbon::now(); + } + + // Create the incident + $incident = Incident::create($data); + + // Store any meta? + if ($meta = $command->meta) { + $this->storeMeta($command->meta, 'incidents', $incident->id); + } + + // Update the component. + if ($component = Component::find($command->component_id)) { + execute(new UpdateComponentCommand( + Component::find($command->component_id), + null, + null, + $command->component_status, + null, + null, + null, + null, + null, + null, + true // Silent mode + )); + } + + event(new IncidentWasCreatedEvent($this->auth->user(), $incident, (bool) $command->notify)); + + return $incident; + } + + protected function sandboxedTwigTemplateData(string $templateData) + { + if (!$templateData) { + return ''; + } + + $policy = new \Twig\Sandbox\SecurityPolicy( + $this->twigConfig['tags'], + $this->twigConfig['filters'], + $this->twigConfig['methods'], + $this->twigConfig['props'], + $this->twigConfig['functions'] + ); + + $sandbox = new \Twig\Extension\SandboxExtension($policy); + + $templateBasicLoader = new Twig_Loader_Array([ + 'firstStageLoader' => $templateData, + ]); + + $sandBoxBasicLoader = new Twig_Loader_Array([ + 'secondStageLoader' => '{% sandbox %}{% include "firstStageLoader" %} {% endsandbox %}', + ]); + + $hardenedLoader = new \Twig\Loader\ChainLoader([$templateBasicLoader, $sandBoxBasicLoader]); + $twig = new Twig_Environment($hardenedLoader); + $twig->addExtension($sandbox); + + return $twig; + } + + /** + * Compiles an incident template into an incident message. + * + * @param \CachetHQ\Cachet\Models\IncidentTemplate $template + * @param \CachetHQ\Cachet\Bus\Commands\Incident\CreateIncidentCommand $command + * + * @return string + */ + protected function parseTemplate(IncidentTemplate $template, CreateIncidentCommand $command) + { + $template = $this->sandboxedTwigTemplateData($template->template); + + $vars = array_merge($command->template_vars, [ + 'incident' => [ + 'name' => $command->name, + 'status' => $command->status, + 'message' => $command->message, + 'visible' => $command->visible, + 'notify' => $command->notify, + 'stickied' => $command->stickied, + 'occurred_at' => $command->occurred_at, + 'component' => Component::find($command->component_id) ?: null, + 'component_status' => $command->component_status, + ], + ]); + + return $template->render('secondStageLoader', $vars); + } +} diff --git a/app/Bus/Handlers/Commands/Incident/RemoveIncidentCommandHandler.php b/app/Bus/Handlers/Commands/Incident/RemoveIncidentCommandHandler.php index 38196c666fa..5fa7fbf3730 100644 --- a/app/Bus/Handlers/Commands/Incident/RemoveIncidentCommandHandler.php +++ b/app/Bus/Handlers/Commands/Incident/RemoveIncidentCommandHandler.php @@ -13,9 +13,29 @@ use CachetHQ\Cachet\Bus\Commands\Incident\RemoveIncidentCommand; use CachetHQ\Cachet\Bus\Events\Incident\IncidentWasRemovedEvent; +use Illuminate\Contracts\Auth\Guard; class RemoveIncidentCommandHandler { + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new remove incident command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + /** * Handle the remove incident command. * @@ -27,7 +47,7 @@ public function handle(RemoveIncidentCommand $command) { $incident = $command->incident; - event(new IncidentWasRemovedEvent($incident)); + event(new IncidentWasRemovedEvent($this->auth->user(), $incident)); $incident->delete(); } diff --git a/app/Bus/Handlers/Commands/Incident/ReportIncidentCommandHandler.php b/app/Bus/Handlers/Commands/Incident/ReportIncidentCommandHandler.php deleted file mode 100644 index 6117074891e..00000000000 --- a/app/Bus/Handlers/Commands/Incident/ReportIncidentCommandHandler.php +++ /dev/null @@ -1,128 +0,0 @@ - - */ -class ReportIncidentCommandHandler -{ - /** - * The date factory instance. - * - * @var \CachetHQ\Cachet\Dates\DateFactory - */ - protected $dates; - - /** - * The twig bridge instance. - * - * @var \TwigBridge\Bridge - */ - protected $twig; - - /** - * Create a new report incident command handler instance. - * - * @param \CachetHQ\Cachet\Dates\DateFactory $dates - * @param \TwigBridge\Bridge $twig - * - * @return void - */ - public function __construct(DateFactory $dates, Bridge $twig) - { - $this->dates = $dates; - $this->twig = $twig; - } - - /** - * Handle the report incident command. - * - * @param \CachetHQ\Cachet\Bus\Commands\Incident\ReportIncidentCommand $command - * - * @return \CachetHQ\Cachet\Models\Incident - */ - public function handle(ReportIncidentCommand $command) - { - $data = [ - 'name' => $command->name, - 'status' => $command->status, - 'visible' => $command->visible, - ]; - - if ($command->template) { - $data['message'] = $this->parseIncidentTemplate($command->template, $command->template_vars); - } else { - $data['message'] = $command->message; - } - - // Link with the component. - if ($command->component_id) { - $data['component_id'] = $command->component_id; - } - - // The incident occurred at a different time. - if ($command->incident_date) { - $incidentDate = $this->dates->create('d/m/Y H:i', $command->incident_date); - - $data['created_at'] = $incidentDate; - $data['updated_at'] = $incidentDate; - } - - // Create the incident - $incident = Incident::create($data); - - // Update the component. - if ($command->component_id) { - Component::find($command->component_id)->update([ - 'status' => $command->component_status, - ]); - } - - $incident->notify = (bool) $command->notify; - - event(new IncidentWasReportedEvent($incident)); - - return $incident; - } - - /** - * Compiles an incident template into an incident message. - * - * @param string $templateSlug - * @param array $vars - * - * @return string - */ - protected function parseIncidentTemplate($templateSlug, $vars) - { - if ($vars === null) { - $vars = []; - } - - $this->twig->setLoader(new Twig_Loader_String()); - $template = IncidentTemplate::forSlug($templateSlug)->first(); - - return $this->twig->render($template->template, $vars); - } -} diff --git a/app/Bus/Handlers/Commands/Incident/ReportMaintenanceCommandHandler.php b/app/Bus/Handlers/Commands/Incident/ReportMaintenanceCommandHandler.php deleted file mode 100644 index 4126909d0d3..00000000000 --- a/app/Bus/Handlers/Commands/Incident/ReportMaintenanceCommandHandler.php +++ /dev/null @@ -1,65 +0,0 @@ -dates = $dates; - } - - /** - * Handle the report maintenance command. - * - * @param \CachetHQ\Cachet\Bus\Commands\Incident\ReportMaintenanceCommand $command - * - * @return \CachetHQ\Cachet\Models\Incident - */ - public function handle(ReportMaintenanceCommand $command) - { - $scheduledAt = $this->dates->create('d/m/Y H:i', $command->timestamp); - - $maintenanceEvent = Incident::create([ - 'name' => $command->name, - 'message' => $command->message, - 'scheduled_at' => $scheduledAt, - 'status' => 0, - 'visible' => 1, - ]); - - $maintenanceEvent->notify = (bool) $command->notify; - - event(new MaintenanceWasScheduledEvent($maintenanceEvent)); - - return $maintenanceEvent; - } -} diff --git a/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php b/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php index 53bc3f7f9a8..c8592025383 100644 --- a/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php +++ b/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php @@ -11,14 +11,16 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\Incident; +use CachetHQ\Cachet\Bus\Commands\Component\UpdateComponentCommand; use CachetHQ\Cachet\Bus\Commands\Incident\UpdateIncidentCommand; use CachetHQ\Cachet\Bus\Events\Incident\IncidentWasUpdatedEvent; -use CachetHQ\Cachet\Dates\DateFactory; +use CachetHQ\Cachet\Bus\Exceptions\Incident\InvalidIncidentTimestampException; +use CachetHQ\Cachet\Bus\Handlers\Traits\StoresMeta; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Incident; use CachetHQ\Cachet\Models\IncidentTemplate; -use Twig_Loader_String; -use TwigBridge\Bridge; +use CachetHQ\Cachet\Services\Dates\DateFactory; +use Illuminate\Contracts\Auth\Guard; /** * This is the update incident command handler. @@ -27,32 +29,41 @@ */ class UpdateIncidentCommandHandler { + use StoresMeta; + + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + /** * The date factory instance. * - * @var \CachetHQ\Cachet\Dates\DateFactory + * @var \CachetHQ\Cachet\Services\Dates\DateFactory */ protected $dates; /** - * The twig bridge instance. - * - * @var \TwigBridge\Bridge + * Twig configuration array. */ - protected $twig; + protected $twigConfig; /** * Create a new update incident command handler instance. * - * @param \CachetHQ\Cachet\Dates\DateFactory $dates - * @param \TwigBridge\Bridge $twig + * @param \Illuminate\Contracts\Auth\Guard $auth + * @param \CachetHQ\Cachet\Services\Dates\DateFactory $dates * * @return void */ - public function __construct(DateFactory $dates, Bridge $twig) + public function __construct(Guard $auth, DateFactory $dates) { + $this->auth = $auth; $this->dates = $dates; - $this->twig = $twig; + + $this->twigConfig = $twigConfig = config('cachet.twig'); } /** @@ -64,31 +75,48 @@ public function __construct(DateFactory $dates, Bridge $twig) */ public function handle(UpdateIncidentCommand $command) { - if ($command->template) { - $command->message = $this->parseIncidentTemplate($command->template, $command->template_vars); + if ($template = IncidentTemplate::where('slug', '=', $command->template)->first()) { + $command->message = $this->parseTemplate($template, $command); } $incident = $command->incident; - $incident->update($this->filter($command)); + $incident->fill($this->filter($command)); // The incident occurred at a different time. - if ($command->incident_date) { - $incidentDate = $this->dates->create('d/m/Y H:i', $command->incident_date); + if ($occurredAt = $command->occurred_at) { + if ($date = $this->dates->create('Y-m-d H:i', $occurredAt)) { + $incident->fill(['occurred_at' => $date]); + } else { + throw new InvalidIncidentTimestampException("Unable to pass timestamp {$occurredAt}"); + } + } + + // Rather than making lots of updates, just fill and save. + $incident->save(); - $incident->update([ - 'created_at' => $incidentDate, - 'updated_at' => $incidentDate, - ]); + // Store any meta? + if ($meta = $command->meta) { + $this->storeMeta($command->meta, 'incidents', $incident->id); } // Update the component. - if ($command->component_id) { - Component::find($command->component_id)->update([ - 'status' => $command->component_status, - ]); + if ($component = Component::find($command->component_id)) { + execute(new UpdateComponentCommand( + Component::find($command->component_id), + null, + null, + $command->component_status, + null, + null, + null, + null, + null, + null, + true // Silent mode + )); } - event(new IncidentWasUpdatedEvent($incident)); + event(new IncidentWasUpdatedEvent($this->auth->user(), $incident)); return $incident; } @@ -107,6 +135,7 @@ protected function filter(UpdateIncidentCommand $command) 'status' => $command->status, 'message' => $command->message, 'visible' => $command->visible, + 'stickied' => $command->stickied, 'component_id' => $command->component_id, 'component_status' => $command->component_status, 'notify' => $command->notify, @@ -117,19 +146,58 @@ protected function filter(UpdateIncidentCommand $command) }); } + protected function sandboxedTwigTemplateData(string $templateData) + { + $policy = new \Twig\Sandbox\SecurityPolicy( + $this->twigConfig['tags'], + $this->twigConfig['filters'], + $this->twigConfig['methods'], + $this->twigConfig['props'], + $this->twigConfig['functions'] + ); + $sandbox = new \Twig\Extension\SandboxExtension($policy); + + $templateBasicLoader = new \Twig\Loader\ArrayLoader([ + 'firstStageLoader' => $templateData, + ]); + + $sandBoxBasicLoader = new \Twig\Loader\ArrayLoader([ + 'secondStageLoader' => '{% sandbox %}{% include "firstStageLoader" %} {% endsandbox %}', + ]); + + $hardenedLoader = new \Twig\Loader\ChainLoader([$templateBasicLoader, $sandBoxBasicLoader]); + $twig = new \Twig\Environment($hardenedLoader); + $twig->addExtension($sandbox); + + return $twig; + } + /** * Compiles an incident template into an incident message. * - * @param string $templateSlug - * @param array $vars + * @param \CachetHQ\Cachet\Models\IncidentTemplate $template + * @param \CachetHQ\Cachet\Bus\Commands\Incident\UpdateIncidentCommand $command * * @return string */ - protected function parseIncidentTemplate($templateSlug, $vars) + protected function parseTemplate(IncidentTemplate $template, UpdateIncidentCommand $command) { - $this->twig->setLoader(new Twig_Loader_String()); - $template = IncidentTemplate::forSlug($templateSlug)->first(); - - return $this->twig->render($template->template, $vars); + $template = $this->sandboxedTwigTemplateData($template->template); + + $vars = array_merge($command->template_vars, [ + 'incident' => [ + 'name' => $command->name, + 'status' => $command->status, + 'message' => $command->message, + 'visible' => $command->visible, + 'notify' => $command->notify, + 'stickied' => $command->stickied, + 'occurred_at' => $command->occurred_at, + 'component' => Component::find($command->component_id) ?: null, + 'component_status' => $command->component_status, + ], + ]); + + return $template->render('secondStageLoader', $vars); } } diff --git a/app/Bus/Handlers/Commands/IncidentUpdate/CreateIncidentUpdateCommandHandler.php b/app/Bus/Handlers/Commands/IncidentUpdate/CreateIncidentUpdateCommandHandler.php new file mode 100644 index 00000000000..20dd2c84a93 --- /dev/null +++ b/app/Bus/Handlers/Commands/IncidentUpdate/CreateIncidentUpdateCommandHandler.php @@ -0,0 +1,85 @@ + + */ +class CreateIncidentUpdateCommandHandler +{ + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new report incident update command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + + /** + * Handle the report incident command. + * + * @param \CachetHQ\Cachet\Bus\Commands\IncidentUpdate\CreateIncidentUpdateCommand $command + * + * @return \CachetHQ\Cachet\Models\IncidentUpdate + */ + public function handle(CreateIncidentUpdateCommand $command) + { + $data = [ + 'incident_id' => $command->incident->id, + 'status' => $command->status, + 'message' => $command->message, + 'user_id' => $command->user->id, + ]; + + // Create the incident update. + $update = IncidentUpdate::create($data); + + // Update the original incident with the new status. + execute(new UpdateIncidentCommand( + $command->incident, + null, + $command->status, + null, + null, + null, + null, + null, + null, + null, + null, + [] + )); + + event(new IncidentUpdateWasReportedEvent($this->auth->user(), $update)); + + return $update; + } +} diff --git a/app/Bus/Handlers/Commands/IncidentUpdate/RemoveIncidentUpdateCommandHandler.php b/app/Bus/Handlers/Commands/IncidentUpdate/RemoveIncidentUpdateCommandHandler.php new file mode 100644 index 00000000000..ee5cc5b7894 --- /dev/null +++ b/app/Bus/Handlers/Commands/IncidentUpdate/RemoveIncidentUpdateCommandHandler.php @@ -0,0 +1,59 @@ + + */ +class RemoveIncidentUpdateCommandHandler +{ + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new remove incident update command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + + /** + * Handle the remove incident update command. + * + * @param \CachetHQ\Cachet\Bus\Commands\IncidentUpdate\RemoveIncidentUpdateCommand $command + * + * @return void + */ + public function handle(RemoveIncidentUpdateCommand $command) + { + $update = $command->incidentUpdate; + + event(new IncidentUpdateWasRemovedEvent($this->auth->user(), $update)); + + $update->delete(); + } +} diff --git a/app/Bus/Handlers/Commands/IncidentUpdate/UpdateIncidentUpdateCommandHandler.php b/app/Bus/Handlers/Commands/IncidentUpdate/UpdateIncidentUpdateCommandHandler.php new file mode 100644 index 00000000000..c3086ea7d74 --- /dev/null +++ b/app/Bus/Handlers/Commands/IncidentUpdate/UpdateIncidentUpdateCommandHandler.php @@ -0,0 +1,79 @@ + + */ +class UpdateIncidentUpdateCommandHandler +{ + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new update incident update command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + + /** + * Handle the update incident update command. + * + * @param \CachetHQ\Cachet\Bus\Commands\IncidentUpdate\UpdateIncidentUpdateCommand $command + * + * @return \CachetHQ\Cachet\Models\IncidentUpdate + */ + public function handle(UpdateIncidentUpdateCommand $command) + { + $command->update->update($this->filter($command)); + + event(new IncidentUpdateWasUpdatedEvent($this->auth->user(), $command->update)); + + return $command->update; + } + + /** + * Filter the command data. + * + * @param \CachetHQ\Cachet\Bus\Commands\IncidentUpdate\UpdateIncidentUpdateCommand $command + * + * @return array + */ + protected function filter(UpdateIncidentUpdateCommand $command) + { + $params = [ + 'status' => $command->status, + 'message' => $command->message, + 'user_id' => $command->user->id, + ]; + + return array_filter($params, function ($val) { + return $val !== null; + }); + } +} diff --git a/app/Bus/Handlers/Commands/Invite/ClaimInviteCommandHandler.php b/app/Bus/Handlers/Commands/Invite/ClaimInviteCommandHandler.php index ba669a8ff4f..bd2603bebbd 100644 --- a/app/Bus/Handlers/Commands/Invite/ClaimInviteCommandHandler.php +++ b/app/Bus/Handlers/Commands/Invite/ClaimInviteCommandHandler.php @@ -20,7 +20,7 @@ class ClaimInviteCommandHandler /** * Handle the claim invite command. * - * @param \CachetHQ\Cachet\Bus\Commands\User\ClaimInviteCommand $command + * @param \CachetHQ\Cachet\Bus\Commands\Invite\ClaimInviteCommand $command * * @return void */ @@ -28,8 +28,7 @@ public function handle(ClaimInviteCommand $command) { $invite = $command->invite; - $invite->claimed_at = Carbon::now(); - $invite->save(); + $invite->update(['claimed_at' => Carbon::now()]); event(new InviteWasClaimedEvent($invite)); } diff --git a/app/Bus/Handlers/Commands/Metric/AddMetricCommandHandler.php b/app/Bus/Handlers/Commands/Metric/CreateMetricCommandHandler.php similarity index 55% rename from app/Bus/Handlers/Commands/Metric/AddMetricCommandHandler.php rename to app/Bus/Handlers/Commands/Metric/CreateMetricCommandHandler.php index a5733b280be..cc410ce0b24 100644 --- a/app/Bus/Handlers/Commands/Metric/AddMetricCommandHandler.php +++ b/app/Bus/Handlers/Commands/Metric/CreateMetricCommandHandler.php @@ -11,20 +11,40 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\Metric; -use CachetHQ\Cachet\Bus\Commands\Metric\AddMetricCommand; -use CachetHQ\Cachet\Bus\Events\Metric\MetricWasAddedEvent; +use CachetHQ\Cachet\Bus\Commands\Metric\CreateMetricCommand; +use CachetHQ\Cachet\Bus\Events\Metric\MetricWasCreatedEvent; use CachetHQ\Cachet\Models\Metric; +use Illuminate\Contracts\Auth\Guard; -class AddMetricCommandHandler +class CreateMetricCommandHandler { + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new add metric command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + /** * Handle the add metric command. * - * @param \CachetHQ\Cachet\Bus\Commands\Metric\AddMetricCommand $command + * @param \CachetHQ\Cachet\Bus\Commands\Metric\CreateMetricCommand $command * * @return \CachetHQ\Cachet\Models\Metric */ - public function handle(AddMetricCommand $command) + public function handle(CreateMetricCommand $command) { $metric = Metric::create([ 'name' => $command->name, @@ -37,9 +57,10 @@ public function handle(AddMetricCommand $command) 'default_view' => $command->default_view, 'threshold' => $command->threshold, 'order' => $command->order, + 'visible' => $command->visible, ]); - event(new MetricWasAddedEvent($metric)); + event(new MetricWasCreatedEvent($this->auth->user(), $metric)); return $metric; } diff --git a/app/Bus/Handlers/Commands/Metric/AddMetricPointCommandHandler.php b/app/Bus/Handlers/Commands/Metric/CreateMetricPointCommandHandler.php similarity index 51% rename from app/Bus/Handlers/Commands/Metric/AddMetricPointCommandHandler.php rename to app/Bus/Handlers/Commands/Metric/CreateMetricPointCommandHandler.php index 17b6dadea89..8fdbe1ca21c 100644 --- a/app/Bus/Handlers/Commands/Metric/AddMetricPointCommandHandler.php +++ b/app/Bus/Handlers/Commands/Metric/CreateMetricPointCommandHandler.php @@ -11,41 +11,51 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\Metric; -use CachetHQ\Cachet\Bus\Commands\Metric\AddMetricPointCommand; -use CachetHQ\Cachet\Bus\Events\Metric\MetricPointWasAddedEvent; -use CachetHQ\Cachet\Dates\DateFactory; +use CachetHQ\Cachet\Bus\Commands\Metric\CreateMetricPointCommand; +use CachetHQ\Cachet\Bus\Events\Metric\MetricPointWasCreatedEvent; use CachetHQ\Cachet\Models\MetricPoint; +use CachetHQ\Cachet\Services\Dates\DateFactory; use Carbon\Carbon; +use Illuminate\Contracts\Auth\Guard; -class AddMetricPointCommandHandler +class CreateMetricPointCommandHandler { + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + /** * The date factory instance. * - * @var \CachetHQ\Cachet\Dates\DateFactory + * @var \CachetHQ\Cachet\Services\Dates\DateFactory */ protected $dates; /** * Create a new add metric point command handler instance. * - * @param \CachetHQ\Cachet\Dates\DateFactory $dates + * @param \Illuminate\Contracts\Auth\Guard $auth + * @param \CachetHQ\Cachet\Services\Dates\DateFactory $dates * * @return void */ - public function __construct(DateFactory $dates) + public function __construct(Guard $auth, DateFactory $dates) { + $this->auth = $auth; $this->dates = $dates; } /** * Handle the add metric point command. * - * @param \CachetHQ\Cachet\Bus\Commands\Metric\AddMetricPointCommand $command + * @param \CachetHQ\Cachet\Bus\Commands\Metric\CreateMetricPointCommand $command * * @return \CachetHQ\Cachet\Models\MetricPoint */ - public function handle(AddMetricPointCommand $command) + public function handle(CreateMetricPointCommand $command) { $metric = $command->metric; $createdAt = $command->created_at; @@ -55,17 +65,23 @@ public function handle(AddMetricPointCommand $command) $point->increment('counter', 1); - event(new MetricPointWasAddedEvent($point)); + event(new MetricPointWasCreatedEvent($this->auth->user(), $point)); return $point; } - protected function findOrCreatePoint(AddMetricPointCommand $command) + /** + * Find or create a metric point. + * + * @param \CachetHQ\Cachet\Bus\Commands\Metric\CreateMetricPointCommand $command + * + * @return \CachetHQ\Cachet\Models\MetricPoint + */ + protected function findOrCreatePoint(CreateMetricPointCommand $command) { - $buffer = Carbon::now()->subMinutes($command->metric->threshold); - $point = MetricPoint::where('metric_id', $command->metric->id)->where('value', $command->value)->where('created_at', '>=', $buffer)->first(); + $buffer = Carbon::now()->subMinutes($command->metric->threshold - 1)->startOfMinute(); - if ($point) { + if ($point = MetricPoint::where('metric_id', '=', $command->metric->id)->where('value', '=', $command->value)->where('created_at', '>=', $buffer)->first()) { return $point; } diff --git a/app/Bus/Handlers/Commands/Metric/RemoveMetricCommandHandler.php b/app/Bus/Handlers/Commands/Metric/RemoveMetricCommandHandler.php index cd15e0ebf5d..478d29523bc 100644 --- a/app/Bus/Handlers/Commands/Metric/RemoveMetricCommandHandler.php +++ b/app/Bus/Handlers/Commands/Metric/RemoveMetricCommandHandler.php @@ -14,9 +14,29 @@ use CachetHQ\Cachet\Bus\Commands\Metric\RemoveMetricCommand; use CachetHQ\Cachet\Bus\Events\Metric\MetricWasRemovedEvent; use CachetHQ\Cachet\Models\Metric; +use Illuminate\Contracts\Auth\Guard; class RemoveMetricCommandHandler { + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new remove metric command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + /** * Handle the remove metric command. * @@ -28,7 +48,7 @@ public function handle(RemoveMetricCommand $command) { $metric = $command->metric; - event(new MetricWasRemovedEvent($metric)); + event(new MetricWasRemovedEvent($this->auth->user(), $metric)); $metric->delete(); } diff --git a/app/Bus/Handlers/Commands/Metric/RemoveMetricPointCommandHandler.php b/app/Bus/Handlers/Commands/Metric/RemoveMetricPointCommandHandler.php index f7d6f6d7a26..7679942ee5b 100644 --- a/app/Bus/Handlers/Commands/Metric/RemoveMetricPointCommandHandler.php +++ b/app/Bus/Handlers/Commands/Metric/RemoveMetricPointCommandHandler.php @@ -14,9 +14,29 @@ use CachetHQ\Cachet\Bus\Commands\Metric\RemoveMetricPointCommand; use CachetHQ\Cachet\Bus\Events\Metric\MetricPointWasRemovedEvent; use CachetHQ\Cachet\Models\Metric; +use Illuminate\Contracts\Auth\Guard; class RemoveMetricPointCommandHandler { + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new remove metric point command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + /** * Handle the remove metric point command. * @@ -28,7 +48,7 @@ public function handle(RemoveMetricPointCommand $command) { $metricPoint = $command->metricPoint; - event(new MetricPointWasRemovedEvent($metricPoint)); + event(new MetricPointWasRemovedEvent($this->auth->user(), $metricPoint)); $metricPoint->delete(); } diff --git a/app/Bus/Handlers/Commands/Metric/UpdateMetricCommandHandler.php b/app/Bus/Handlers/Commands/Metric/UpdateMetricCommandHandler.php index e8abda24281..1ba3636be28 100644 --- a/app/Bus/Handlers/Commands/Metric/UpdateMetricCommandHandler.php +++ b/app/Bus/Handlers/Commands/Metric/UpdateMetricCommandHandler.php @@ -14,9 +14,29 @@ use CachetHQ\Cachet\Bus\Commands\Metric\UpdateMetricCommand; use CachetHQ\Cachet\Bus\Events\Metric\MetricWasUpdatedEvent; use CachetHQ\Cachet\Models\Metric; +use Illuminate\Contracts\Auth\Guard; class UpdateMetricCommandHandler { + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new update metric command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + /** * Handle the update metric command. * @@ -30,7 +50,7 @@ public function handle(UpdateMetricCommand $command) $metric->update($this->filter($command)); - event(new MetricWasUpdatedEvent($metric)); + event(new MetricWasUpdatedEvent($this->auth->user(), $metric)); return $metric; } @@ -55,6 +75,7 @@ protected function filter(UpdateMetricCommand $command) 'default_view' => $command->default_view, 'threshold' => $command->threshold, 'order' => $command->order, + 'visible' => $command->visible, ]; return array_filter($params, function ($val) { diff --git a/app/Bus/Handlers/Commands/Metric/UpdateMetricPointCommandHandler.php b/app/Bus/Handlers/Commands/Metric/UpdateMetricPointCommandHandler.php index aec34b63101..f61e1733375 100644 --- a/app/Bus/Handlers/Commands/Metric/UpdateMetricPointCommandHandler.php +++ b/app/Bus/Handlers/Commands/Metric/UpdateMetricPointCommandHandler.php @@ -13,26 +13,36 @@ use CachetHQ\Cachet\Bus\Commands\Metric\UpdateMetricPointCommand; use CachetHQ\Cachet\Bus\Events\Metric\MetricPointWasUpdatedEvent; -use CachetHQ\Cachet\Dates\DateFactory; +use CachetHQ\Cachet\Services\Dates\DateFactory; +use Illuminate\Contracts\Auth\Guard; class UpdateMetricPointCommandHandler { + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + /** * The date factory instance. * - * @var \CachetHQ\Cachet\Dates\DateFactory + * @var \CachetHQ\Cachet\Services\Dates\DateFactory */ protected $dates; /** * Create a new update metric point command handler instance. * - * @param \CachetHQ\Cachet\Dates\DateFactory $dates + * @param \Illuminate\Contracts\Auth\Guard $auth + * @param \CachetHQ\Cachet\Services\Dates\DateFactory $dates * * @return void */ - public function __construct(DateFactory $dates) + public function __construct(Guard $auth, DateFactory $dates) { + $this->auth = $auth; $this->dates = $dates; } @@ -60,7 +70,7 @@ public function handle(UpdateMetricPointCommand $command) $point->update($data); - event(new MetricPointWasUpdatedEvent($point)); + event(new MetricPointWasUpdatedEvent($this->auth->user(), $point)); return $point; } diff --git a/app/Bus/Handlers/Commands/Schedule/CreateScheduleCommandHandler.php b/app/Bus/Handlers/Commands/Schedule/CreateScheduleCommandHandler.php new file mode 100644 index 00000000000..9069eadb9c0 --- /dev/null +++ b/app/Bus/Handlers/Commands/Schedule/CreateScheduleCommandHandler.php @@ -0,0 +1,107 @@ + + */ +class CreateScheduleCommandHandler +{ + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * The date factory instance. + * + * @var \CachetHQ\Cachet\Services\Dates\DateFactory + */ + protected $dates; + + /** + * Create a new update schedule command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * @param \CachetHQ\Cachet\Services\Dates\DateFactory $dates + * + * @return void + */ + public function __construct(Guard $auth, DateFactory $dates) + { + $this->auth = $auth; + $this->dates = $dates; + } + + /** + * Handle the create schedule command. + * + * @param \CachetHQ\Cachet\Bus\Commands\Schedule\CreateScheduleCommand $command + * + * @return \CachetHQ\Cachet\Models\Schedule + */ + public function handle(CreateScheduleCommand $command) + { + try { + $schedule = Schedule::create($this->filter($command)); + event(new ScheduleWasCreatedEvent($this->auth->user(), $schedule, (bool) $command->notify)); + } catch (InvalidArgumentException $e) { + throw new ValidationException(new MessageBag([$e->getMessage()])); + } + + return $schedule; + } + + /** + * Filter the command data. + * + * @param \CachetHQ\Cachet\Bus\Commands\Schedule\CreateScheduleCommand $command + * + * @return array + */ + protected function filter(CreateScheduleCommand $command) + { + $scheduledAt = $this->dates->create('Y-m-d H:i', $command->scheduled_at); + + if ($completedAt = $command->completed_at) { + $completedAt = $this->dates->create('Y-m-d H:i', $command->completed_at); + } + + $params = [ + 'name' => $command->name, + 'message' => $command->message, + 'status' => $command->status, + 'scheduled_at' => $scheduledAt, + 'completed_at' => $completedAt, + 'notify' => $command->notify, + ]; + + $availableParams = array_filter($params, function ($val) { + return $val !== null && $val !== ''; + }); + + return $availableParams; + } +} diff --git a/app/Bus/Handlers/Commands/Schedule/DeleteScheduleCommandHandler.php b/app/Bus/Handlers/Commands/Schedule/DeleteScheduleCommandHandler.php new file mode 100644 index 00000000000..cf5f62278a5 --- /dev/null +++ b/app/Bus/Handlers/Commands/Schedule/DeleteScheduleCommandHandler.php @@ -0,0 +1,59 @@ + + */ +class DeleteScheduleCommandHandler +{ + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new delete schedule command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + + /** + * Handle the delete schedule command. + * + * @param \CachetHQ\Cachet\Bus\Commands\Schedule\DeleteScheduleCommand $command + * + * @return void + */ + public function handle(DeleteScheduleCommand $command) + { + $schedule = $command->schedule; + + event(new ScheduleWasRemovedEvent($this->auth->user(), $schedule)); + + $schedule->delete(); + } +} diff --git a/app/Bus/Handlers/Commands/Schedule/UpdateScheduleCommandHandler.php b/app/Bus/Handlers/Commands/Schedule/UpdateScheduleCommandHandler.php new file mode 100644 index 00000000000..72f74328010 --- /dev/null +++ b/app/Bus/Handlers/Commands/Schedule/UpdateScheduleCommandHandler.php @@ -0,0 +1,102 @@ + + */ +class UpdateScheduleCommandHandler +{ + /** + * The authentication guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * The date factory instance. + * + * @var \CachetHQ\Cachet\Services\Dates\DateFactory + */ + protected $dates; + + /** + * Create a new update schedule command handler instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * @param \CachetHQ\Cachet\Services\Dates\DateFactory $dates + * + * @return void + */ + public function __construct(Guard $auth, DateFactory $dates) + { + $this->auth = $auth; + $this->dates = $dates; + } + + /** + * Handle the update schedule command. + * + * @param \CachetHQ\Cachet\Bus\Commands\Schedule\UpdateScheduleCommand $command + * + * @return \CachetHQ\Cachet\Models\Schedule + */ + public function handle(UpdateScheduleCommand $command) + { + $schedule = $command->schedule; + + $schedule->update($this->filter($command)); + + event(new ScheduleWasUpdatedEvent($this->auth->user(), $schedule)); + + return $schedule; + } + + /** + * Filter the command data. + * + * @param \CachetHQ\Cachet\Bus\Commands\Schedule\UpdateScheduleCommand $command + * + * @return array + */ + protected function filter(UpdateScheduleCommand $command) + { + $params = [ + 'name' => $command->name, + 'message' => $command->message, + 'status' => $command->status, + ]; + + if ($scheduledAt = $command->scheduled_at) { + $params['scheduled_at'] = $this->dates->create('Y-m-d H:i', $scheduledAt); + } + + if ($completedAt = $command->completed_at) { + $params['completed_at'] = $this->dates->create('Y-m-d H:i', $completedAt); + } + + $availableParams = array_filter($params, function ($val) { + return $val !== null; + }); + + return $availableParams; + } +} diff --git a/app/Bus/Handlers/Commands/Subscriber/SubscribeSubscriberCommandHandler.php b/app/Bus/Handlers/Commands/Subscriber/SubscribeSubscriberCommandHandler.php index a4554210e71..1dde43da4a8 100644 --- a/app/Bus/Handlers/Commands/Subscriber/SubscribeSubscriberCommandHandler.php +++ b/app/Bus/Handlers/Commands/Subscriber/SubscribeSubscriberCommandHandler.php @@ -17,12 +17,13 @@ use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Subscriber; use CachetHQ\Cachet\Models\Subscription; +use CachetHQ\Cachet\Notifications\Subscriber\VerifySubscriptionNotification; /** * This is the subscribe subscriber command handler. * * @author James Brooks - * @author Joe Cohen + * @author Joseph Cohen * @author Graham Campbell */ class SubscribeSubscriberCommandHandler @@ -36,7 +37,7 @@ class SubscribeSubscriberCommandHandler */ public function handle(SubscribeSubscriberCommand $command) { - if ($subscriber = Subscriber::where('email', $command->email)->first()) { + if ($subscriber = Subscriber::where('email', '=', $command->email)->first()) { return $subscriber; } @@ -44,24 +45,28 @@ public function handle(SubscribeSubscriberCommand $command) // Decide what to subscribe the subscriber to. if ($subscriptions = $command->subscriptions) { - $subscriptions = Component::whereIn('id', $subscriptions); + $components = Component::whereIn('id', $subscriptions)->get(); } else { - $subscriptions = Component::all(); + $components = Component::all(); } - foreach ($subscriptions as $component) { + $components->each(function ($component) use ($subscriber) { Subscription::create([ 'subscriber_id' => $subscriber->id, 'component_id' => $component->id, ]); - } + }); if ($command->verified) { - dispatch(new VerifySubscriberCommand($subscriber)); + execute(new VerifySubscriberCommand($subscriber)); } else { - event(new SubscriberHasSubscribedEvent($subscriber)); + $subscriber->notify(new VerifySubscriptionNotification()); } + event(new SubscriberHasSubscribedEvent($subscriber)); + + $subscriber->load('subscriptions'); + return $subscriber; } } diff --git a/app/Bus/Handlers/Commands/Subscriber/UnsubscribeSubscriberCommandHandler.php b/app/Bus/Handlers/Commands/Subscriber/UnsubscribeSubscriberCommandHandler.php index 7dac8828fdd..be0dd021752 100644 --- a/app/Bus/Handlers/Commands/Subscriber/UnsubscribeSubscriberCommandHandler.php +++ b/app/Bus/Handlers/Commands/Subscriber/UnsubscribeSubscriberCommandHandler.php @@ -13,8 +13,14 @@ use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriberCommand; use CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasUnsubscribedEvent; -use CachetHQ\Cachet\Models\Subscriber; +/** + * This is the unsubscribe subscriber command class. + * + * @author Joseph Cohem + * @author Graham Campbell + * @author James Brooks + */ class UnsubscribeSubscriberCommandHandler { /** @@ -28,8 +34,12 @@ public function handle(UnsubscribeSubscriberCommand $command) { $subscriber = $command->subscriber; + // First remove subscriptions. + $subscriber->subscriptions()->delete(); + event(new SubscriberHasUnsubscribedEvent($subscriber)); + // Then remove the subscriber. $subscriber->delete(); } } diff --git a/app/Bus/Handlers/Commands/Subscriber/UpdateSubscriberSubscriptionCommandHandler.php b/app/Bus/Handlers/Commands/Subscriber/UpdateSubscriberSubscriptionCommandHandler.php index 6ac9d2c0b02..5e8a1dd5a8c 100644 --- a/app/Bus/Handlers/Commands/Subscriber/UpdateSubscriberSubscriptionCommandHandler.php +++ b/app/Bus/Handlers/Commands/Subscriber/UpdateSubscriberSubscriptionCommandHandler.php @@ -36,7 +36,7 @@ public function handle(UpdateSubscriberSubscriptionCommand $command) $subscriber = $command->subscriber; $subscriptions = $command->subscriptions ?: []; - $components = Component::all(); + $components = Component::enabled()->get(); $updateSubscriptions = $components->filter(function ($item) use ($subscriptions) { return in_array($item->id, $subscriptions); @@ -47,12 +47,12 @@ public function handle(UpdateSubscriberSubscriptionCommand $command) $subscriber->subscriptions()->delete(); if (!$updateSubscriptions->isEmpty()) { - foreach ($updateSubscriptions as $subscription) { + $updateSubscriptions->each(function ($subscription) use ($subscriber) { Subscription::firstOrCreate([ 'subscriber_id' => $subscriber->id, 'component_id' => $subscription->id, ]); - } + }); } $subscriber->save(); diff --git a/app/Bus/Handlers/Commands/Subscriber/VerifySubscriberCommandHandler.php b/app/Bus/Handlers/Commands/Subscriber/VerifySubscriberCommandHandler.php index b5c104f681b..d56f928f545 100644 --- a/app/Bus/Handlers/Commands/Subscriber/VerifySubscriberCommandHandler.php +++ b/app/Bus/Handlers/Commands/Subscriber/VerifySubscriberCommandHandler.php @@ -30,8 +30,7 @@ public function handle(VerifySubscriberCommand $command) $subscriber = $command->subscriber; // Mark the subscriber as verified. - $subscriber->verified_at = Carbon::now(); - $subscriber->save(); + $subscriber->update(['verified_at' => Carbon::now()]); event(new SubscriberHasVerifiedEvent($subscriber)); } diff --git a/app/Bus/Handlers/Commands/System/Config/UpdateConfigCommandHandler.php b/app/Bus/Handlers/Commands/System/Config/UpdateConfigCommandHandler.php new file mode 100644 index 00000000000..ff7d1f4e101 --- /dev/null +++ b/app/Bus/Handlers/Commands/System/Config/UpdateConfigCommandHandler.php @@ -0,0 +1,68 @@ + + */ +class UpdateConfigCommandHandler +{ + /** + * Handle update config command handler instance. + * + * @param \CachetHQ\Cachet\Bus\Commands\System\Config\UpdateConfigCommand $command + * + * @return void + */ + public function handle(UpdateConfigCommand $command) + { + foreach ($command->values as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Writes to the .env file with given parameters. + * + * @param string $key + * @param mixed $value + * + * @return void + */ + protected function writeEnv($key, $value) + { + $dir = app()->environmentPath(); + $file = app()->environmentFile(); + $path = "{$dir}/{$file}"; + + try { + (new Dotenv($dir, $file))->load(); + + $envKey = strtoupper($key); + $envValue = env($envKey) ?: 'null'; + + file_put_contents($path, str_replace( + "{$envKey}={$envValue}", + "{$envKey}={$value}", + file_get_contents($path) + )); + } catch (InvalidPathException $e) { + throw $e; + } + } +} diff --git a/app/Bus/Handlers/Commands/User/AddTeamMemberCommandHandler.php b/app/Bus/Handlers/Commands/User/CreateUserCommandHandler.php similarity index 58% rename from app/Bus/Handlers/Commands/User/AddTeamMemberCommandHandler.php rename to app/Bus/Handlers/Commands/User/CreateUserCommandHandler.php index ff87e2091f3..9ae22e67b84 100644 --- a/app/Bus/Handlers/Commands/User/AddTeamMemberCommandHandler.php +++ b/app/Bus/Handlers/Commands/User/CreateUserCommandHandler.php @@ -11,20 +11,25 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\User; -use CachetHQ\Cachet\Bus\Commands\User\AddTeamMemberCommand; -use CachetHQ\Cachet\Bus\Events\User\UserWasAddedEvent; +use CachetHQ\Cachet\Bus\Commands\User\CreateUserCommand; +use CachetHQ\Cachet\Bus\Events\User\UserWasCreatedEvent; use CachetHQ\Cachet\Models\User; -class AddTeamMemberCommandHandler +/** + * This is the create user command handler. + * + * @author James Brooks + */ +class CreateUserCommandHandler { /** - * Handle the add team member command. + * Handle the add user command. * - * @param \CachetHQ\Cachet\Bus\Commands\User\AddTeamMemberCommand $command + * @param \CachetHQ\Cachet\Bus\Commands\User\CreateUserCommand $command * * @return \CachetHQ\Cachet\Models\User */ - public function handle(AddTeamMemberCommand $command) + public function handle(CreateUserCommand $command) { $user = User::create([ 'username' => $command->username, @@ -33,7 +38,7 @@ public function handle(AddTeamMemberCommand $command) 'level' => $command->level, ]); - event(new UserWasAddedEvent($user)); + event(new UserWasCreatedEvent($user)); return $user; } diff --git a/app/Bus/Handlers/Commands/User/GenerateApiTokenCommandHandler.php b/app/Bus/Handlers/Commands/User/GenerateApiTokenCommandHandler.php index 99efbe41e3a..f7b8ab53909 100644 --- a/app/Bus/Handlers/Commands/User/GenerateApiTokenCommandHandler.php +++ b/app/Bus/Handlers/Commands/User/GenerateApiTokenCommandHandler.php @@ -12,6 +12,7 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\User; use CachetHQ\Cachet\Bus\Commands\User\GenerateApiTokenCommand; +use CachetHQ\Cachet\Bus\Events\User\UserRegeneratedApiTokenEvent; use CachetHQ\Cachet\Models\User; class GenerateApiTokenCommandHandler @@ -27,9 +28,8 @@ public function handle(GenerateApiTokenCommand $command) { $user = $command->user; - $user->api_key = User::generateApiKey(); - $user->save(); + $user->update(['api_key' => User::generateApiKey()]); - //event(new GeneratedApiTokenEvent($user)); + event(new UserRegeneratedApiTokenEvent($user)); } } diff --git a/app/Bus/Handlers/Commands/User/InviteTeamMemberCommandHandler.php b/app/Bus/Handlers/Commands/User/InviteUserCommandHandler.php similarity index 60% rename from app/Bus/Handlers/Commands/User/InviteTeamMemberCommandHandler.php rename to app/Bus/Handlers/Commands/User/InviteUserCommandHandler.php index 77eebe6579e..164a4220308 100644 --- a/app/Bus/Handlers/Commands/User/InviteTeamMemberCommandHandler.php +++ b/app/Bus/Handlers/Commands/User/InviteUserCommandHandler.php @@ -11,26 +11,34 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\User; -use CachetHQ\Cachet\Bus\Commands\User\InviteTeamMemberCommand; +use CachetHQ\Cachet\Bus\Commands\User\InviteUserCommand; use CachetHQ\Cachet\Bus\Events\User\UserWasInvitedEvent; use CachetHQ\Cachet\Models\Invite; +use CachetHQ\Cachet\Notifications\User\InviteUserNotification; -class InviteTeamMemberCommandHandler +/** + * This is the invite user command handler. + * + * @author James Brooks + */ +class InviteUserCommandHandler { /** * Handle the invite team member command. * - * @param \CachetHQ\Cachet\Bus\Commands\User\InviteTeamMemberCommand $command + * @param \CachetHQ\Cachet\Bus\Commands\User\InviteUserCommand $command * * @return void */ - public function handle(InviteTeamMemberCommand $command) + public function handle(InviteUserCommand $command) { foreach ($command->emails as $email) { $invite = Invite::create([ 'email' => $email, ]); + $invite->notify(new InviteUserNotification()); + event(new UserWasInvitedEvent($invite)); } } diff --git a/app/Bus/Handlers/Commands/User/SignupUserCommandHandler.php b/app/Bus/Handlers/Commands/User/SignupUserCommandHandler.php index 740b8a4c0ea..bb274a2faac 100644 --- a/app/Bus/Handlers/Commands/User/SignupUserCommandHandler.php +++ b/app/Bus/Handlers/Commands/User/SignupUserCommandHandler.php @@ -12,7 +12,7 @@ namespace CachetHQ\Cachet\Bus\Handlers\Commands\User; use CachetHQ\Cachet\Bus\Commands\User\SignupUserCommand; -use CachetHQ\Cachet\Bus\Events\User\UserWasAddedEvent; +use CachetHQ\Cachet\Bus\Events\User\UserWasCreatedEvent; use CachetHQ\Cachet\Models\User; class SignupUserCommandHandler @@ -33,7 +33,7 @@ public function handle(SignupUserCommand $command) 'level' => User::LEVEL_USER, ]); - event(new UserWasAddedEvent($user)); + event(new UserWasCreatedEvent($user)); return $user; } diff --git a/app/Bus/Handlers/Commands/User/WelcomeUserCommandHandler.php b/app/Bus/Handlers/Commands/User/WelcomeUserCommandHandler.php new file mode 100644 index 00000000000..d0f1e505511 --- /dev/null +++ b/app/Bus/Handlers/Commands/User/WelcomeUserCommandHandler.php @@ -0,0 +1,37 @@ + + */ +class WelcomeUserCommandHandler +{ + /** + * Handle the welcome user command. + * + * @param \CachetHQ\Cachet\Bus\Commands\User\WelcomeUserCommand $command + * + * @return void + */ + public function handle(WelcomeUserCommand $command) + { + $command->user->update(['welcomed' => true]); + + event(new UserWasWelcomedEvent($command->user)); + } +} diff --git a/app/Bus/Handlers/Events/ActionStorageHandler.php b/app/Bus/Handlers/Events/ActionStorageHandler.php new file mode 100644 index 00000000000..3ccc7a0fbe3 --- /dev/null +++ b/app/Bus/Handlers/Events/ActionStorageHandler.php @@ -0,0 +1,49 @@ + + * @author James Brooks + */ +class ActionStorageHandler +{ + /** + * Handle the any actions that need storing. + * + * @param \CachetHQ\Cachet\Bus\Events\ActionInterface $event + * + * @return void + */ + public function handle(ActionInterface $event) + { + $data = $event->getAction(); + + $action = [ + 'class_name' => get_class($event), + 'user_id' => $data['user']->id, + 'username' => $data['user']->username, + 'description' => $data['description'], + ]; + + if (isset($data['information'])) { + $action['information'] = $data['information']; + } + + Action::create($action); + } +} diff --git a/app/Bus/Handlers/Events/Beacon/LogBeaconFailedHandler.php b/app/Bus/Handlers/Events/Beacon/LogBeaconFailedHandler.php new file mode 100644 index 00000000000..f69cf49f2c0 --- /dev/null +++ b/app/Bus/Handlers/Events/Beacon/LogBeaconFailedHandler.php @@ -0,0 +1,34 @@ + + */ +class LogBeaconFailedHandler +{ + /** + * Handle the event. + * + * @param \CachetHQ\Cachet\Bus\Events\Beacon\BeaconFailedToSendEvent $event + * + * @return void + */ + public function handle(BeaconFailedToSendEvent $event) + { + logger('Beacon failed.'); + } +} diff --git a/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php b/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php index 38dd9689f71..6ecdbfca3a0 100644 --- a/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php +++ b/app/Bus/Handlers/Events/Component/SendComponentUpdateEmailNotificationHandler.php @@ -11,21 +11,20 @@ namespace CachetHQ\Cachet\Bus\Handlers\Events\Component; -use CachetHQ\Cachet\Bus\Events\Component\ComponentWasUpdatedEvent; +use CachetHQ\Cachet\Bus\Events\Component\ComponentStatusWasChangedEvent; +use CachetHQ\Cachet\Integrations\Contracts\System; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Subscriber; -use Illuminate\Contracts\Mail\MailQueue; -use Illuminate\Mail\Message; -use McCool\LaravelAutoPresenter\Facades\AutoPresenter; +use CachetHQ\Cachet\Notifications\Component\ComponentStatusChangedNotification; class SendComponentUpdateEmailNotificationHandler { /** - * The mailer instance. + * The system instance. * - * @var \Illuminate\Contracts\Mail\Mailer + * @var \CachetHQ\Cachet\Integrations\Contracts\System */ - protected $mailer; + protected $system; /** * The subscriber instance. @@ -37,34 +36,43 @@ class SendComponentUpdateEmailNotificationHandler /** * Create a new send incident email notification handler. * - * @param \Illuminate\Contracts\Mail\Mailer $mailer * @param \CachetHQ\Cachet\Models\Subscriber $subscriber * * @return void */ - public function __construct(MailQueue $mailer, Subscriber $subscriber) + public function __construct(System $system, Subscriber $subscriber) { - $this->mailer = $mailer; + $this->system = $system; $this->subscriber = $subscriber; } /** * Handle the event. * - * @param \CachetHQ\Cachet\Bus\Events\Component\ComponentWasUpdatedEvent $event + * @param \CachetHQ\Cachet\Bus\Events\Component\ComponentStatusWasChangedEvent $event * * @return void */ - public function handle(ComponentWasUpdatedEvent $event) + public function handle(ComponentStatusWasChangedEvent $event) { $component = $event->component; + // If we're silent or the notifications are suppressed don't send this. + if ($event->silent || !$this->system->canNotifySubscribers()) { + return; + } + + // Don't email anything if the status hasn't changed. + if ($event->original_status === $event->new_status) { + return; + } + // First notify all global subscribers. $globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get(); - foreach ($globalSubscribers as $subscriber) { - $this->notify($component, $subscriber); - } + $globalSubscribers->each(function ($subscriber) use ($component, $event) { + $subscriber->notify(new ComponentStatusChangedNotification($component, $event->new_status)); + }); $notified = $globalSubscribers->pluck('id')->all(); @@ -77,37 +85,8 @@ public function handle(ComponentWasUpdatedEvent $event) return in_array($subscriber->id, $notified); }); - foreach ($componentSubscribers as $subscriber) { - $this->notify($component, $subscriber); - } - } - - /** - * Send notification to subscriber. - * - * @param \CachetHQ\Cachet\Models\Component $component - * @param \CachetHQ\Cachet\Models\Subscriber $subscriber - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function notify(Component $component, Subscriber $subscriber) - { - $component = AutoPresenter::decorate($component); - - $mail = [ - 'subject' => trans('cachet.subscriber.email.component.subject'), - 'component_name' => $component->name, - 'component_human_status' => $component->human_status, - ]; - - $mail['email'] = $subscriber->email; - $mail['manage_link'] = route('subscribe.manage', ['code' => $subscriber->verify_code]); - - $this->mailer->queue([ - 'html' => 'emails.components.update-html', - 'text' => 'emails.components.update-text', - ], $mail, function (Message $message) use ($mail) { - $message->to($mail['email'])->subject($mail['subject']); + $componentSubscribers->each(function ($subscriber) use ($component, $event) { + $subscriber->notify(new ComponentStatusChangedNotification($component, $event->new_status)); }); } } diff --git a/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php b/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php index f92e49c0f4a..d30916d10de 100644 --- a/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php +++ b/app/Bus/Handlers/Events/Incident/SendIncidentEmailNotificationHandler.php @@ -11,20 +11,19 @@ namespace CachetHQ\Cachet\Bus\Handlers\Events\Incident; -use CachetHQ\Cachet\Bus\Events\Incident\IncidentWasReportedEvent; +use CachetHQ\Cachet\Bus\Events\Incident\IncidentWasCreatedEvent; +use CachetHQ\Cachet\Integrations\Contracts\System; use CachetHQ\Cachet\Models\Subscriber; -use Illuminate\Contracts\Mail\MailQueue; -use Illuminate\Mail\Message; -use McCool\LaravelAutoPresenter\Facades\AutoPresenter; +use CachetHQ\Cachet\Notifications\Incident\NewIncidentNotification; class SendIncidentEmailNotificationHandler { /** - * The mailer instance. + * The system instance. * - * @var \Illuminate\Contracts\Mail\Mailer + * @var \CachetHQ\Cachet\Integrations\Contracts\System */ - protected $mailer; + protected $system; /** * The subscriber instance. @@ -36,43 +35,45 @@ class SendIncidentEmailNotificationHandler /** * Create a new send incident email notification handler. * - * @param \Illuminate\Contracts\Mail\Mailer $mailer - * @param \CachetHQ\Cachet\Models\Subscriber $subscriber + * @param \CachetHQ\Cachet\Integrations\Contracts\System $system + * @param \CachetHQ\Cachet\Models\Subscriber $subscriber * * @return void */ - public function __construct(MailQueue $mailer, Subscriber $subscriber) + public function __construct(System $system, Subscriber $subscriber) { - $this->mailer = $mailer; + $this->system = $system; $this->subscriber = $subscriber; } /** * Handle the event. * - * @param \CachetHQ\Cachet\Bus\Events\Incident\IncidentWasReportedEvent $event + * @param \CachetHQ\Cachet\Bus\Events\Incident\IncidentWasCreatedEvent $event * * @return void */ - public function handle(IncidentWasReportedEvent $event) + public function handle(IncidentWasCreatedEvent $event) { - if (!$event->incident->notify) { + $incident = $event->incident; + + if (!$event->notify || !$this->system->canNotifySubscribers()) { return false; } // Only send emails for public incidents. - if ($event->incident->visible === 0) { + if (!$incident->visible) { return; } // First notify all global subscribers. $globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get(); - foreach ($globalSubscribers as $subscriber) { - $this->notify($event, $subscriber); - } + $globalSubscribers->each(function ($subscriber) use ($incident) { + $subscriber->notify(new NewIncidentNotification($incident)); + }); - if (!$event->incident->component) { + if (!$incident->component) { return; } @@ -81,53 +82,12 @@ public function handle(IncidentWasReportedEvent $event) // Notify the remaining component specific subscribers. $componentSubscribers = $this->subscriber ->isVerified() - ->forComponent($event->incident->component->id) + ->forComponent($incident->component->id) ->get() ->reject(function ($subscriber) use ($notified) { return in_array($subscriber->id, $notified); + })->each(function ($subscriber) use ($incident) { + $subscriber->notify(new NewIncidentNotification($incident)); }); - - foreach ($componentSubscribers as $subscriber) { - $this->notify($event, $subscriber); - } - } - - /** - * Send notification to subscriber. - * - * @param \CachetHQ\Cachet\Bus\Events\IncidentWasReportedEvent $event - * @param \CachetHQ\Cachet\Models\Subscriber $subscriber - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function notify(IncidentWasReportedEvent $event, $subscriber) - { - $incident = AutoPresenter::decorate($event->incident); - $component = AutoPresenter::decorate($event->incident->component); - - $mail = [ - 'email' => $subscriber->email, - 'subject' => trans('cachet.subscriber.email.incident.subject', [ - 'status' => $incident->human_status, - 'name' => $incident->name, - ]), - 'has_component' => ($event->incident->component) ? true : false, - 'component_name' => $component ? $component->name : null, - 'name' => $incident->name, - 'timestamp' => $incident->created_at_formatted, - 'status' => $incident->human_status, - 'html_content' => $incident->formattedMessage, - 'text_content' => $incident->message, - 'token' => $subscriber->token, - 'manage_link' => route('subscribe.manage', ['code' => $subscriber->verify_code]), - 'unsubscribe_link' => route('subscribe.unsubscribe', ['code' => $subscriber->verify_code]), - ]; - - $this->mailer->queue([ - 'html' => 'emails.incidents.new-html', - 'text' => 'emails.incidents.new-text', - ], $mail, function (Message $message) use ($mail) { - $message->to($mail['email'])->subject($mail['subject']); - }); } } diff --git a/app/Bus/Handlers/Events/Incident/SendMaintenanceEmailNotificationHandler.php b/app/Bus/Handlers/Events/Incident/SendMaintenanceEmailNotificationHandler.php deleted file mode 100644 index faa4fd38a7a..00000000000 --- a/app/Bus/Handlers/Events/Incident/SendMaintenanceEmailNotificationHandler.php +++ /dev/null @@ -1,132 +0,0 @@ -mailer = $mailer; - $this->subscriber = $subscriber; - } - - /** - * Handle the event. - * - * @param \CachetHQ\Cachet\Bus\Events\MaintenanceWasScheduledEvent $event - * - * @return void - */ - public function handle(MaintenanceWasScheduledEvent $event) - { - if (!$event->incident->notify) { - return false; - } - - // Only send emails for public incidents. - if ($event->incident->visible === 0) { - return; - } - - // First notify all global subscribers. - $globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get(); - - foreach ($globalSubscribers as $subscriber) { - $this->notify($event, $subscriber); - } - - if (!$event->incident->component) { - return; - } - - $notified = $globalSubscribers->pluck('id')->all(); - - // Notify the remaining component specific subscribers. - $componentSubscribers = $this->subscriber - ->isVerified() - ->forComponent($event->incident->component->id) - ->get() - ->reject(function ($subscriber) use ($notified) { - return in_array($subscriber->id, $notified); - }); - - foreach ($componentSubscribers as $subscriber) { - $this->notify($event, $subscriber); - } - } - - /** - * Send notification to subscriber. - * - * @param \CachetHQ\Cachet\Bus\Events\MaintenanceWasScheduledEvent $event - * @param \CachetHQ\Cachet\Models\Subscriber $subscriber - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function notify(MaintenanceWasScheduledEvent $event, $subscriber) - { - $incident = AutoPresenter::decorate($event->incident); - $component = AutoPresenter::decorate($event->incident->component); - - $mail = [ - 'email' => $subscriber->email, - 'subject' => trans('cachet.subscriber.email.maintenance.subject', [ - 'name' => $incident->name, - ]), - 'has_component' => ($event->incident->component) ? true : false, - 'component_name' => $component ? $component->name : null, - 'name' => $incident->name, - 'timestamp' => $incident->scheduled_at_formatted, - 'status' => $incident->human_status, - 'html_content' => $incident->formattedMessage, - 'text_content' => $incident->message, - 'token' => $subscriber->token, - 'manage_link' => route('subscribe.manage', ['code' => $subscriber->verify_code]), - 'unsubscribe_link' => route('subscribe.unsubscribe', ['code' => $subscriber->verify_code]), - ]; - - $this->mailer->queue([ - 'html' => 'emails.incidents.maintenance-html', - 'text' => 'emails.incidents.maintenance-text', - ], $mail, function (Message $message) use ($mail) { - $message->to($mail['email'])->subject($mail['subject']); - }); - } -} diff --git a/app/Bus/Handlers/Events/IncidentUpdate/SendIncidentUpdateEmailNotificationHandler.php b/app/Bus/Handlers/Events/IncidentUpdate/SendIncidentUpdateEmailNotificationHandler.php new file mode 100644 index 00000000000..447604816e4 --- /dev/null +++ b/app/Bus/Handlers/Events/IncidentUpdate/SendIncidentUpdateEmailNotificationHandler.php @@ -0,0 +1,90 @@ +system = $system; + $this->subscriber = $subscriber; + } + + /** + * Handle the event. + * + * @param \CachetHQ\Cachet\Bus\Events\IncidentUpdate\IncidentUpdateWasReportedEvent $event + * + * @return void + */ + public function handle(IncidentUpdateWasReportedEvent $event) + { + $update = $event->update; + $incident = $update->incident; + + // Only send emails for public incidents while the system is not under scheduled maintenance. + if (!$incident->visible || !$this->system->canNotifySubscribers()) { + return; + } + + // First notify all global subscribers. + $globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get(); + + $globalSubscribers->each(function ($subscriber) use ($update) { + $subscriber->notify(new IncidentUpdatedNotification($update)); + }); + + if (!$incident->component) { + return; + } + + $notified = $globalSubscribers->pluck('id')->all(); + + // Notify the remaining component specific subscribers. + $componentSubscribers = $this->subscriber + ->isVerified() + ->forComponent($incident->component->id) + ->get() + ->reject(function ($subscriber) use ($notified) { + return in_array($subscriber->id, $notified); + })->each(function ($subscriber) use ($update) { + $subscriber->notify(new IncidentUpdatedNotification($update)); + }); + } +} diff --git a/app/Bus/Handlers/Events/Schedule/SendScheduleEmailNotificationHandler.php b/app/Bus/Handlers/Events/Schedule/SendScheduleEmailNotificationHandler.php new file mode 100644 index 00000000000..84e9db31d61 --- /dev/null +++ b/app/Bus/Handlers/Events/Schedule/SendScheduleEmailNotificationHandler.php @@ -0,0 +1,63 @@ + + */ +class SendScheduleEmailNotificationHandler +{ + /** + * The subscriber instance. + * + * @var \CachetHQ\Cachet\Models\Subscriber + */ + protected $subscriber; + + /** + * Create a new send schedule email notification handler. + * + * @param \CachetHQ\Cachet\Models\Subscriber $subscriber + * + * @return void + */ + public function __construct(Subscriber $subscriber) + { + $this->subscriber = $subscriber; + } + + /** + * Handle the event. + * + * @param \CachetHQ\Cachet\Bus\Events\Schedule\ScheduleEventInterface $event + * + * @return void + */ + public function handle(ScheduleEventInterface $event) + { + $schedule = $event->schedule; + if (!$event->notify) { + return false; + } + + // First notify all global subscribers. + $globalSubscribers = $this->subscriber->isVerified()->isGlobal()->get()->each(function ($subscriber) use ($schedule) { + $subscriber->notify(new NewScheduleNotification($schedule)); + }); + } +} diff --git a/app/Bus/Handlers/Events/Subscriber/SendSubscriberVerificationEmailHandler.php b/app/Bus/Handlers/Events/Subscriber/SendSubscriberVerificationEmailHandler.php deleted file mode 100644 index 2ff98f02b0b..00000000000 --- a/app/Bus/Handlers/Events/Subscriber/SendSubscriberVerificationEmailHandler.php +++ /dev/null @@ -1,61 +0,0 @@ -mailer = $mailer; - } - - /** - * Handle the event. - * - * @param \CachetHQ\Cachet\Bus\Events\SubscriberHasSubscribedEvent $event - * - * @return void - */ - public function handle(SubscriberHasSubscribedEvent $event) - { - $mail = [ - 'email' => $event->subscriber->email, - 'subject' => 'Confirm your subscription.', - 'link' => route('subscribe.verify', ['code' => $event->subscriber->verify_code]), - ]; - - $this->mailer->queue([ - 'html' => 'emails.subscribers.verify-html', - 'text' => 'emails.subscribers.verify-text', - ], $mail, function (Message $message) use ($mail) { - $message->to($mail['email'])->subject($mail['subject']); - }); - } -} diff --git a/app/Bus/Handlers/Events/User/SendInviteUserEmailHandler.php b/app/Bus/Handlers/Events/User/SendInviteUserEmailHandler.php deleted file mode 100644 index 83e8f35659c..00000000000 --- a/app/Bus/Handlers/Events/User/SendInviteUserEmailHandler.php +++ /dev/null @@ -1,61 +0,0 @@ -mailer = $mailer; - } - - /** - * Handle the event. - * - * @param \CachetHQ\Cachet\Bus\Events\UserWasInvitedEvent $event - * - * @return void - */ - public function handle(UserWasInvitedEvent $event) - { - $mail = [ - 'email' => $event->invite->email, - 'subject' => 'You have been invited.', - 'link' => route('signup.invite', ['code' => $event->invite->code]), - ]; - - $this->mailer->queue([ - 'html' => 'emails.users.invite-html', - 'text' => 'emails.users.invite-text', - ], $mail, function (Message $message) use ($mail) { - $message->to($mail['email'])->subject($mail['subject']); - }); - } -} diff --git a/app/Bus/Handlers/Jobs/System/SendBeaconJobHandler.php b/app/Bus/Handlers/Jobs/System/SendBeaconJobHandler.php new file mode 100644 index 00000000000..da0eb87d1bb --- /dev/null +++ b/app/Bus/Handlers/Jobs/System/SendBeaconJobHandler.php @@ -0,0 +1,64 @@ + + */ +class SendBeaconJobHandler +{ + /** + * The beacon instance. + * + * @var \CachetHQ\Cachet\Integrations\Contracts\Beacon + */ + protected $beacon; + + /** + * Create a new send beacon job handler instance. + * + * @param \CachetHQ\Cachet\Integrations\Contracts\Beacon $beacon + * + * @return void + */ + public function __construct(Beacon $beacon) + { + $this->beacon = $beacon; + } + + /** + * Handle the send beacon job. + * + * @param \CachetHQ\Cachet\Bus\Jobs\System\SendBeaconJob $job + * + * @return void + */ + public function handle(SendBeaconJob $job) + { + // Don't send anything if the installation explicitly prevents us. + if (!$this->beacon->enabled()) { + return; + } + + try { + $this->beacon->send(); + } catch (Exception $e) { + // + } + } +} diff --git a/app/Bus/Handlers/Traits/StoresMeta.php b/app/Bus/Handlers/Traits/StoresMeta.php new file mode 100644 index 00000000000..e5272ba51b4 --- /dev/null +++ b/app/Bus/Handlers/Traits/StoresMeta.php @@ -0,0 +1,81 @@ + $value) { + $modelInstance = call_user_func( + [$metaModel, 'firstOrNew'], + [ + 'key' => $key, + 'meta_type' => $metaType, + 'meta_id' => $metaId, + ] + ); + + $value = $this->removeEmptyValues($value); + if (!empty($value)) { + $modelInstance->setAttribute('value', $value); + $modelInstance->save(); + continue; + } + + // The value is empty, remove the row + if ($modelInstance->exists) { + $modelInstance->delete(); + } + } + } + + /** + * Determine if a Value is empty. + * + * @param mixed $values + * + * @return array|mixed + */ + protected function removeEmptyValues($values) + { + if (!is_array($values)) { + return empty($values) ? null : $values; + } + + foreach ($values as $key => $value) { + if (!empty($value)) { + continue; + } + unset($values[$key]); + } + + return $values; + } +} diff --git a/app/Bus/Jobs/System/SendBeaconJob.php b/app/Bus/Jobs/System/SendBeaconJob.php new file mode 100644 index 00000000000..577aa8102d1 --- /dev/null +++ b/app/Bus/Jobs/System/SendBeaconJob.php @@ -0,0 +1,24 @@ + + */ +final class SendBeaconJob implements ShouldQueue +{ + // +} diff --git a/app/Composers/AppComposer.php b/app/Composers/AppComposer.php index 4d9cb199e83..822b30f2615 100644 --- a/app/Composers/AppComposer.php +++ b/app/Composers/AppComposer.php @@ -11,12 +11,47 @@ namespace CachetHQ\Cachet\Composers; +use CachetHQ\Cachet\Services\Dates\DateFactory; use GrahamCampbell\Markdown\Facades\Markdown; +use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\View\View; -use Illuminate\Support\Facades\Config; +/** + * This is the app composer class. + * + * @author James Brooks + * @author Graham Campbell + */ class AppComposer { + /** + * The date factory instance. + * + * @var \CachetHQ\Cachet\Services\Dates\DateFactory + */ + protected $dates; + + /** + * The illuminate config instance. + * + * @var \Illuminate\Contracts\Config\Repository + */ + protected $config; + + /** + * Create a new app composer instance. + * + * @param \CachetHQ\Cachet\Services\Dates\DateFactory $dates + * @param \Illuminate\Contracts\Config\Repository $config + * + * @return void + */ + public function __construct(DateFactory $dates, Repository $config) + { + $this->dates = $dates; + $this->config = $config; + } + /** * Index page view composer. * @@ -26,25 +61,38 @@ class AppComposer */ public function compose(View $view) { - $view->withAboutApp(Markdown::convertToHtml(Config::get('setting.app_about'))); - $view->withAppAnalytics(Config::get('setting.app_analytics')); - $view->withAppAnalyticsGoSquared(Config::get('setting.app_analytics_gs')); - $view->withAppAnalyticsPiwikUrl(Config::get('setting.app_analytics_piwik_url')); - $view->withAppAnalyticsPiwikSiteId(Config::get('setting.app_analytics_piwik_site_id')); - $view->withAppBanner(Config::get('setting.app_banner')); - $view->withAppBannerStyleFullWidth(Config::get('setting.style_fullwidth_header')); - $view->withAppBannerType(Config::get('setting.app_banner_type')); - $view->withAppDomain(Config::get('setting.app_domain')); - $view->withAppGraphs(Config::get('setting.display_graphs')); - $view->withAppLocale(Config::get('setting.app_locale')); - $view->withAppStylesheet(Config::get('setting.stylesheet')); - $view->withAppUrl(Config::get('app.url')); - $view->withAppHeader(Config::get('setting.header')); - $view->withAppFooter(Config::get('setting.footer')); - $view->withAppName(Config::get('setting.app_name')); - $view->withShowSupport($support = Config::get('setting.show_support')); - $view->withAutomaticLocalization(Config::get('setting.automatic_localization')); - $view->withSiteTitle(Config::get('setting.app_name')); - $view->withFontSubset(Config::get('langs.'.Config::get('app.locale').'.subset', 'latin')); + if ($this->config->get('setting.app_about')) { + $about = Markdown::convertToHtml($this->config->get('setting.app_about')); + } else { + $about = ''; + } + + $view->withAboutApp($about); + $view->withAppAnalytics($this->config->get('setting.app_analytics')); + $view->withAppAnalyticsGoSquared($this->config->get('setting.app_analytics_gs')); + $view->withAppAnalyticsPiwikUrl($this->config->get('setting.app_analytics_piwik_url')); + $view->withAppAnalyticsPiwikSiteId($this->config->get('setting.app_analytics_piwik_site_id')); + $view->withAppBanner($this->config->get('setting.app_banner')); + $view->withAppBannerStyleFullWidth($this->config->get('setting.style_fullwidth_header')); + $view->withAppBannerType($this->config->get('setting.app_banner_type')); + $view->withAppDomain($this->config->get('setting.app_domain')); + $view->withAppGraphs($this->config->get('setting.display_graphs')); + $view->withAppLocale($this->config->get('setting.app_locale')); + $view->withAppStylesheet($this->config->get('setting.stylesheet')); + $view->withAppUrl($this->config->get('app.url')); + $view->withAppHeader($this->config->get('setting.header')); + $view->withAppFooter($this->config->get('setting.footer')); + $view->withAppName($this->config->get('setting.app_name')); + $view->withShowSupport($this->config->get('setting.show_support')); + $view->withAutomaticLocalization($this->config->get('setting.automatic_localization')); + $view->withEnableExternalDependencies($this->config->get('setting.enable_external_dependencies')); + $view->withShowTimezone($this->config->get('setting.show_timezone')); + $view->withAppRefreshRate($this->config->get('setting.app_refresh_rate')); + $view->withTimezone($this->dates->getTimezone()); + $view->withSiteTitle($this->config->get('setting.app_name')); + $view->withFontSubset($this->config->get('langs.'.$this->config->get('app.locale').'.subset', 'latin')); + $view->withOnlyDisruptedDays($this->config->get('setting.only_disrupted_days')); + $view->withDashboardLink($this->config->get('setting.dashboard_login_link')); + $view->withEnableSubscribers($this->config->get('setting.enable_subscribers')); } } diff --git a/app/Composers/ComponentsComposer.php b/app/Composers/ComponentsComposer.php new file mode 100644 index 00000000000..1fac9423df7 --- /dev/null +++ b/app/Composers/ComponentsComposer.php @@ -0,0 +1,79 @@ + + * @author Connor S. Parks + */ +class ComponentsComposer +{ + /** + * The user session object. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $guard; + + /** + * Creates a new components composer instance. + * + * @param \Illuminate\Contracts\Auth\Guard $guard + * + * @return void + */ + public function __construct(Guard $guard) + { + $this->guard = $guard; + } + + /** + * Bind data to the view. + * + * @param \Illuminate\Contracts\View\View $view + * + * @return void + */ + public function compose(View $view) + { + $componentGroups = $this->getVisibleGroupedComponents(); + $ungroupedComponents = Component::ungrouped()->orderBy('status', 'desc')->get(); + + $view->withComponentGroups($componentGroups) + ->withUngroupedComponents($ungroupedComponents); + } + + /** + * Get visible grouped components. + * + * @return \Illuminate\Support\Collection + */ + protected function getVisibleGroupedComponents() + { + $componentGroupsBuilder = ComponentGroup::query(); + if (!$this->guard->check()) { + $componentGroupsBuilder->visible(); + } + + $usedComponentGroups = Component::grouped()->pluck('group_id'); + + return $componentGroupsBuilder->used($usedComponentGroups) + ->get(); + } +} diff --git a/app/Composers/CurrentUserComposer.php b/app/Composers/CurrentUserComposer.php index 7543ad8d2af..d7afe3b9603 100644 --- a/app/Composers/CurrentUserComposer.php +++ b/app/Composers/CurrentUserComposer.php @@ -13,7 +13,15 @@ use Illuminate\Contracts\View\View; use Illuminate\Support\Facades\Auth; +use McCool\LaravelAutoPresenter\Facades\AutoPresenter; +/** + * This is the current user composer class. + * + * @author Joseph Cohen + * @author James Brooks + * @author Graham Campbell + */ class CurrentUserComposer { /** @@ -25,6 +33,6 @@ class CurrentUserComposer */ public function compose(View $view) { - $view->withCurrentUser(Auth::user()); + $view->withCurrentUser(AutoPresenter::decorate(Auth::user())); } } diff --git a/app/Composers/DashboardComposer.php b/app/Composers/DashboardComposer.php index e36c9fd03ce..c5ccef937ce 100644 --- a/app/Composers/DashboardComposer.php +++ b/app/Composers/DashboardComposer.php @@ -14,11 +14,81 @@ use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Incident; use CachetHQ\Cachet\Models\IncidentTemplate; +use CachetHQ\Cachet\Models\Schedule; use CachetHQ\Cachet\Models\Subscriber; use Illuminate\Contracts\View\View; +/** + * This is the dashboard composer class. + * + * @author James Brooks + * @author Graham Campbell + */ class DashboardComposer { + /** + * The component count. + * + * @var int + */ + protected $componentCount; + + /** + * The incident count. + * + * @var int + */ + protected $incidentCount; + + /** + * The incident template count. + * + * @var int + */ + protected $incidentTemplateCount; + + /** + * The schedule count. + * + * @var int + */ + protected $scheduleCount; + + /** + * The subscriber count. + * + * @var int + */ + protected $subscriberCount; + + /** + * Create a new dashboard composer instance. + * + * @return void + */ + public function __construct() + { + if (is_null($this->componentCount)) { + $this->componentCount = Component::count(); + } + + if (is_null($this->incidentCount)) { + $this->incidentCount = Incident::count(); + } + + if (is_null($this->incidentTemplateCount)) { + $this->incidentTemplateCount = IncidentTemplate::count(); + } + + if (is_null($this->scheduleCount)) { + $this->scheduleCount = Schedule::count(); + } + + if (is_null($this->subscriberCount)) { + $this->subscriberCount = Subscriber::isVerified()->count(); + } + } + /** * Bind data to the view. * @@ -28,9 +98,11 @@ class DashboardComposer */ public function compose(View $view) { - $view->withIncidentCount(Incident::notScheduled()->count()); - $view->withIncidentTemplateCount(IncidentTemplate::count()); - $view->withComponentCount(Component::all()->count()); - $view->withSubscriberCount(Subscriber::isVerified()->count()); + $view->withComponentCount($this->componentCount); + $view->withIncidentCount($this->incidentCount); + $view->withIncidentTemplateCount($this->incidentTemplateCount); + $view->withScheduleCount($this->scheduleCount); + $view->withSubscriberCount($this->subscriberCount); + $view->withIsWriteable(is_writable(app()->bootstrapPath().'/cachet')); } } diff --git a/app/Composers/MetricsComposer.php b/app/Composers/MetricsComposer.php index 4f6696db519..e6e32e9f7f1 100644 --- a/app/Composers/MetricsComposer.php +++ b/app/Composers/MetricsComposer.php @@ -12,13 +12,48 @@ namespace CachetHQ\Cachet\Composers; use CachetHQ\Cachet\Models\Metric; +use Illuminate\Contracts\Auth\Guard; +use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\View\View; -use Illuminate\Support\Facades\Config; +/** + * This is the metrics composer. + * + * @author James Brooks + * @author Connor S. Parks + */ class MetricsComposer { /** - * Metrics view composer. + * The illuminate config instance. + * + * @var \Illuminate\Contracts\Config\Repository + */ + protected $config; + + /** + * The user session object. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $guard; + + /** + * Create a new metrics composer instance. + * + * @param \Illuminate\Contracts\Config\Repository $config + * @param \Illuminate\Contracts\Auth\Guard $guard + * + * @return void + */ + public function __construct(Repository $config, Guard $guard) + { + $this->config = $config; + $this->guard = $guard; + } + + /** + * Bind data to the view. * * @param \Illuminate\Contracts\View\View $view * @@ -26,12 +61,32 @@ class MetricsComposer */ public function compose(View $view) { - $metrics = null; - if ($displayMetrics = Config::get('setting.display_graphs')) { - $metrics = Metric::displayable()->orderBy('order')->orderBy('id')->get(); - } + $displayMetrics = $this->config->get('setting.display_graphs'); + $metrics = $this->getVisibleMetrics($displayMetrics); $view->withDisplayMetrics($displayMetrics) ->withMetrics($metrics); } + + /** + * Get visible grouped components. + * + * @param bool $displayMetrics + * + * @return \Illuminate\Support\Collection|void + */ + protected function getVisibleMetrics($displayMetrics) + { + if (!$displayMetrics) { + return; + } + + $metrics = Metric::displayable(); + + if (!$this->guard->check()) { + $metrics->visible(); + } + + return $metrics->orderBy('order')->orderBy('id')->get(); + } } diff --git a/app/Composers/ScheduledComposer.php b/app/Composers/ScheduledComposer.php new file mode 100644 index 00000000000..0e65b4a8924 --- /dev/null +++ b/app/Composers/ScheduledComposer.php @@ -0,0 +1,38 @@ + + * @author Connor S. Parks + */ +class ScheduledComposer +{ + /** + * Bind data to the view. + * + * @param \Illuminate\Contracts\View\View $view + * + * @return void + */ + public function compose(View $view) + { + $scheduledMaintenance = Schedule::uncompleted()->orderBy('scheduled_at')->get(); + + $view->withScheduledMaintenance($scheduledMaintenance); + } +} diff --git a/app/Composers/SettingsComposer.php b/app/Composers/SettingsComposer.php new file mode 100644 index 00000000000..aa0ff2fac6c --- /dev/null +++ b/app/Composers/SettingsComposer.php @@ -0,0 +1,80 @@ + + */ +class SettingsComposer +{ + /** + * Array of cache drivers. + * + * @var string[] + */ + protected $cacheDrivers = [ + 'apc' => 'APC(u)', + 'array' => 'Array', + 'database' => 'Database', + 'file' => 'File', + 'memcached' => 'Memcached', + 'redis' => 'Redis', + ]; + + /** + * Array of cache drivers. + * + * @var string[] + */ + protected $mailDrivers = [ + 'smtp' => 'SMTP', + 'mail' => 'Mail', + 'sendmail' => 'Sendmail', + 'mailgun' => 'Mailgun', + 'mandrill' => 'Mandrill', + 'ses' => 'Amazon SES', + 'sparkpost' => 'SparkPost', + 'log' => 'Log (Testing)', + ]; + + /** + * Array of queue drivers. + * + * @var string[] + */ + protected $queueDrivers = [ + 'null' => 'None', + 'sync' => 'Synchronous', + 'database' => 'Database', + 'beanstalkd' => 'Beanstalk', + 'sqs' => 'Amazon SQS', + 'redis' => 'Redis', + ]; + + /** + * Bind data to the view. + * + * @param \Illuminate\Contracts\View\View $view + * + * @return void + */ + public function compose(View $view) + { + $view->withCacheDrivers($this->cacheDrivers); + $view->withMailDrivers($this->mailDrivers); + $view->withQueueDrivers($this->queueDrivers); + } +} diff --git a/app/Composers/StatusComposer.php b/app/Composers/StatusComposer.php new file mode 100644 index 00000000000..6b953343e9a --- /dev/null +++ b/app/Composers/StatusComposer.php @@ -0,0 +1,59 @@ + + * @author Connor S. Parks + */ +class StatusComposer +{ + /** + * The system instance. + * + * @var \CachetHQ\Cachet\Integrations\Contracts\System + */ + protected $system; + + /** + * Create a new status composer instance. + * + * @param \CachetHQ\Cachet\Integrations\Contracts\System $system + * + * @return void + */ + public function __construct(System $system) + { + $this->system = $system; + } + + /** + * Bind data to the view. + * + * @param \Illuminate\Contracts\View\View $view + * + * @return void + */ + public function compose(View $view) + { + $status = $this->system->getStatus(); + + $view->withSystemStatus(Arr::get($status, 'system_status')); + $view->withSystemMessage(Arr::get($status, 'system_message')); + } +} diff --git a/app/Composers/StatusPageComposer.php b/app/Composers/StatusPageComposer.php deleted file mode 100644 index ddfed69b4f8..00000000000 --- a/app/Composers/StatusPageComposer.php +++ /dev/null @@ -1,80 +0,0 @@ -count(); - $majorOutages = Component::enabled()->status(4)->count(); - $isMajorOutage = $totalComponents ? ($majorOutages / $totalComponents) >= 0.5 : false; - - // Default data - $withData = [ - 'system_status' => 'info', - 'system_message' => trans_choice('cachet.service.bad', $totalComponents), - 'favicon' => 'favicon-high-alert', - ]; - - if ($isMajorOutage) { - $withData = [ - 'system_status' => 'danger', - 'system_message' => trans_choice('cachet.service.major', $totalComponents), - 'favicon' => 'favicon-high-alert', - ]; - } elseif (Component::enabled()->notStatus(1)->count() === 0) { - // If all our components are ok, do we have any non-fixed incidents? - $incidents = Incident::notScheduled()->orderBy('created_at', 'desc')->get()->filter(function ($incident) { - return $incident->status > 0; - }); - $incidentCount = $incidents->count(); - - if ($incidentCount === 0 || ($incidentCount >= 1 && (int) $incidents->first()->status === 4)) { - $withData = [ - 'system_status' => 'success', - 'system_message' => trans_choice('cachet.service.good', $totalComponents), - 'favicon' => 'favicon', - ]; - } - } else { - if (Component::enabled()->whereIn('status', [2, 3])->count() > 0) { - $withData['favicon'] = 'favicon-medium-alert'; - } - } - - // Scheduled maintenance code. - $scheduledMaintenance = Incident::scheduled()->orderBy('scheduled_at')->get(); - - // Component & Component Group lists. - $usedComponentGroups = Component::enabled()->where('group_id', '>', 0)->groupBy('group_id')->pluck('group_id'); - $componentGroups = ComponentGroup::whereIn('id', $usedComponentGroups)->orderBy('order')->get(); - $ungroupedComponents = Component::enabled()->where('group_id', 0)->orderBy('order')->orderBy('created_at')->get(); - - $view->with($withData) - ->withComponentGroups($componentGroups) - ->withUngroupedComponents($ungroupedComponents) - ->withScheduledMaintenance($scheduledMaintenance); - } -} diff --git a/app/Composers/StickiedComposer.php b/app/Composers/StickiedComposer.php new file mode 100644 index 00000000000..82e357f395e --- /dev/null +++ b/app/Composers/StickiedComposer.php @@ -0,0 +1,42 @@ + + * @author Connor S. Parks + * @author Antoine Girard + */ +class StickiedComposer +{ + /** + * Bind data to the view. + * + * @param \Illuminate\Contracts\View\View $view + * + * @return void + */ + public function compose(View $view) + { + $stickiedIncidents = Incident::stickied()->orderBy('occurred_at', 'desc')->get()->groupBy(function (Incident $incident) { + return app(DateFactory::class)->make($incident->is_scheduled ? $incident->scheduled_at : $incident->occurred_at)->toDateString(); + }); + + $view->withStickiedIncidents($stickiedIncidents); + } +} diff --git a/app/Composers/ThemeComposer.php b/app/Composers/ThemeComposer.php index 5f608a0a826..0153a35f9d4 100644 --- a/app/Composers/ThemeComposer.php +++ b/app/Composers/ThemeComposer.php @@ -11,11 +11,36 @@ namespace CachetHQ\Cachet\Composers; +use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\View\View; -use Illuminate\Support\Facades\Config; +/** + * This is the theme composer class. + * + * @author James Brooks + * @author Graham Campbell + */ class ThemeComposer { + /** + * The illuminate config instance. + * + * @var \Illuminate\Contracts\Config\Repository + */ + protected $config; + + /** + * Create a new theme composer. + * + * @param \Illuminate\Contracts\Config\Repository $config + * + * @return void + */ + public function __construct(Repository $config) + { + $this->config = $config; + } + /** * Bind data to the view. * @@ -25,18 +50,18 @@ class ThemeComposer */ public function compose(View $view) { - // Theme colors. - $view->withThemeBackgroundColor(Config::get('setting.style_background_color', '#F0F3F4')); - $view->withThemeBackgroundFills(Config::get('setting.style_background_fills', '#FFFFFF')); - $view->withThemeBannerBackgroundColor(Config::get('setting.style_banner_background_color', '')); - $view->withThemeBannerPadding(Config::get('setting.style_banner_padding', '40px 0')); - $view->withThemeTextColor(Config::get('setting.style_text_color', '#333333')); - $view->withThemeReds(Config::get('setting.style_reds', '#ff6f6f')); - $view->withThemeBlues(Config::get('setting.style_blues', '#3498db')); - $view->withThemeGreens(Config::get('setting.style_greens', '#7ED321')); - $view->withThemeYellows(Config::get('setting.style_yellows', '#F7CA18')); - $view->withThemeOranges(Config::get('setting.style_oranges', '#FF8800')); - $view->withThemeMetrics(Config::get('setting.style_metrics', '#0dccc0')); - $view->withThemeLinks(Config::get('setting.style_links', '#7ED321')); + $view->withThemeBackgroundColor($this->config->get('setting.style_background_color', '#F0F3F4')); + $view->withThemeBackgroundFills($this->config->get('setting.style_background_fills', '#FFFFFF')); + $view->withThemeBannerBackgroundColor($this->config->get('setting.style_banner_background_color', '')); + $view->withThemeBannerPadding($this->config->get('setting.style_banner_padding', '40px 0')); + $view->withThemeTextColor($this->config->get('setting.style_text_color', '#333333')); + $view->withThemeReds($this->config->get('setting.style_reds', '#FF6F6F')); + $view->withThemeBlues($this->config->get('setting.style_blues', '#3498DB')); + $view->withThemeGreens($this->config->get('setting.style_greens', '#7ED321')); + $view->withThemeYellows($this->config->get('setting.style_yellows', '#F7CA18')); + $view->withThemeOranges($this->config->get('setting.style_oranges', '#FF8800')); + $view->withThemeGreys($this->config->get('setting.style_greys', '#888888')); + $view->withThemeMetrics($this->config->get('setting.style_metrics', '#0DCCC0')); + $view->withThemeLinks($this->config->get('setting.style_links', '#7ED321')); } } diff --git a/app/Composers/TimelineComposer.php b/app/Composers/TimelineComposer.php new file mode 100644 index 00000000000..0206a2dc722 --- /dev/null +++ b/app/Composers/TimelineComposer.php @@ -0,0 +1,35 @@ + + * @author Connor S. Parks + */ +class TimelineComposer +{ + /** + * Bind data to the view. + * + * @param \Illuminate\Contracts\View\View $view + * + * @return void + */ + public function compose(View $view) + { + // ... + } +} diff --git a/app/Composers/TimezoneLocaleComposer.php b/app/Composers/TimezoneLocaleComposer.php index e8ce68bb980..5e3712d8e58 100644 --- a/app/Composers/TimezoneLocaleComposer.php +++ b/app/Composers/TimezoneLocaleComposer.php @@ -13,11 +13,38 @@ use DateTime; use DateTimeZone; +use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\View\View; -use Illuminate\Support\Facades\Config; +use Illuminate\Support\Arr; +/** + * This is the timezone locale composer class. + * + * @author Joseph Cohen + * @author James Brooks + * @author Graham Campbell + */ class TimezoneLocaleComposer { + /** + * The illuminate config instance. + * + * @var \Illuminate\Contracts\Config\Repository + */ + protected $config; + + /** + * Create a new timezone locale composer. + * + * @param \Illuminate\Contracts\Config\Repository $config + * + * @return void + */ + public function __construct(Repository $config) + { + $this->config = $config; + } + /** * Timezones and Locales composer. * @@ -27,27 +54,31 @@ class TimezoneLocaleComposer */ public function compose(View $view) { - $enabledLangs = Config::get('langs'); + $enabledLangs = $this->config->get('langs'); $langs = array_map(function ($lang) use ($enabledLangs) { $locale = basename($lang); - return [$locale => $enabledLangs[$locale]]; + return [$locale => Arr::get($enabledLangs, $locale, [ + 'name' => $locale, + 'subset' => null, + ])]; }, glob(base_path('resources/lang').'/*')); $langs = call_user_func_array('array_merge', $langs); $regions = [ + 'UTC' => DateTimeZone::UTC, 'Africa' => DateTimeZone::AFRICA, 'America' => DateTimeZone::AMERICA, 'Antarctica' => DateTimeZone::ANTARCTICA, + 'Arctic' => DateTimeZone::ARCTIC, 'Asia' => DateTimeZone::ASIA, 'Atlantic' => DateTimeZone::ATLANTIC, 'Australia' => DateTimeZone::AUSTRALIA, 'Europe' => DateTimeZone::EUROPE, 'Indian' => DateTimeZone::INDIAN, 'Pacific' => DateTimeZone::PACIFIC, - 'UTC' => DateTimeZone::UTC, ]; $timezones = []; @@ -59,10 +90,12 @@ public function compose(View $view) // Lets sample the time there right now $time = new DateTime(null, new DateTimeZone($timezone)); - $ampm = $time->format('H') > 12 ? ' ('.$time->format('g:i a').')' : ''; - - // Remove region name and add a sample time - $timezones[$name][$timezone] = substr($timezone, strlen($name) + 1).' - '.$time->format('H:i').$ampm; + if ($timezone !== 'UTC') { + // Remove region name and add a sample time + $timezones[$name][$timezone] = substr($timezone, strlen($name) + 1).' - '.$time->format('H:i'); + } else { + $timezones[$name][$timezone] = 'UTC - '.$time->format('H:i'); + } $timezones[$name] = str_replace('_', ' ', $timezones[$name]); } diff --git a/app/Console/Commands/AppResetCommand.php b/app/Console/Commands/AppResetCommand.php new file mode 100644 index 00000000000..3add76aa5c6 --- /dev/null +++ b/app/Console/Commands/AppResetCommand.php @@ -0,0 +1,76 @@ + + */ +class AppResetCommand extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'app:reset'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Resets and installs the application'; + + /** + * The events instance. + * + * @var \Illuminate\Contracts\Events\Dispatcher + */ + protected $events; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $this->events->fire('command.resetting', $this); + $this->events->fire('command.generatekey', $this); + $this->events->fire('command.cacheconfig', $this); + $this->events->fire('command.cacheroutes', $this); + $this->events->fire('command.publishvendors', $this); + $this->events->fire('command.resetmigrations', $this); + $this->events->fire('command.runmigrations', $this); + $this->events->fire('command.runseeding', $this); + $this->events->fire('command.updatecache', $this); + $this->events->fire('command.extrastuff', $this); + $this->events->fire('command.reset', $this); + } +} diff --git a/app/Console/Commands/AppUpdateCommand.php b/app/Console/Commands/AppUpdateCommand.php new file mode 100644 index 00000000000..1aa4bd975eb --- /dev/null +++ b/app/Console/Commands/AppUpdateCommand.php @@ -0,0 +1,73 @@ + + */ +class AppUpdateCommand extends Command +{ + /** + * The name and signature of the console command. + * + * @var string + */ + protected $signature = 'app:update'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Updates the application'; + + /** + * The events instance. + * + * @var \Illuminate\Contracts\Events\Dispatcher + */ + protected $events; + + /** + * Create a new command instance. + * + * @return void + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + $this->events->fire('command.updating', $this); + $this->events->fire('command.cacheconfig', $this); + $this->events->fire('command.cacheroutes', $this); + $this->events->fire('command.publishvendors', $this); + $this->events->fire('command.runmigrations', $this); + $this->events->fire('command.updatecache', $this); + $this->events->fire('command.extrastuff', $this); + $this->events->fire('command.updated', $this); + } +} diff --git a/app/Console/Commands/BeaconCommand.php b/app/Console/Commands/BeaconCommand.php new file mode 100644 index 00000000000..27cad3f0684 --- /dev/null +++ b/app/Console/Commands/BeaconCommand.php @@ -0,0 +1,47 @@ + + */ +class BeaconCommand extends Command +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'cachet:beacon'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Communicate with the Cachet Beacon server'; + + /** + * Execute the console command. + * + * @return void + */ + public function handle() + { + dispatch(new SendBeaconJob()); + } +} diff --git a/app/Console/Commands/DemoMetricPointSeederCommand.php b/app/Console/Commands/DemoMetricPointSeederCommand.php index 7c731b6c263..d4e16235849 100644 --- a/app/Console/Commands/DemoMetricPointSeederCommand.php +++ b/app/Console/Commands/DemoMetricPointSeederCommand.php @@ -12,8 +12,6 @@ namespace CachetHQ\Cachet\Console\Commands; use CachetHQ\Cachet\Models\MetricPoint; -use DateInterval; -use DateTime; use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; use Symfony\Component\Console\Input\InputOption; @@ -39,14 +37,14 @@ class DemoMetricPointSeederCommand extends Command * * @var string */ - protected $description = 'Seeds the demo Cachet metric with points.'; + protected $description = 'Seeds the demo Cachet metrics with points'; /** * Execute the console command. * * @return void */ - public function fire() + public function handle() { if (!$this->confirmToProceed()) { return; @@ -66,16 +64,26 @@ protected function seedMetricPoints() { MetricPoint::truncate(); - // Generate 11 hours of metric points - for ($i = 0; $i < 11; $i++) { - $metricTime = (new DateTime())->sub(new DateInterval('PT'.$i.'H')); + $points = []; - MetricPoint::create([ - 'metric_id' => 1, - 'value' => random_int(1, 10), - 'created_at' => $metricTime, - 'updated_at' => $metricTime, - ]); + // Generate 24 hours of metric points + for ($i = 0; $i <= 23; $i++) { + for ($j = 0; $j <= 59; $j++) { + $this->info("{$i}:{$j}"); + + $pointTime = date("Y-m-d {$i}:{$j}:00"); + + $points[] = [ + 'metric_id' => 1, + 'value' => random_int(1, 10), + 'created_at' => $pointTime, + 'updated_at' => $pointTime, + ]; + } + } + + foreach (array_chunk($points, 100) as $chunk) { + MetricPoint::insert($chunk); } } diff --git a/app/Console/Commands/DemoSeederCommand.php b/app/Console/Commands/DemoSeederCommand.php index 8048891ca62..3d496ca0667 100644 --- a/app/Console/Commands/DemoSeederCommand.php +++ b/app/Console/Commands/DemoSeederCommand.php @@ -11,15 +11,19 @@ namespace CachetHQ\Cachet\Console\Commands; +use CachetHQ\Cachet\Models\Action; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\ComponentGroup; use CachetHQ\Cachet\Models\Incident; use CachetHQ\Cachet\Models\IncidentTemplate; +use CachetHQ\Cachet\Models\IncidentUpdate; use CachetHQ\Cachet\Models\Metric; use CachetHQ\Cachet\Models\MetricPoint; +use CachetHQ\Cachet\Models\Schedule; use CachetHQ\Cachet\Models\Subscriber; use CachetHQ\Cachet\Models\User; use CachetHQ\Cachet\Settings\Repository; +use Carbon\Carbon; use DateInterval; use DateTime; use Illuminate\Console\Command; @@ -47,19 +51,19 @@ class DemoSeederCommand extends Command * * @var string */ - protected $description = 'Seeds Cachet with demo data.'; + protected $description = 'Seeds Cachet with demo data'; /** * The settings repository. * - * @var \CachetHQ\Cache\Settings\Repository + * @var \CachetHQ\Cachet\Settings\Repository */ protected $settings; /** * Create a new demo seeder command instance. * - * @param \CachetHQ\Cache\Settings\Repository $settings + * @param \CachetHQ\Cachet\Settings\Repository $settings * * @return void */ @@ -75,25 +79,37 @@ public function __construct(Repository $settings) * * @return void */ - public function fire() + public function handle() { if (!$this->confirmToProceed()) { return; } + $this->seedUsers(); + $this->seedActions(); $this->seedComponentGroups(); $this->seedComponents(); $this->seedIncidents(); $this->seedIncidentTemplates(); $this->seedMetricPoints(); $this->seedMetrics(); + $this->seedSchedules(); $this->seedSettings(); $this->seedSubscribers(); - $this->seedUsers(); $this->info('Database seeded with demo data successfully!'); } + /** + * Seed the actions table. + * + * @return void + */ + protected function seedActions() + { + Action::truncate(); + } + /** * Seed the component groups table. * @@ -106,10 +122,12 @@ protected function seedComponentGroups() 'name' => 'Websites', 'order' => 1, 'collapsed' => 0, + 'visible' => ComponentGroup::VISIBLE_AUTHENTICATED, ], [ - 'name' => 'Alt Three', + 'name' => 'Services', 'order' => 2, 'collapsed' => 1, + 'visible' => ComponentGroup::VISIBLE_GUEST, ], ]; @@ -150,26 +168,26 @@ protected function seedComponents() 'group_id' => 1, 'link' => 'https://cachethq.io', ], [ - 'name' => 'Blog', - 'description' => 'The Alt Three Blog.', + 'name' => 'Laravel Artisan Cheatsheet', + 'description' => 'A searchable, bookmarkable cheatsheet for Laravel\'s Artisan commands.', 'status' => 1, 'order' => 0, 'group_id' => 2, - 'link' => 'https://blog.alt-three.com', + 'link' => 'https://artisan.page', ], [ - 'name' => 'StyleCI', - 'description' => 'The PHP Coding Style Service.', + 'name' => 'Checkmango', + 'description' => 'The Full-Stack A/B Testing Platform', 'status' => 1, 'order' => 1, 'group_id' => 2, - 'link' => 'https://styleci.io', + 'link' => 'https://checkmango.com', ], [ - 'name' => 'Patreon Page', - 'description' => 'Support future development of Cachet.', + 'name' => 'GitHub', + 'description' => '', 'status' => 1, 'order' => 0, 'group_id' => 0, - 'link' => 'https://patreon.com/jbrooksuk', + 'link' => 'https://github.com/cachethq/cachet', ], ]; @@ -199,59 +217,34 @@ protected function seedIncidents() $defaultIncidents = [ [ - 'name' => 'Cachet supports Markdown!', - 'message' => $incidentMessage, - 'status' => 4, - 'component_id' => 0, - 'scheduled_at' => null, - 'visible' => 1, - ], - [ - 'name' => 'Awesome', - 'message' => ':+1: We totally nailed the fix.', - 'status' => 4, + 'name' => 'Our monkeys aren\'t performing', + 'message' => 'We\'re investigating an issue with our monkeys not performing as they should be.', + 'status' => Incident::INVESTIGATING, 'component_id' => 0, - 'scheduled_at' => null, 'visible' => 1, + 'stickied' => false, + 'user_id' => 1, + 'occurred_at' => Carbon::now(), ], [ - 'name' => 'Monitoring the fix', - 'message' => ":ship: We've deployed a fix.", - 'status' => 3, + 'name' => 'This is an unresolved incident', + 'message' => 'Unresolved incidents are left without a **Fixed** update.', + 'status' => Incident::INVESTIGATING, 'component_id' => 0, - 'scheduled_at' => null, - 'visible' => 1, - ], - [ - 'name' => 'Update', - 'message' => "We've identified the problem. Our engineers are currently looking at it.", - 'status' => 2, - 'component_id' => 0, - 'scheduled_at' => null, - 'visible' => 1, - ], - [ - 'name' => 'Test Incident', - 'message' => 'Something went wrong, with something or another.', - 'status' => 1, - 'component_id' => 0, - 'scheduled_at' => null, - 'visible' => 1, - ], - [ - 'name' => 'Investigating the API', - 'message' => ':zap: We\'ve seen high response times from our API. It looks to be fixing itself as time goes on.', - 'status' => 1, - 'component_id' => 1, - 'scheduled_at' => null, 'visible' => 1, + 'stickied' => false, + 'user_id' => 1, + 'occurred_at' => Carbon::now(), ], ]; Incident::truncate(); + IncidentUpdate::truncate(); - foreach ($defaultIncidents as $incident) { - Incident::create($incident); + foreach ($defaultIncidents as $defaultIncident) { + $incident = Incident::create($defaultIncident); + + $this->seedIncidentUpdates($incident); } } @@ -265,6 +258,47 @@ protected function seedIncidentTemplates() IncidentTemplate::truncate(); } + /** + * Seed the incident updates table for a given incident. + * + * @return void + */ + protected function seedIncidentUpdates($incident) + { + $defaultUpdates = [ + 1 => [ + [ + 'status' => Incident::FIXED, + 'message' => 'The monkeys are back and rested!', + 'user_id' => 1, + ], [ + 'status' => Incident::WATCHED, + 'message' => 'Our monkeys need a break from performing. They\'ll be back after a good rest.', + 'user_id' => 1, + ], [ + 'status' => Incident::IDENTIFIED, + 'message' => 'We have identified the issue with our lovely performing monkeys.', + 'user_id' => 1, + ], + ], + 2 => [ + [ + 'status' => Incident::WATCHED, + 'message' => 'We\'re actively watching this issue, so it remains unresolved.', + 'user_id' => 1, + ], + ], + ]; + + $updates = $defaultUpdates[$incident->id]; + + foreach ($updates as $updateId => $update) { + $update['incident_id'] = $incident->id; + + IncidentUpdate::create($update); + } + } + /** * Seed the metric points table. * @@ -312,6 +346,29 @@ protected function seedMetrics() } } + /** + * Seed the schedules table. + * + * @return void + */ + protected function seedSchedules() + { + $defaultSchedules = [ + [ + 'name' => 'Demo resets every half hour!', + 'message' => 'You can schedule downtime for _your_ service!', + 'status' => Schedule::UPCOMING, + 'scheduled_at' => (new DateTime())->add(new DateInterval('PT2H')), + ], + ]; + + Schedule::truncate(); + + foreach ($defaultSchedules as $schedule) { + Schedule::create($schedule); + } + } + /** * Seed the settings table. * @@ -339,20 +396,20 @@ protected function seedSettings() 'key' => 'app_incident_days', 'value' => '7', ], [ - 'key' => 'app_analytics', - 'value' => 'UA-58442674-3', - ], [ - 'key' => 'app_analytics_gs', - 'value' => 'GSN-712462-P', + 'key' => 'app_refresh_rate', + 'value' => '0', ], [ 'key' => 'display_graphs', 'value' => '1', ], [ 'key' => 'app_about', - 'value' => 'This is the demo instance of [Cachet](https://cachethq.io?ref=demo). The open source status page system, for everyone. An [Alt Three](https://alt-three.com) product.', + 'value' => 'This is the demo instance of [Cachet](https://cachethq.io?ref=demo). The open-source status page system, for everyone. 3.x is coming soon! [Read the announcement](https://github.com/cachethq/cachet/discussions/4342).', ], [ 'key' => 'enable_subscribers', 'value' => '0', + ], [ + 'key' => 'header', + 'value' => '', ], ]; @@ -384,7 +441,7 @@ protected function seedUsers() [ 'username' => 'test', 'password' => 'test123', - 'email' => 'test@test.com', + 'email' => 'test@example.com', 'level' => User::LEVEL_ADMIN, 'api_key' => '9yMHsdioQosnyVK4iCVR', ], diff --git a/app/Console/Commands/InstallCommand.php b/app/Console/Commands/InstallCommand.php new file mode 100644 index 00000000000..7c71cbc0de2 --- /dev/null +++ b/app/Console/Commands/InstallCommand.php @@ -0,0 +1,448 @@ + + */ +class InstallCommand extends Command +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'cachet:install'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Install Cachet'; + + /** + * The events instance. + * + * @var \Illuminate\Contracts\Events\Dispatcher + */ + protected $events; + + /** + * Create a new command instance. + * + * @param Dispatcher $events + */ + public function __construct(Dispatcher $events) + { + $this->events = $events; + + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return void + */ + public function handle() + { + if ($this->confirm('Do you want to configure Cachet before installing?')) { + $this->configureEnvironmentFile(); + $this->configureKey(); + $this->configureDatabase(); + $this->configureDrivers(); + $this->configureMail(); + $this->configureCachet(); + $this->configureUser(); + } + + $this->line('Installing Cachet...'); + + $this->events->fire('command.installing', $this); + $this->events->fire('command.generatekey', $this); + $this->events->fire('command.cacheconfig', $this); + $this->events->fire('command.cacheroutes', $this); + $this->events->fire('command.publishvendors', $this); + $this->events->fire('command.runmigrations', $this); + $this->events->fire('command.runseeding', $this); + $this->events->fire('command.updatecache', $this); + $this->events->fire('command.linkstorage', $this); + $this->events->fire('command.extrastuff', $this); + $this->events->fire('command.installed', $this); + + $this->info('Cachet is installed ⚡'); + } + + /** + * Copy the environment file. + * + * @return void + */ + protected function configureEnvironmentFile() + { + $dir = app()->environmentPath(); + $file = app()->environmentFile(); + $path = "{$dir}/{$file}"; + + if (file_exists($path)) { + $this->line('Environment file already exists. Moving on.'); + + return; + } + + copy("$path.example", $path); + } + + /** + * Generate the app key. + * + * @return void + */ + protected function configureKey() + { + $this->call('key:generate'); + } + + /** + * Configure the database. + * + * @param array $default + * + * @return void + */ + protected function configureDatabase(array $default = []) + { + $config = array_merge([ + 'DB_DRIVER' => null, + 'DB_HOST' => null, + 'DB_DATABASE' => null, + 'DB_USERNAME' => null, + 'DB_PASSWORD' => null, + 'DB_PORT' => null, + 'DB_PREFIX' => null, + ], $default); + + $config['DB_DRIVER'] = $this->choice('Which database driver do you want to use?', [ + 'mysql' => 'MySQL', + 'pgsql' => 'PostgreSQL', + 'sqlite' => 'SQLite', + ], $config['DB_DRIVER']); + + if ($config['DB_DRIVER'] === 'sqlite') { + $config['DB_DATABASE'] = $this->ask('Please provide the full path to your SQLite file.', $config['DB_DATABASE']); + } else { + $config['DB_HOST'] = $this->ask("What is the host of your {$config['DB_DRIVER']} database?", $config['DB_HOST']); + if ($config['DB_HOST'] === 'localhost' && $config['DB_DRIVER'] === 'mysql') { + $this->warn("Using 'localhost' will result in the usage of a local unix socket. Use 127.0.0.1 if you want to connect over TCP"); + } + + $config['DB_DATABASE'] = $this->ask('What is the name of the database that Cachet should use?', $config['DB_DATABASE']); + + $config['DB_USERNAME'] = $this->ask('What username should we connect with?', $config['DB_USERNAME']); + + $config['DB_PASSWORD'] = $this->secret('What password should we connect with?', $config['DB_PASSWORD']); + + $config['DB_PORT'] = $config['DB_DRIVER'] === 'mysql' ? 3306 : 5432; + if ($this->confirm('Is your database listening on a non-standard port number?')) { + $config['DB_PORT'] = $this->anticipate('What port number is your database using?', [3306, 5432], $config['DB_PORT']); + } + } + + if ($this->confirm('Do you want to use a prefix on the table names?')) { + $config['DB_PREFIX'] = $this->ask('Please enter the prefix now...', $config['DB_PREFIX']); + } + + // Format the settings ready to display them in the table. + $this->formatConfigsTable($config); + + if (!$this->confirm('Are these settings correct?')) { + return $this->configureDatabase($config); + } + + foreach ($config as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Configure other drivers. + * + * @param array $default + * + * @return void + */ + protected function configureDrivers(array $default = []) + { + $config = array_merge([ + 'CACHE_DRIVER' => null, + 'SESSION_DRIVER' => null, + 'QUEUE_DRIVER' => null, + ], $default); + + // Format the settings ready to display them in the table. + $this->formatConfigsTable($config); + + $config['CACHE_DRIVER'] = $this->choice('Which cache driver do you want to use?', [ + 'apc' => 'APC(u)', + 'array' => 'Array', + 'database' => 'Database', + 'file' => 'File', + 'memcached' => 'Memcached', + 'redis' => 'Redis', + ], $config['CACHE_DRIVER']); + + // We need to configure Redis. + if ($config['CACHE_DRIVER'] === 'redis') { + $this->configureRedis(); + } + + $config['SESSION_DRIVER'] = $this->choice('Which session driver do you want to use?', [ + 'apc' => 'APC(u)', + 'array' => 'Array', + 'database' => 'Database', + 'file' => 'File', + 'memcached' => 'Memcached', + 'redis' => 'Redis', + ], $config['SESSION_DRIVER']); + + // We need to configure Redis. + if ($config['SESSION_DRIVER'] === 'redis') { + $this->configureRedis(); + } + + $config['QUEUE_DRIVER'] = $this->choice('Which queue driver do you want to use?', [ + 'null' => 'None', + 'sync' => 'Synchronous', + 'database' => 'Database', + 'beanstalkd' => 'Beanstalk', + 'sqs' => 'Amazon SQS', + 'redis' => 'Redis', + ], $config['QUEUE_DRIVER']); + + // We need to configure Redis, but only if the cache driver wasn't redis. + if ($config['QUEUE_DRIVER'] === 'redis' && ($config['SESSION_DRIVER'] !== 'redis' || $config['CACHE_DRIVER'] !== 'redis')) { + $this->configureRedis(); + } + + // Format the settings ready to display them in the table. + $this->formatConfigsTable($config); + + if (!$this->confirm('Are these settings correct?')) { + return $this->configureDrivers($config); + } + + foreach ($config as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Configure mail. + * + * @param array $config + * + * @return void + */ + protected function configureMail(array $config = []) + { + $config = array_merge([ + 'MAIL_DRIVER' => null, + 'MAIL_HOST' => null, + 'MAIL_PORT' => null, + 'MAIL_USERNAME' => null, + 'MAIL_PASSWORD' => null, + 'MAIL_ADDRESS' => null, + 'MAIL_NAME' => null, + 'MAIL_ENCRYPTION' => null, + ], $config); + + // Don't continue with these settings if we're not interested in notifications. + if (!$this->confirm('Do you want Cachet to send mail notifications?')) { + return; + } + + $config['MAIL_DRIVER'] = $this->choice('What driver do you want to use to send notifications?', [ + 'smtp' => 'SMTP', + 'mail' => 'Mail', + 'sendmail' => 'Sendmail', + 'mailgun' => 'Mailgun', + 'mandrill' => 'Mandrill', + 'ses' => 'Amazon SES', + 'sparkpost' => 'SparkPost', + 'log' => 'Log (Testing)', + ]); + + if (!$config['MAIL_DRIVER'] === 'log') { + if ($config['MAIL_DRIVER'] === 'smtp') { + $config['MAIL_HOST'] = $this->ask('Please supply your mail server host'); + } + + $config['MAIL_ADDRESS'] = $this->ask('What email address should we send notifications from?'); + $config['MAIL_USERNAME'] = $this->ask('What username should we connect as?'); + $config['MAIL_PASSWORD'] = $this->secret('What password should we connect with?'); + } + + // Format the settings ready to display them in the table. + $this->formatConfigsTable($config); + + if (!$this->confirm('Are these settings correct?')) { + return $this->configureMail($config); + } + + foreach ($config as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Configure Cachet. + * + * @param array $config + * + * @return void + */ + protected function configureCachet(array $config = []) + { + $config = []; + if ($this->confirm('Do you wish to use Cachet Beacon?')) { + $config['CACHET_BEACON'] = 'true'; + } + + if ($this->confirm('Do you wish to use Emoji? This requires a GitHub oAuth Token!')) { + $config['GITHUB_TOKEN'] = $this->ask('Please enter your GitHub oAuth Token'); + $config['CACHET_EMOJI'] = 'true'; + } + + foreach ($config as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Configure the first user. + * + * @return void + */ + protected function configureUser() + { + if (!$this->confirm('Do you want to create an admin user?')) { + return; + } + + // We need to refresh the config to get access to the newly connected database. + $this->getFreshConfiguration(); + + // Now we need to install the application. + // $this->call('cachet:install'); + + $user = [ + 'username' => $this->ask('Please enter your username'), + 'email' => $this->ask('Please enter your email'), + 'password' => $this->secret('Please enter your password'), + 'level' => User::LEVEL_ADMIN, + ]; + + User::create($user); + } + + /** + * Configure the redis connection. + * + * @return void + */ + protected function configureRedis() + { + $config = [ + 'REDIS_HOST' => null, + 'REDIS_DATABASE' => null, + 'REDIS_PORT' => null, + ]; + + $config['REDIS_HOST'] = $this->ask('What is the host of your redis server?'); + $config['REDIS_DATABASE'] = $this->ask('What is the name of the database that Cachet should use?'); + $config['REDIS_PORT'] = $this->ask('What port should Cachet use?', 6379); + + foreach ($config as $setting => $value) { + $this->writeEnv($setting, $value); + } + } + + /** + * Format the configs into a pretty table that we can easily read. + * + * @param array $config + * + * @return void + */ + protected function formatConfigsTable(array $config) + { + $configRows = []; + + foreach ($config as $setting => $value) { + $configRows[] = compact('setting', 'value'); + } + + $this->table(['Setting', 'Value'], $configRows); + } + + /** + * Boot a fresh copy of the application configuration. + * + * @return void + */ + protected function getFreshConfiguration() + { + $app = require $this->laravel->bootstrapPath().'/app.php'; + $app->make(Kernel::class)->bootstrap(); + } + + /** + * Writes to the .env file with given parameters. + * + * @param string $key + * @param mixed $value + * + * @return void + */ + protected function writeEnv($key, $value) + { + $dir = app()->environmentPath(); + $file = app()->environmentFile(); + $path = "{$dir}/{$file}"; + + try { + (new Dotenv($dir, $file))->load(); + + $envKey = strtoupper($key); + $envValue = env($envKey) ?: 'null'; + + $envFileContents = file_get_contents($path); + $envFileContents = str_replace("{$envKey}={$envValue}", "{$envKey}={$value}", $envFileContents, $count); + if ($count < 1 && $envValue === 'null') { + $envFileContents = str_replace("{$envKey}=", "{$envKey}={$value}", $envFileContents); + } + file_put_contents($path, $envFileContents); + } catch (InvalidPathException $e) { + throw $e; + } + } +} diff --git a/app/Console/Commands/VersionCommand.php b/app/Console/Commands/VersionCommand.php new file mode 100644 index 00000000000..e093fe7a07f --- /dev/null +++ b/app/Console/Commands/VersionCommand.php @@ -0,0 +1,46 @@ + + */ +class VersionCommand extends Command +{ + /** + * The console command name. + * + * @var string + */ + protected $name = 'cachet:version'; + + /** + * The console command description. + * + * @var string + */ + protected $description = 'Display the version of Cachet'; + + /** + * Execute the console command. + * + * @return void + */ + public function handle() + { + $this->info('Cachet '.CACHET_VERSION.' is installed ⚡'); + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index d1c9686b261..12bc4a2ab21 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -11,11 +11,23 @@ namespace CachetHQ\Cachet\Console; +use CachetHQ\Cachet\Console\Commands\AppResetCommand; +use CachetHQ\Cachet\Console\Commands\AppUpdateCommand; +use CachetHQ\Cachet\Console\Commands\BeaconCommand; use CachetHQ\Cachet\Console\Commands\DemoMetricPointSeederCommand; use CachetHQ\Cachet\Console\Commands\DemoSeederCommand; +use CachetHQ\Cachet\Console\Commands\InstallCommand; +use CachetHQ\Cachet\Console\Commands\VersionCommand; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; +/** + * This is the console kernel class. + * + * @author Graham Campbell + * @author Joseph Cohen + * @author James Brooks + */ class Kernel extends ConsoleKernel { /** @@ -24,8 +36,13 @@ class Kernel extends ConsoleKernel * @var array */ protected $commands = [ + AppResetCommand::class, + AppUpdateCommand::class, + BeaconCommand::class, DemoMetricPointSeederCommand::class, DemoSeederCommand::class, + InstallCommand::class, + VersionCommand::class, ]; /** @@ -37,6 +54,6 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule) { - $schedule->command('queue:work --sleep=3 --tries=3')->everyMinute(); + $schedule->command('cachet:beacon')->twiceDaily(0, 12); } } diff --git a/app/Foundation/Exceptions/Displayers/JsonValidationDisplayer.php b/app/Exceptions/Displayers/JsonValidationDisplayer.php similarity index 90% rename from app/Foundation/Exceptions/Displayers/JsonValidationDisplayer.php rename to app/Exceptions/Displayers/JsonValidationDisplayer.php index 02fd20ad3cb..bb3d0c5014e 100644 --- a/app/Foundation/Exceptions/Displayers/JsonValidationDisplayer.php +++ b/app/Exceptions/Displayers/JsonValidationDisplayer.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Foundation\Exceptions\Displayers; +namespace CachetHQ\Cachet\Exceptions\Displayers; use AltThree\Validator\ValidationException; use Exception; @@ -29,7 +29,7 @@ class JsonValidationDisplayer extends JsonDisplayer implements DisplayerInterfac * * @return \Symfony\Component\HttpFoundation\Response */ - public function display(Exception $exception, $id, $code, array $headers) + public function display(Exception $exception, string $id, int $code, array $headers) { $info = $this->info->generate($exception, $id, 400); @@ -47,7 +47,7 @@ public function display(Exception $exception, $id, $code, array $headers) * * @return bool */ - public function canDisplay(Exception $original, Exception $transformed, $code) + public function canDisplay(Exception $original, Exception $transformed, int $code) { return $transformed instanceof ValidationException; } diff --git a/app/Exceptions/Displayers/MaintenanceDisplayer.php b/app/Exceptions/Displayers/MaintenanceDisplayer.php new file mode 100644 index 00000000000..20b4a16d5e7 --- /dev/null +++ b/app/Exceptions/Displayers/MaintenanceDisplayer.php @@ -0,0 +1,104 @@ + + */ +class MaintenanceDisplayer implements DisplayerInterface +{ + /** + * The view factory instance. + * + * @var \Illuminate\Contracts\View\Factory + */ + protected $view; + + /** + * Create a new maintenance displayer instance. + * + * @param \Illuminate\Contracts\View\Factory $view + * + * @return void + */ + public function __construct(Factory $view) + { + $this->view = $view; + } + + /** + * Get the error response associated with the given exception. + * + * @param \Exception $exception + * @param string $id + * @param int $code + * @param string[] $headers + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function display(Exception $exception, string $id, int $code, array $headers) + { + return new Response($this->render(), $code, array_merge($headers, ['Content-Type' => $this->contentType()])); + } + + /** + * Render the page. + * + * @return string + */ + protected function render() + { + return $this->view->make('errors.maintenance')->render(); + } + + /** + * Get the supported content type. + * + * @return string + */ + public function contentType() + { + return 'text/html'; + } + + /** + * Can we display the exception? + * + * @param \Exception $original + * @param \Exception $transformed + * @param int $code + * + * @return bool + */ + public function canDisplay(Exception $original, Exception $transformed, int $code) + { + return $transformed instanceof MaintenanceModeException; + } + + /** + * Do we provide verbose information about the exception? + * + * @return bool + */ + public function isVerbose() + { + return false; + } +} diff --git a/app/Foundation/Exceptions/Displayers/RedirectDisplayer.php b/app/Exceptions/Displayers/RedirectDisplayer.php similarity index 92% rename from app/Foundation/Exceptions/Displayers/RedirectDisplayer.php rename to app/Exceptions/Displayers/RedirectDisplayer.php index 147a2c97618..7a1670cbf77 100644 --- a/app/Foundation/Exceptions/Displayers/RedirectDisplayer.php +++ b/app/Exceptions/Displayers/RedirectDisplayer.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Foundation\Exceptions\Displayers; +namespace CachetHQ\Cachet\Exceptions\Displayers; use Exception; use GrahamCampbell\Exceptions\Displayers\DisplayerInterface; @@ -47,7 +47,7 @@ public function __construct(Request $request) * * @return \Symfony\Component\HttpFoundation\Response */ - public function display(Exception $exception, $id, $code, array $headers) + public function display(Exception $exception, string $id, int $code, array $headers) { return redirect()->guest('auth/login'); } @@ -71,7 +71,7 @@ public function contentType() * * @return bool */ - public function canDisplay(Exception $original, Exception $transformed, $code) + public function canDisplay(Exception $original, Exception $transformed, int $code) { $redirect = $transformed instanceof HttpExceptionInterface && $transformed->getStatusCode() === 401; diff --git a/app/Exceptions/Displayers/SettingsDisplayer.php b/app/Exceptions/Displayers/SettingsDisplayer.php new file mode 100644 index 00000000000..d3a76d0408a --- /dev/null +++ b/app/Exceptions/Displayers/SettingsDisplayer.php @@ -0,0 +1,88 @@ +request = $request; + } + + /** + * Get the error response associated with the given exception. + * + * @param \Exception $exception + * @param string $id + * @param int $code + * @param string[] $headers + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function display(Exception $exception, string $id, int $code, array $headers) + { + return cachet_redirect('setup'); + } + + /** + * Get the supported content type. + * + * @return string + */ + public function contentType() + { + return 'text/html'; + } + + /** + * Can we display the exception? + * + * @param \Exception $original + * @param \Exception $transformed + * @param int $code + * + * @return bool + */ + public function canDisplay(Exception $original, Exception $transformed, int $code) + { + return ($transformed instanceof ReadException) && !$this->request->is('setup*'); + } + + /** + * Do we provide verbose information about the exception? + * + * @return bool + */ + public function isVerbose() + { + return false; + } +} diff --git a/app/Foundation/Exceptions/Displayers/ThrottleDisplayer.php b/app/Exceptions/Displayers/ThrottleDisplayer.php similarity index 87% rename from app/Foundation/Exceptions/Displayers/ThrottleDisplayer.php rename to app/Exceptions/Displayers/ThrottleDisplayer.php index f36871db921..5f1907c7d7d 100644 --- a/app/Foundation/Exceptions/Displayers/ThrottleDisplayer.php +++ b/app/Exceptions/Displayers/ThrottleDisplayer.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Foundation\Exceptions\Displayers; +namespace CachetHQ\Cachet\Exceptions\Displayers; use Exception; use GrahamCampbell\Exceptions\Displayers\DisplayerInterface; @@ -47,9 +47,9 @@ public function __construct(Request $request) * * @return \Symfony\Component\HttpFoundation\Response */ - public function display(Exception $exception, $id, $code, array $headers) + public function display(Exception $exception, string $id, int $code, array $headers) { - return redirect()->route('auth.login')->withError(trans('forms.login.rate-limit')); + return cachet_redirect('auth.login')->withError(trans('forms.login.rate-limit')); } /** @@ -71,7 +71,7 @@ public function contentType() * * @return bool */ - public function canDisplay(Exception $original, Exception $transformed, $code) + public function canDisplay(Exception $original, Exception $transformed, int $code) { return $transformed instanceof TooManyRequestsHttpException && $this->request->is('auth*'); } diff --git a/app/Foundation/Exceptions/Filters/ApiFilter.php b/app/Exceptions/Filters/ApiFilter.php similarity index 84% rename from app/Foundation/Exceptions/Filters/ApiFilter.php rename to app/Exceptions/Filters/ApiFilter.php index e824de2a495..8d12e4dbffc 100644 --- a/app/Foundation/Exceptions/Filters/ApiFilter.php +++ b/app/Exceptions/Filters/ApiFilter.php @@ -9,10 +9,11 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Foundation\Exceptions\Filters; +namespace CachetHQ\Cachet\Exceptions\Filters; use Exception; use Illuminate\Http\Request; +use Illuminate\Support\Str; class ApiFilter { @@ -27,11 +28,11 @@ class ApiFilter * * @return \GrahamCampbell\Exceptions\Displayers\DisplayerInterface[] */ - public function filter(array $displayers, Request $request, Exception $original, Exception $transformed, $code) + public function filter(array $displayers, Request $request, Exception $original, Exception $transformed, int $code) { if ($request->is('api*')) { foreach ($displayers as $index => $displayer) { - if (!str_contains($displayer->contentType(), 'application/')) { + if (!Str::contains($displayer->contentType(), 'application/')) { unset($displayers[$index]); } } diff --git a/app/Foundation/Exceptions/Transformers/BusTransformer.php b/app/Exceptions/Transformers/BusTransformer.php similarity index 93% rename from app/Foundation/Exceptions/Transformers/BusTransformer.php rename to app/Exceptions/Transformers/BusTransformer.php index 6ffd879a2e9..be0b2fe5cb1 100644 --- a/app/Foundation/Exceptions/Transformers/BusTransformer.php +++ b/app/Exceptions/Transformers/BusTransformer.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Foundation\Exceptions\Transformers; +namespace CachetHQ\Cachet\Exceptions\Transformers; use CachetHQ\Cachet\Bus\Exceptions\ExceptionInterface; use Exception; diff --git a/app/Foundation/Providers/ComposerServiceProvider.php b/app/Foundation/Providers/ComposerServiceProvider.php deleted file mode 100644 index 7831d008bce..00000000000 --- a/app/Foundation/Providers/ComposerServiceProvider.php +++ /dev/null @@ -1,51 +0,0 @@ -composer('*', AppComposer::class); - $factory->composer('*', CurrentUserComposer::class); - $factory->composer(['index'], MetricsComposer::class); - $factory->composer(['index', 'single-incident', 'subscribe', 'signup'], StatusPageComposer::class); - $factory->composer(['index', 'single-incident', 'subscribe.*', 'signup', 'dashboard.settings.theme', 'emails.*'], ThemeComposer::class); - $factory->composer('dashboard.*', DashboardComposer::class); - $factory->composer(['setup', 'dashboard.settings.localization'], TimezoneLocaleComposer::class); - } - - /** - * Register the service provider. - * - * @return void - */ - public function register() - { - // - } -} diff --git a/app/Foundation/Providers/EventServiceProvider.php b/app/Foundation/Providers/EventServiceProvider.php deleted file mode 100644 index b8f18b9bcc3..00000000000 --- a/app/Foundation/Providers/EventServiceProvider.php +++ /dev/null @@ -1,94 +0,0 @@ - [ - // - ], - 'CachetHQ\Cachet\Bus\Events\ComponentGroup\ComponentGroupWasRemovedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\ComponentGroup\ComponentGroupWasUpdatedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Component\ComponentWasAddedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Component\ComponentWasRemovedEvent' => [ - 'CachetHQ\Cachet\Bus\Handlers\Events\Component\CleanupComponentSubscriptionsHandler', - ], - 'CachetHQ\Cachet\Bus\Events\Component\ComponentWasUpdatedEvent' => [ - 'CachetHQ\Cachet\Bus\Handlers\Events\Component\SendComponentUpdateEmailNotificationHandler', - ], - 'CachetHQ\Cachet\Bus\Events\Incident\IncidentWasRemovedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Incident\IncidentWasReportedEvent' => [ - 'CachetHQ\Cachet\Bus\Handlers\Events\Incident\SendIncidentEmailNotificationHandler', - ], - 'CachetHQ\Cachet\Bus\Events\Incident\IncidentWasUpdatedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Incident\MaintenanceWasScheduledEvent' => [ - 'CachetHQ\Cachet\Bus\Handlers\Events\Incident\SendMaintenanceEmailNotificationHandler', - ], - 'CachetHQ\Cachet\Bus\Events\Invite\InviteWasClaimedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Metric\MetricPointWasAddedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Metric\MetricPointWasRemovedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Metric\MetricPointWasUpdatedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Metric\MetricWasAddedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Metric\MetricWasRemovedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Metric\MetricWasUpdatedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasSubscribedEvent' => [ - 'CachetHQ\Cachet\Bus\Handlers\Events\Subscriber\SendSubscriberVerificationEmailHandler', - ], - 'CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasUnsubscribedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasUpdatedSubscriptionsEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasVerifiedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\User\UserWasAddedEvent' => [ - // - ], - 'CachetHQ\Cachet\Bus\Events\User\UserWasInvitedEvent' => [ - 'CachetHQ\Cachet\Bus\Handlers\Events\User\SendInviteUserEmailHandler', - ], - ]; -} diff --git a/app/Foundation/Providers/RouteServiceProvider.php b/app/Foundation/Providers/RouteServiceProvider.php deleted file mode 100644 index cc97eb0453e..00000000000 --- a/app/Foundation/Providers/RouteServiceProvider.php +++ /dev/null @@ -1,76 +0,0 @@ -registerBindings(); - } - - /** - * Register model bindings. - * - * @return void - */ - protected function registerBindings() - { - $this->app->router->model('component', 'CachetHQ\Cachet\Models\Component'); - $this->app->router->model('component_group', 'CachetHQ\Cachet\Models\ComponentGroup'); - $this->app->router->model('incident', 'CachetHQ\Cachet\Models\Incident'); - $this->app->router->model('incident_template', 'CachetHQ\Cachet\Models\IncidentTemplate'); - $this->app->router->model('metric', 'CachetHQ\Cachet\Models\Metric'); - $this->app->router->model('metric_point', 'CachetHQ\Cachet\Models\MetricPoint'); - $this->app->router->model('setting', 'CachetHQ\Cachet\Models\Setting'); - $this->app->router->model('subscriber', 'CachetHQ\Cachet\Models\Subscriber'); - $this->app->router->model('subscription', 'CachetHQ\Cachet\Models\Subscription'); - $this->app->router->model('user', 'CachetHQ\Cachet\Models\User'); - } - - /** - * Define the routes for the application. - * - * @param \Illuminate\Routing\Router $router - * - * @return void - */ - public function map(Router $router) - { - $router->group(['namespace' => $this->namespace], function (Router $router) { - foreach (glob(app_path('Http//Routes').'/*.php') as $file) { - $this->app->make('CachetHQ\\Cachet\\Http\\Routes\\'.basename($file, '.php'))->map($router); - } - }); - } -} diff --git a/app/Http/Controllers/Api/AbstractApiController.php b/app/Http/Controllers/Api/AbstractApiController.php index 4b871c5be28..10be23db248 100644 --- a/app/Http/Controllers/Api/AbstractApiController.php +++ b/app/Http/Controllers/Api/AbstractApiController.php @@ -141,7 +141,7 @@ protected function paginator(Paginator $paginator, Request $request) { foreach ($request->query as $key => $value) { if ($key != 'page') { - $paginator->addQuery($key, $value); + $paginator->appends($key, $value); } } diff --git a/app/Http/Controllers/Api/ComponentController.php b/app/Http/Controllers/Api/ComponentController.php index 35c43a8ad13..9bda7b09cb5 100644 --- a/app/Http/Controllers/Api/ComponentController.php +++ b/app/Http/Controllers/Api/ComponentController.php @@ -11,11 +11,10 @@ namespace CachetHQ\Cachet\Http\Controllers\Api; -use CachetHQ\Cachet\Bus\Commands\Component\AddComponentCommand; +use CachetHQ\Cachet\Bus\Commands\Component\CreateComponentCommand; use CachetHQ\Cachet\Bus\Commands\Component\RemoveComponentCommand; use CachetHQ\Cachet\Bus\Commands\Component\UpdateComponentCommand; use CachetHQ\Cachet\Models\Component; -use CachetHQ\Cachet\Models\Tag; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Contracts\Auth\Guard; use Illuminate\Database\QueryException; @@ -29,7 +28,7 @@ class ComponentController extends AbstractApiController * * @return \Illuminate\Http\JsonResponse */ - public function getComponents() + public function index() { if (app(Guard::class)->check()) { $components = Component::query(); @@ -37,6 +36,10 @@ public function getComponents() $components = Component::enabled(); } + if ($tags = Binput::get('tags')) { + $components->withAnyTags($tags); + } + $components->search(Binput::except(['sort', 'order', 'per_page'])); if ($sortBy = Binput::get('sort')) { @@ -57,7 +60,7 @@ public function getComponents() * * @return \Illuminate\Http\JsonResponse */ - public function getComponent(Component $component) + public function show(Component $component) { return $this->item($component); } @@ -67,36 +70,24 @@ public function getComponent(Component $component) * * @return \Illuminate\Http\JsonResponse */ - public function postComponents() + public function store() { try { - $component = dispatch(new AddComponentCommand( + $component = execute(new CreateComponentCommand( Binput::get('name'), Binput::get('description'), Binput::get('status'), Binput::get('link'), Binput::get('order'), Binput::get('group_id'), - (bool) Binput::get('enabled', true) + (bool) Binput::get('enabled', true), + Binput::get('meta'), + Binput::get('tags') )); } catch (QueryException $e) { throw new BadRequestHttpException(); } - if (Binput::has('tags')) { - // The component was added successfully, so now let's deal with the tags. - $tags = preg_split('/ ?, ?/', Binput::get('tags')); - - // For every tag, do we need to create it? - $componentTags = array_map(function ($taggable) use ($component) { - return Tag::firstOrCreate([ - 'name' => $taggable, - ])->id; - }, $tags); - - $component->tags()->sync($componentTags); - } - return $this->item($component); } @@ -107,10 +98,10 @@ public function postComponents() * * @return \Illuminate\Http\JsonResponse */ - public function putComponent(Component $component) + public function update(Component $component) { try { - dispatch(new UpdateComponentCommand( + execute(new UpdateComponentCommand( $component, Binput::get('name'), Binput::get('description'), @@ -118,23 +109,15 @@ public function putComponent(Component $component) Binput::get('link'), Binput::get('order'), Binput::get('group_id'), - (bool) Binput::get('enabled', true) + Binput::get('enabled', $component->enabled), + Binput::get('meta'), + Binput::get('tags'), + (bool) Binput::get('silent', false) )); } catch (QueryException $e) { throw new BadRequestHttpException(); } - if (Binput::has('tags')) { - $tags = preg_split('/ ?, ?/', Binput::get('tags')); - - // For every tag, do we need to create it? - $componentTags = array_map(function ($taggable) use ($component) { - return Tag::firstOrCreate(['name' => $taggable])->id; - }, $tags); - - $component->tags()->sync($componentTags); - } - return $this->item($component); } @@ -145,9 +128,9 @@ public function putComponent(Component $component) * * @return \Illuminate\Http\JsonResponse */ - public function deleteComponent(Component $component) + public function destroy(Component $component) { - dispatch(new RemoveComponentCommand($component)); + execute(new RemoveComponentCommand($component)); return $this->noContent(); } diff --git a/app/Http/Controllers/Api/ComponentGroupController.php b/app/Http/Controllers/Api/ComponentGroupController.php index 9c424b79823..957106e101d 100644 --- a/app/Http/Controllers/Api/ComponentGroupController.php +++ b/app/Http/Controllers/Api/ComponentGroupController.php @@ -11,11 +11,12 @@ namespace CachetHQ\Cachet\Http\Controllers\Api; -use CachetHQ\Cachet\Bus\Commands\ComponentGroup\AddComponentGroupCommand; +use CachetHQ\Cachet\Bus\Commands\ComponentGroup\CreateComponentGroupCommand; use CachetHQ\Cachet\Bus\Commands\ComponentGroup\RemoveComponentGroupCommand; use CachetHQ\Cachet\Bus\Commands\ComponentGroup\UpdateComponentGroupCommand; use CachetHQ\Cachet\Models\ComponentGroup; use GrahamCampbell\Binput\Facades\Binput; +use Illuminate\Contracts\Auth\Guard; use Illuminate\Database\QueryException; use Illuminate\Support\Facades\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; @@ -25,23 +26,43 @@ * * @author James Brooks * @author Graham Campbell - * @author Joe Cohen + * @author Joseph Cohen */ class ComponentGroupController extends AbstractApiController { + /** + * The user session object. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $guard; + + /** + * Creates a new component group controller instance. + * + * @param \Illuminate\Contracts\Auth\Guard $guard + */ + public function __construct(Guard $guard) + { + $this->guard = $guard; + } + /** * Get all groups. * * @return \Illuminate\Http\JsonResponse */ - public function getGroups() + public function index() { $groups = ComponentGroup::query(); + if (!$this->guard->check()) { + $groups = ComponentGroup::visible(); + } $groups->search(Binput::except(['sort', 'order', 'per_page'])); if ($sortBy = Binput::get('sort')) { - $direction = Binput::has('order') && Binput::get('order') == 'desc'; + $direction = Binput::get('order', 'asc'); $groups->sort($sortBy, $direction); } @@ -58,7 +79,7 @@ public function getGroups() * * @return \Illuminate\Http\JsonResponse */ - public function getGroup(ComponentGroup $group) + public function show(ComponentGroup $group) { return $this->item($group); } @@ -68,13 +89,14 @@ public function getGroup(ComponentGroup $group) * * @return \Illuminate\Http\JsonResponse */ - public function postGroups() + public function store() { try { - $group = dispatch(new AddComponentGroupCommand( + $group = execute(new CreateComponentGroupCommand( Binput::get('name'), Binput::get('order', 0), - Binput::get('collapsed', 0) + Binput::get('collapsed', 0), + Binput::get('visible', ComponentGroup::VISIBLE_AUTHENTICATED) )); } catch (QueryException $e) { throw new BadRequestHttpException(); @@ -90,14 +112,15 @@ public function postGroups() * * @return \Illuminate\Http\JsonResponse */ - public function putGroup(ComponentGroup $group) + public function update(ComponentGroup $group) { try { - $group = dispatch(new UpdateComponentGroupCommand( + $group = execute(new UpdateComponentGroupCommand( $group, Binput::get('name'), Binput::get('order'), - Binput::get('collapsed') + Binput::get('collapsed'), + Binput::get('visible') )); } catch (QueryException $e) { throw new BadRequestHttpException(); @@ -113,9 +136,9 @@ public function putGroup(ComponentGroup $group) * * @return \Illuminate\Http\JsonResponse */ - public function deleteGroup(ComponentGroup $group) + public function destroy(ComponentGroup $group) { - dispatch(new RemoveComponentGroupCommand($group)); + execute(new RemoveComponentGroupCommand($group)); return $this->noContent(); } diff --git a/app/Http/Controllers/Api/GeneralController.php b/app/Http/Controllers/Api/GeneralController.php index 2fd7331eff0..23ba1fa4485 100644 --- a/app/Http/Controllers/Api/GeneralController.php +++ b/app/Http/Controllers/Api/GeneralController.php @@ -11,12 +11,13 @@ namespace CachetHQ\Cachet\Http\Controllers\Api; -use CachetHQ\Cachet\Integrations\Releases; +use CachetHQ\Cachet\Integrations\Contracts\Releases; +use CachetHQ\Cachet\Integrations\Contracts\System; /** * This is the general api controller. * - * @author James Brooks + * @author James Brooks */ class GeneralController extends AbstractApiController { @@ -37,11 +38,26 @@ public function ping() */ public function version() { - $latest = app(Releases::class)->latest(); + $latest = app()->make(Releases::class)->latest(); return $this->setMetaData([ 'on_latest' => version_compare(CACHET_VERSION, $latest['tag_name']) === 1, 'latest' => $latest, ])->item(CACHET_VERSION); } + + /** + * Get the system status message. + * + * @return \Illuminate\Http\JsonResponse + */ + public function status() + { + $system = app()->make(System::class)->getStatus(); + + return $this->item([ + 'status' => $system['system_status'], + 'message' => $system['system_message'], + ]); + } } diff --git a/app/Http/Controllers/Api/IncidentController.php b/app/Http/Controllers/Api/IncidentController.php index 3a3066e695f..cd705519f58 100644 --- a/app/Http/Controllers/Api/IncidentController.php +++ b/app/Http/Controllers/Api/IncidentController.php @@ -11,8 +11,8 @@ namespace CachetHQ\Cachet\Http\Controllers\Api; +use CachetHQ\Cachet\Bus\Commands\Incident\CreateIncidentCommand; use CachetHQ\Cachet\Bus\Commands\Incident\RemoveIncidentCommand; -use CachetHQ\Cachet\Bus\Commands\Incident\ReportIncidentCommand; use CachetHQ\Cachet\Bus\Commands\Incident\UpdateIncidentCommand; use CachetHQ\Cachet\Models\Incident; use GrahamCampbell\Binput\Facades\Binput; @@ -28,7 +28,7 @@ class IncidentController extends AbstractApiController * * @return \Illuminate\Http\JsonResponse */ - public function getIncidents() + public function index() { $incidentVisibility = app(Guard::class)->check() ? 0 : 1; @@ -54,7 +54,7 @@ public function getIncidents() * * @return \Illuminate\Http\JsonResponse */ - public function getIncident(Incident $incident) + public function show(Incident $incident) { return $this->item($incident); } @@ -64,20 +64,22 @@ public function getIncident(Incident $incident) * * @return \Illuminate\Http\JsonResponse */ - public function postIncidents() + public function store() { try { - $incident = dispatch(new ReportIncidentCommand( + $incident = execute(new CreateIncidentCommand( Binput::get('name'), Binput::get('status'), - Binput::get('message'), - Binput::get('visible', true), + Binput::get('message', null, false, false), + (bool) Binput::get('visible', true), Binput::get('component_id'), Binput::get('component_status'), - Binput::get('notify', true), - Binput::get('created_at'), + (bool) Binput::get('notify', true), + (bool) Binput::get('stickied', false), + Binput::get('occurred_at'), Binput::get('template'), - Binput::get('vars') + Binput::get('vars', []), + Binput::get('meta', []) )); } catch (QueryException $e) { throw new BadRequestHttpException(); @@ -93,21 +95,22 @@ public function postIncidents() * * @return \Illuminate\Http\JsonResponse */ - public function putIncident(Incident $incident) + public function update(Incident $incident) { try { - $incident = dispatch(new UpdateIncidentCommand( + $incident = execute(new UpdateIncidentCommand( $incident, Binput::get('name'), Binput::get('status'), Binput::get('message'), - Binput::get('visible', true), + (bool) Binput::get('visible', true), Binput::get('component_id'), Binput::get('component_status'), - Binput::get('notify', true), - Binput::get('created_at'), + (bool) Binput::get('notify', true), + (bool) Binput::get('stickied', false), + Binput::get('occurred_at'), Binput::get('template'), - Binput::get('vars') + Binput::get('vars', []) )); } catch (QueryException $e) { throw new BadRequestHttpException(); @@ -123,9 +126,9 @@ public function putIncident(Incident $incident) * * @return \Illuminate\Http\JsonResponse */ - public function deleteIncident(Incident $incident) + public function destroy(Incident $incident) { - dispatch(new RemoveIncidentCommand($incident)); + execute(new RemoveIncidentCommand($incident)); return $this->noContent(); } diff --git a/app/Http/Controllers/Api/IncidentTemplateController.php b/app/Http/Controllers/Api/IncidentTemplateController.php new file mode 100644 index 00000000000..3f1ba418356 --- /dev/null +++ b/app/Http/Controllers/Api/IncidentTemplateController.php @@ -0,0 +1,51 @@ +sort($sortBy, $direction); + } + + $templates = $templates->paginate(Binput::get('per_page', 20)); + + return $this->paginator($templates, Request::instance()); + } + + /** + * Get a single incident templates. + * + * @param \CachetHQ\Cachet\Models\IncidentTemplate $incidentTemplate + * + * @return \Illuminate\Http\JsonResponse + */ + public function show(IncidentTemplate $incidentTemplate) + { + return $this->item($incidentTemplate); + } +} diff --git a/app/Http/Controllers/Api/IncidentUpdateController.php b/app/Http/Controllers/Api/IncidentUpdateController.php new file mode 100644 index 00000000000..0c239a6a431 --- /dev/null +++ b/app/Http/Controllers/Api/IncidentUpdateController.php @@ -0,0 +1,134 @@ + + */ +class IncidentUpdateController extends AbstractApiController +{ + /** + * Return all updates on the incident. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * + * @return \Illuminate\Http\JsonResponse + */ + public function index(Incident $incident) + { + $updates = $incident->updates()->orderBy('created_at', 'desc'); + + if ($sortBy = Binput::get('sort')) { + $direction = Binput::has('order') && Binput::get('order') == 'desc'; + + $updates->sort($sortBy, $direction); + } + + $updates = $updates->paginate(Binput::get('per_page', 20)); + + return $this->paginator($updates, Request::instance()); + } + + /** + * Return a single incident update. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * @param \CachetHQ\Cachet\Models\IncidentUpdate $update + * + * @return \Illuminate\Http\JsonResponse + */ + public function show(Incident $incident, IncidentUpdate $update) + { + return $this->item($update); + } + + /** + * Create a new incident update. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * + * @return \Illuminate\Http\JsonResponse + */ + public function store(Incident $incident) + { + try { + $update = execute(new CreateIncidentUpdateCommand( + $incident, + Binput::get('status'), + Binput::get('message'), + Binput::get('component_id'), + Binput::get('component_status'), + Auth::user() + )); + } catch (QueryException $e) { + throw new BadRequestHttpException(); + } + + return $this->item($update); + } + + /** + * Update an incident update. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * @param \CachetHQ\Cachet\Models\IncidentUpdate $update + * + * @return \Illuminate\Http\JsonResponse + */ + public function update(Incident $incident, IncidentUpdate $update) + { + try { + $update = execute(new UpdateIncidentUpdateCommand( + $update, + Binput::get('status'), + Binput::get('message'), + Auth::user() + )); + } catch (QueryException $e) { + throw new BadRequestHttpException(); + } + + return $this->item($update); + } + + /** + * Create a new incident update. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * @param \CachetHQ\Cachet\Models\IncidentUpdate $update + * + * @return \Illuminate\Http\JsonResponse + */ + public function destroy(Incident $incident, IncidentUpdate $update) + { + try { + execute(new RemoveIncidentUpdateCommand($update)); + } catch (QueryException $e) { + throw new BadRequestHttpException(); + } + + return $this->noContent(); + } +} diff --git a/app/Http/Controllers/Api/MetricController.php b/app/Http/Controllers/Api/MetricController.php index d8b931b01bb..4ef2e1e4fd3 100644 --- a/app/Http/Controllers/Api/MetricController.php +++ b/app/Http/Controllers/Api/MetricController.php @@ -11,7 +11,7 @@ namespace CachetHQ\Cachet\Http\Controllers\Api; -use CachetHQ\Cachet\Bus\Commands\Metric\AddMetricCommand; +use CachetHQ\Cachet\Bus\Commands\Metric\CreateMetricCommand; use CachetHQ\Cachet\Bus\Commands\Metric\RemoveMetricCommand; use CachetHQ\Cachet\Bus\Commands\Metric\UpdateMetricCommand; use CachetHQ\Cachet\Models\Metric; @@ -27,7 +27,7 @@ class MetricController extends AbstractApiController * * @return \Illuminate\Database\Eloquent\Collection */ - public function getMetrics() + public function index() { $metrics = Metric::query(); @@ -49,34 +49,20 @@ public function getMetrics() * * @return \Illuminate\Http\JsonResponse */ - public function getMetric(Metric $metric) + public function show(Metric $metric) { return $this->item($metric); } - /** - * Get all metric points. - * - * @param \CachetHQ\Cachet\Models\Metric $metric - * - * @return \Illuminate\Database\Eloquent\Collection - */ - public function getMetricPoints(Metric $metric) - { - $points = $metric->points()->paginate(Binput::get('per_page', 20)); - - return $this->paginator($points, Request::instance()); - } - /** * Create a new metric. * * @return \Illuminate\Http\JsonResponse */ - public function postMetrics() + public function store() { try { - $metric = dispatch(new AddMetricCommand( + $metric = execute(new CreateMetricCommand( Binput::get('name'), Binput::get('suffix'), Binput::get('description'), @@ -86,7 +72,8 @@ public function postMetrics() Binput::get('places', 2), Binput::get('default_view', Binput::get('view', 1)), Binput::get('threshold', 5), - Binput::get('order', 0) + Binput::get('order', 0), + Binput::get('visible', 1) )); } catch (QueryException $e) { throw new BadRequestHttpException(); @@ -102,10 +89,10 @@ public function postMetrics() * * @return \Illuminate\Http\JsonResponse */ - public function putMetric(Metric $metric) + public function update(Metric $metric) { try { - $metric = dispatch(new UpdateMetricCommand( + $metric = execute(new UpdateMetricCommand( $metric, Binput::get('name'), Binput::get('suffix'), @@ -116,7 +103,8 @@ public function putMetric(Metric $metric) Binput::get('places'), Binput::get('default_view', Binput::get('view')), Binput::get('threshold'), - Binput::get('order') + Binput::get('order'), + Binput::get('visible') )); } catch (QueryException $e) { throw new BadRequestHttpException(); @@ -132,9 +120,9 @@ public function putMetric(Metric $metric) * * @return \Illuminate\Http\JsonResponse */ - public function deleteMetric(Metric $metric) + public function destroy(Metric $metric) { - dispatch(new RemoveMetricCommand($metric)); + execute(new RemoveMetricCommand($metric)); return $this->noContent(); } diff --git a/app/Http/Controllers/Api/MetricPointController.php b/app/Http/Controllers/Api/MetricPointController.php index a84758d9334..8afb5c59ed1 100644 --- a/app/Http/Controllers/Api/MetricPointController.php +++ b/app/Http/Controllers/Api/MetricPointController.php @@ -11,13 +11,14 @@ namespace CachetHQ\Cachet\Http\Controllers\Api; -use CachetHQ\Cachet\Bus\Commands\Metric\AddMetricPointCommand; +use CachetHQ\Cachet\Bus\Commands\Metric\CreateMetricPointCommand; use CachetHQ\Cachet\Bus\Commands\Metric\RemoveMetricPointCommand; use CachetHQ\Cachet\Bus\Commands\Metric\UpdateMetricPointCommand; use CachetHQ\Cachet\Models\Metric; use CachetHQ\Cachet\Models\MetricPoint; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Database\QueryException; +use Illuminate\Support\Facades\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; class MetricPointController extends AbstractApiController @@ -30,9 +31,11 @@ class MetricPointController extends AbstractApiController * * @return \Illuminate\Http\JsonResponse */ - public function getMetricPoints(Metric $metric, MetricPoint $metricPoint) + public function index(Metric $metric, MetricPoint $metricPoint) { - return $this->item($metricPoint); + $points = $metric->points()->paginate(Binput::get('per_page', 20)); + + return $this->paginator($points, Request::instance()); } /** @@ -42,10 +45,10 @@ public function getMetricPoints(Metric $metric, MetricPoint $metricPoint) * * @return \Illuminate\Http\JsonResponse */ - public function postMetricPoints(Metric $metric) + public function store(Metric $metric) { try { - $metricPoint = dispatch(new AddMetricPointCommand( + $metricPoint = execute(new CreateMetricPointCommand( $metric, Binput::get('value'), Binput::get('timestamp') @@ -61,13 +64,13 @@ public function postMetricPoints(Metric $metric) * Updates a metric point. * * @param \CachetHQ\Cachet\Models\Metric $metric - * @param \CachetHQ\Cachet\Models\MetircPoint $metricPoint + * @param \CachetHQ\Cachet\Models\MetricPoint $metricPoint * * @return \Illuminate\Http\JsonResponse */ - public function putMetricPoint(Metric $metric, MetricPoint $metricPoint) + public function update(Metric $metric, MetricPoint $metricPoint) { - $metricPoint = dispatch(new UpdateMetricPointCommand( + $metricPoint = execute(new UpdateMetricPointCommand( $metricPoint, $metric, Binput::get('value'), @@ -85,9 +88,9 @@ public function putMetricPoint(Metric $metric, MetricPoint $metricPoint) * * @return \Illuminate\Http\JsonResponse */ - public function deleteMetricPoint(Metric $metric, MetricPoint $metricPoint) + public function destroy(Metric $metric, MetricPoint $metricPoint) { - dispatch(new RemoveMetricPointCommand($metricPoint)); + execute(new RemoveMetricPointCommand($metricPoint)); return $this->noContent(); } diff --git a/app/Http/Controllers/Api/ScheduleController.php b/app/Http/Controllers/Api/ScheduleController.php new file mode 100644 index 00000000000..c59f46dbd62 --- /dev/null +++ b/app/Http/Controllers/Api/ScheduleController.php @@ -0,0 +1,129 @@ + + */ +class ScheduleController extends AbstractApiController +{ + /** + * Return all schedules. + * + * @return \Illuminate\Http\JsonResponse + */ + public function index() + { + $schedule = Schedule::query(); + + if ($sortBy = Binput::get('sort')) { + $direction = Binput::has('order') && Binput::get('order') == 'desc'; + + $schedule->sort($sortBy, $direction); + } + + $schedule = $schedule->paginate(Binput::get('per_page', 20)); + + return $this->paginator($schedule, Request::instance()); + } + + /** + * Return a single schedule. + * + * @param \CachetHQ\Cachet\Models\Schedule $schedule + * + * @return \Illuminate\Http\JsonResponse + */ + public function show(Schedule $schedule) + { + return $this->item($schedule); + } + + /** + * Create a new schedule. + * + * @return \Illuminate\Http\JsonResponse + */ + public function store() + { + try { + $schedule = execute(new CreateScheduleCommand( + Binput::get('name'), + Binput::get('message', null, false, false), + Binput::get('status'), + Binput::get('scheduled_at'), + Binput::get('completed_at'), + Binput::get('components', []), + Binput::get('notify', false) + )); + } catch (QueryException $e) { + throw new BadRequestHttpException(); + } + + return $this->item($schedule); + } + + /** + * Update a schedule. + * + * @param \CachetHQ\Cachet\Models\Schedule $schedule + * + * @return \Illuminate\Http\JsonResponse + */ + public function update(Schedule $schedule) + { + try { + $schedule = execute(new UpdateScheduleCommand( + $schedule, + Binput::get('name'), + Binput::get('message'), + Binput::get('status'), + Binput::get('scheduled_at'), + Binput::get('completed_at'), + Binput::get('components', []) + )); + } catch (QueryException $e) { + throw new BadRequestHttpException(); + } + + return $this->item($schedule); + } + + /** + * Delete a schedule. + * + * @param \CachetHQ\Cachet\Models\Schedule $schedule + * + * @return \Illuminate\Http\JsonResponse + */ + public function destroy(Schedule $schedule) + { + try { + execute(new DeleteScheduleCommand($schedule)); + } catch (QueryException $e) { + throw new BadRequestHttpException(); + } + + return $this->noContent(); + } +} diff --git a/app/Http/Controllers/Api/SubscriberController.php b/app/Http/Controllers/Api/SubscriberController.php index 42eeec094eb..621aa06d70b 100644 --- a/app/Http/Controllers/Api/SubscriberController.php +++ b/app/Http/Controllers/Api/SubscriberController.php @@ -13,10 +13,9 @@ use CachetHQ\Cachet\Bus\Commands\Subscriber\SubscribeSubscriberCommand; use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriberCommand; -use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriptionCommand; use CachetHQ\Cachet\Models\Subscriber; -use CachetHQ\Cachet\Models\Subscription; use GrahamCampbell\Binput\Facades\Binput; +use Illuminate\Contracts\Config\Repository; use Illuminate\Database\QueryException; use Illuminate\Support\Facades\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; @@ -34,7 +33,7 @@ class SubscriberController extends AbstractApiController * * @return \Illuminate\Http\JsonResponse */ - public function getSubscribers() + public function index() { $subscribers = Subscriber::paginate(Binput::get('per_page', 20)); @@ -46,14 +45,12 @@ public function getSubscribers() * * @return \Illuminate\Http\JsonResponse */ - public function postSubscribers() + public function store() { + $verified = Binput::get('verify', app(Repository::class)->get('setting.skip_subscriber_verification')); + try { - $subscriber = dispatch(new SubscribeSubscriberCommand( - Binput::get('email'), - Binput::get('verify', false), - Binput::get('components', null) - )); + $subscriber = execute(new SubscribeSubscriberCommand(Binput::get('email'), $verified, Binput::get('components', null))); } catch (QueryException $e) { throw new BadRequestHttpException(); } @@ -68,23 +65,9 @@ public function postSubscribers() * * @return \Illuminate\Http\JsonResponse */ - public function deleteSubscriber(Subscriber $subscriber) - { - dispatch(new UnsubscribeSubscriberCommand($subscriber)); - - return $this->noContent(); - } - - /** - * Delete a subscriber. - * - * @param \CachetHQ\Cachet\Models\Subscriber $subscriber - * - * @return \Illuminate\Http\JsonResponse - */ - public function deleteSubscription(Subscription $subscriber) + public function destroy(Subscriber $subscriber) { - dispatch(new UnsubscribeSubscriptionCommand($subscriber)); + execute(new UnsubscribeSubscriberCommand($subscriber)); return $this->noContent(); } diff --git a/app/Http/Controllers/Api/SubscriptionController.php b/app/Http/Controllers/Api/SubscriptionController.php new file mode 100644 index 00000000000..173a5e0ffc9 --- /dev/null +++ b/app/Http/Controllers/Api/SubscriptionController.php @@ -0,0 +1,37 @@ + + */ +class SubscriptionController extends AbstractApiController +{ + /** + * Delete a subscription. + * + * @param \CachetHQ\Cachet\Models\Subscription $subscription + * + * @return \Illuminate\Http\JsonResponse + */ + public function destroy(Subscription $subscription) + { + execute(new UnsubscribeSubscriptionCommand($subscription)); + + return $this->noContent(); + } +} diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index b6d6357034a..597b9b51893 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -11,15 +11,18 @@ namespace CachetHQ\Cachet\Http\Controllers; +use CachetHQ\Cachet\Bus\Events\User\UserFailedTwoAuthEvent; +use CachetHQ\Cachet\Bus\Events\User\UserLoggedInEvent; +use CachetHQ\Cachet\Bus\Events\User\UserLoggedOutEvent; +use CachetHQ\Cachet\Bus\Events\User\UserPassedTwoAuthEvent; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Redirect; -use Illuminate\Support\Facades\Request; use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\View; -use Illuminate\Support\Str; -use PragmaRX\Google2FA\Vendor\Laravel\Facade as Google2FA; +use PragmaRX\Google2FA\Google2FA; class AuthController extends Controller { @@ -41,31 +44,32 @@ public function showLogin() */ public function postLogin() { - $loginData = Binput::only(['username', 'password']); + $loginData = Binput::only(['username', 'password', 'remember_me']); // Login with username or email. - $loginKey = Str::contains($loginData['username'], '@') ? 'email' : 'username'; - $loginData[$loginKey] = array_pull($loginData, 'username'); + $loginKey = filter_var($loginData['username'], FILTER_VALIDATE_EMAIL) ? 'email' : 'username'; + $loginData[$loginKey] = Arr::pull($loginData, 'username'); + + $rememberUser = Arr::pull($loginData, 'remember_me') === '1'; // Validate login credentials. if (Auth::validate($loginData)) { - // Log the user in for one request. Auth::once($loginData); - // Do we have Two Factor Auth enabled? + if (Auth::user()->hasTwoFactor) { - // Temporarily store the user. Session::put('2fa_id', Auth::user()->id); - return Redirect::route('auth.two-factor'); + return cachet_redirect('auth.two-factor'); } - // We probably want to add support for "Remember me" here. - Auth::attempt($loginData); + Auth::attempt($loginData, $rememberUser); + + event(new UserLoggedInEvent(Auth::user())); - return Redirect::intended('dashboard'); + return Redirect::intended(cachet_route('dashboard')); } - return Redirect::route('auth.login') + return cachet_redirect('auth.login') ->withInput(Binput::except('password')) ->withError(trans('forms.login.invalid')); } @@ -85,30 +89,43 @@ public function showTwoFactorAuth() * * This feels very hacky, but we have to juggle authentication and codes. * + * @throws \PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException + * @throws \PragmaRX\Google2FA\Exceptions\InvalidCharactersException + * @throws \PragmaRX\Google2FA\Exceptions\SecretKeyTooShortException + * * @return \Illuminate\Http\RedirectResponse */ public function postTwoFactor() { // Check that we have a session. if ($userId = Session::pull('2fa_id')) { - $code = Binput::get('code'); + $code = str_replace(' ', '', Binput::get('code')); // Maybe a temp login here. Auth::loginUsingId($userId); - $valid = Google2FA::verifyKey(Auth::user()->google_2fa_secret, $code); + $user = Auth::user(); + + $google2fa = new Google2FA(); + $valid = $google2fa->verifyKey($user->google_2fa_secret, $code); if ($valid) { + event(new UserPassedTwoAuthEvent($user)); + + event(new UserLoggedInEvent($user)); + return Redirect::intended('dashboard'); } else { + event(new UserFailedTwoAuthEvent($user)); + // Failed login, log back out. Auth::logout(); - return Redirect::route('auth.login')->withError(trans('forms.login.invalid-token')); + return cachet_redirect('auth.login')->withError(trans('forms.login.invalid-token')); } } - return Redirect::route('auth.login')->withError(trans('forms.login.invalid-token')); + return cachet_redirect('auth.login')->withError(trans('forms.login.invalid-token')); } /** @@ -118,8 +135,10 @@ public function postTwoFactor() */ public function logoutAction() { + event(new UserLoggedOutEvent(Auth::user())); + Auth::logout(); - return Redirect::to('/'); + return cachet_redirect('status-page'); } } diff --git a/app/Http/Controllers/Dashboard/ApiController.php b/app/Http/Controllers/Dashboard/ApiController.php index 207a3875d7c..4e59a7a40c1 100644 --- a/app/Http/Controllers/Dashboard/ApiController.php +++ b/app/Http/Controllers/Dashboard/ApiController.php @@ -36,15 +36,18 @@ class ApiController extends AbstractApiController public function postUpdateComponent(Component $component) { try { - dispatch(new UpdateComponentCommand( + execute(new UpdateComponentCommand( $component, - null, - null, + $component->name, + $component->description, Binput::get('status'), - null, - null, - null, - null + $component->link, + $component->order, + $component->group_id, + $component->enabled, + $component->meta, + $component->tags, + true // Silent mode )); } catch (QueryException $e) { throw new BadRequestHttpException(); @@ -64,15 +67,20 @@ public function postUpdateComponentOrder() foreach ($componentData as $order => $componentId) { try { - dispatch(new UpdateComponentCommand( - Component::find($componentId), - null, - null, - null, - null, + $component = Component::find($componentId); + + execute(new UpdateComponentCommand( + $component, + $component->name, + $component->description, + $component->status, + $component->link, $order + 1, - null, - null + $component->group_id, + $component->enabled, + $component->meta, + $component->tags, + true // Silent mode )); } catch (QueryException $e) { throw new BadRequestHttpException(); @@ -92,11 +100,14 @@ public function postUpdateComponentGroupOrder() $groupData = Binput::get('ids'); foreach ($groupData as $order => $groupId) { - dispatch(new UpdateComponentGroupCommand( - ComponentGroup::find($groupId), - null, + $group = ComponentGroup::find($groupId); + + execute(new UpdateComponentGroupCommand( + $group, + $group->name, $order + 1, - null + $group->collapsed, + $group->visible )); } @@ -114,7 +125,7 @@ public function getIncidentTemplate() { $templateSlug = Binput::get('slug'); - if ($template = IncidentTemplate::where('slug', $templateSlug)->first()) { + if ($template = IncidentTemplate::where('slug', '=', $templateSlug)->first()) { return $template; } diff --git a/app/Http/Controllers/Dashboard/ComponentController.php b/app/Http/Controllers/Dashboard/ComponentController.php index 38a021f453c..c9c8e6792e1 100644 --- a/app/Http/Controllers/Dashboard/ComponentController.php +++ b/app/Http/Controllers/Dashboard/ComponentController.php @@ -12,20 +12,20 @@ namespace CachetHQ\Cachet\Http\Controllers\Dashboard; use AltThree\Validator\ValidationException; -use CachetHQ\Cachet\Bus\Commands\Component\AddComponentCommand; +use CachetHQ\Cachet\Bus\Commands\Component\CreateComponentCommand; use CachetHQ\Cachet\Bus\Commands\Component\RemoveComponentCommand; use CachetHQ\Cachet\Bus\Commands\Component\UpdateComponentCommand; -use CachetHQ\Cachet\Bus\Commands\ComponentGroup\AddComponentGroupCommand; -use CachetHQ\Cachet\Bus\Commands\ComponentGroup\RemoveComponentGroupCommand; -use CachetHQ\Cachet\Bus\Commands\ComponentGroup\UpdateComponentGroupCommand; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\ComponentGroup; -use CachetHQ\Cachet\Models\Tag; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; -use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\View; +/** + * This is the component controller class. + * + * @author James Brooks + */ class ComponentController extends Controller { /** @@ -45,21 +45,21 @@ public function __construct() $this->subMenu = [ 'components' => [ 'title' => trans('dashboard.components.components'), - 'url' => route('dashboard.components.index'), + 'url' => cachet_route('dashboard.components'), 'icon' => 'ion-ios-browsers', 'active' => false, ], 'groups' => [ 'title' => trans_choice('dashboard.components.groups.groups', 2), - 'url' => route('dashboard.components.groups'), + 'url' => cachet_route('dashboard.components.groups'), 'icon' => 'ion-folder', 'active' => false, ], ]; View::share([ - 'sub_menu' => $this->subMenu, - 'sub_title' => trans_choice('dashboard.components.components', 2), + 'subMenu' => $this->subMenu, + 'subTitle' => trans_choice('dashboard.components.components', 2), ]); } @@ -70,7 +70,7 @@ public function __construct() */ public function showComponents() { - $components = Component::orderBy('order')->orderBy('created_at')->get(); + $components = Component::with('group')->orderBy('order')->orderBy('created_at')->get(); $this->subMenu['components']['active'] = true; @@ -80,21 +80,6 @@ public function showComponents() ->withSubMenu($this->subMenu); } - /** - * Shows the component groups view. - * - * @return \Illuminate\View\View - */ - public function showComponentGroups() - { - $this->subMenu['groups']['active'] = true; - - return View::make('dashboard.components.groups.index') - ->withPageTitle(trans_choice('dashboard.components.groups.groups', 2).' - '.trans('dashboard.dashboard')) - ->withGroups(ComponentGroup::orderBy('order')->get()) - ->withSubMenu($this->subMenu); - } - /** * Shows the edit component view. * @@ -124,10 +109,9 @@ public function showEditComponent(Component $component) public function updateComponentAction(Component $component) { $componentData = Binput::get('component'); - $tags = array_pull($componentData, 'tags'); try { - $component = dispatch(new UpdateComponentCommand( + $component = execute(new UpdateComponentCommand( $component, $componentData['name'], $componentData['description'], @@ -135,26 +119,19 @@ public function updateComponentAction(Component $component) $componentData['link'], $componentData['order'], $componentData['group_id'], - $componentData['enabled'] + $componentData['enabled'], + null, // Meta data cannot be supplied through the dashboard yet. + $componentData['tags'], // Meta data cannot be supplied through the dashboard yet. + true // Silent since we're not really making changes to the component (this should be optional) )); } catch (ValidationException $e) { - return Redirect::route('dashboard.components.edit', ['id' => $component->id]) + return cachet_redirect('dashboard.components.edit', [$component->id]) ->withInput(Binput::all()) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.components.edit.failure'))) ->withErrors($e->getMessageBag()); } - // The component was added successfully, so now let's deal with the tags. - $tags = preg_split('/ ?, ?/', $tags); - - // For every tag, do we need to create it? - $componentTags = array_map(function ($taggable) use ($component) { - return Tag::firstOrCreate(['name' => $taggable])->id; - }, $tags); - - $component->tags()->sync($componentTags); - - return Redirect::route('dashboard.components.edit', ['id' => $component->id]) + return cachet_redirect('dashboard.components.edit', [$component->id]) ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.components.edit.success'))); } @@ -178,36 +155,27 @@ public function showAddComponent() public function createComponentAction() { $componentData = Binput::get('component'); - $tags = array_pull($componentData, 'tags'); try { - $component = dispatch(new AddComponentCommand( + $component = execute(new CreateComponentCommand( $componentData['name'], $componentData['description'], $componentData['status'], $componentData['link'], $componentData['order'], $componentData['group_id'], - $componentData['enabled'] + $componentData['enabled'], + null, // Meta data cannot be supplied through the dashboard yet. + $componentData['tags'] )); } catch (ValidationException $e) { - return Redirect::route('dashboard.components.add') + return cachet_redirect('dashboard.components.create') ->withInput(Binput::all()) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.components.add.failure'))) ->withErrors($e->getMessageBag()); } - // The component was added successfully, so now let's deal with the tags. - $tags = preg_split('/ ?, ?/', $tags); - - // For every tag, do we need to create it? - $componentTags = array_map(function ($taggable) use ($component) { - return Tag::firstOrCreate(['name' => $taggable])->id; - }, $tags); - - $component->tags()->sync($componentTags); - - return Redirect::route('dashboard.components.index') + return cachet_redirect('dashboard.components') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.components.add.success'))); } @@ -220,100 +188,9 @@ public function createComponentAction() */ public function deleteComponentAction(Component $component) { - dispatch(new RemoveComponentCommand($component)); - - return Redirect::route('dashboard.components.index') - ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.components.delete.success'))); - } - - /** - * Deletes a given component group. - * - * @param \CachetHQ\Cachet\Models\ComponentGroup $group - * - * @return \Illuminate\Http\RedirectResponse - */ - public function deleteComponentGroupAction(ComponentGroup $group) - { - dispatch(new RemoveComponentGroupCommand($group)); + execute(new RemoveComponentCommand($component)); - return Redirect::route('dashboard.components.index') + return cachet_redirect('dashboard.components') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.components.delete.success'))); } - - /** - * Shows the add component group view. - * - * @return \Illuminate\View\View - */ - public function showAddComponentGroup() - { - return View::make('dashboard.components.groups.add') - ->withPageTitle(trans('dashboard.components.groups.add.title').' - '.trans('dashboard.dashboard')); - } - - /** - * Shows the edit component group view. - * - * @param \CachetHQ\Cachet\Models\ComponentGroup $group - * - * @return \Illuminate\View\View - */ - public function showEditComponentGroup(ComponentGroup $group) - { - return View::make('dashboard.components.groups.edit') - ->withPageTitle(trans('dashboard.components.groups.edit.title').' - '.trans('dashboard.dashboard')) - ->withGroup($group); - } - - /** - * Creates a new component. - * - * @return \Illuminate\Http\RedirectResponse - */ - public function postAddComponentGroup() - { - try { - $group = dispatch(new AddComponentGroupCommand( - Binput::get('name'), - Binput::get('order', 0), - Binput::get('collapsed') - )); - } catch (ValidationException $e) { - return Redirect::route('dashboard.components.groups.add') - ->withInput(Binput::all()) - ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.components.groups.add.failure'))) - ->withErrors($e->getMessageBag()); - } - - return Redirect::route('dashboard.components.groups') - ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.components.groups.add.success'))); - } - - /** - * Updates a component group. - * - * @param \CachetHQ\Cachet\Models\ComponentGroup $group - * - * @return \Illuminate\Http\RedirectResponse - */ - public function updateComponentGroupAction(ComponentGroup $group) - { - try { - $group = dispatch(new UpdateComponentGroupCommand( - $group, - Binput::get('name'), - $group->order, - Binput::get('collapsed') - )); - } catch (ValidationException $e) { - return Redirect::route('dashboard.components.groups.edit', ['id' => $group->id]) - ->withInput(Binput::all()) - ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.components.groups.edit.failure'))) - ->withErrors($e->getMessageBag()); - } - - return Redirect::route('dashboard.components.groups.edit', ['id' => $group->id]) - ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.components.groups.edit.success'))); - } } diff --git a/app/Http/Controllers/Dashboard/ComponentGroupController.php b/app/Http/Controllers/Dashboard/ComponentGroupController.php new file mode 100644 index 00000000000..ad81afc9f00 --- /dev/null +++ b/app/Http/Controllers/Dashboard/ComponentGroupController.php @@ -0,0 +1,173 @@ + + */ +class ComponentGroupController extends Controller +{ + /** + * Array of sub-menu items. + * + * @var array + */ + protected $subMenu = []; + + /** + * Creates a new component controller instance. + * + * @return void + */ + public function __construct() + { + $this->subMenu = [ + 'components' => [ + 'title' => trans('dashboard.components.components'), + 'url' => cachet_route('dashboard.components'), + 'icon' => 'ion-ios-browsers', + 'active' => false, + ], + 'groups' => [ + 'title' => trans_choice('dashboard.components.groups.groups', 2), + 'url' => cachet_route('dashboard.components.groups'), + 'icon' => 'ion-folder', + 'active' => false, + ], + ]; + + View::share([ + 'sub_menu' => $this->subMenu, + 'subTitle' => trans_choice('dashboard.components.components', 2), + ]); + } + + /** + * Shows the component groups view. + * + * @return \Illuminate\View\View + */ + public function showComponentGroups() + { + $this->subMenu['groups']['active'] = true; + + return View::make('dashboard.components.groups.index') + ->withPageTitle(trans_choice('dashboard.components.groups.groups', 2).' - '.trans('dashboard.dashboard')) + ->withGroups(ComponentGroup::orderBy('order')->get()) + ->withSubMenu($this->subMenu); + } + + /** + * Deletes a given component group. + * + * @param \CachetHQ\Cachet\Models\ComponentGroup $group + * + * @return \Illuminate\Http\RedirectResponse + */ + public function deleteComponentGroupAction(ComponentGroup $group) + { + execute(new RemoveComponentGroupCommand($group)); + + return cachet_redirect('dashboard.components.groups') + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.components.delete.success'))); + } + + /** + * Shows the add component group view. + * + * @return \Illuminate\View\View + */ + public function showAddComponentGroup() + { + return View::make('dashboard.components.groups.add') + ->withPageTitle(trans('dashboard.components.groups.add.title').' - '.trans('dashboard.dashboard')); + } + + /** + * Shows the edit component group view. + * + * @param \CachetHQ\Cachet\Models\ComponentGroup $group + * + * @return \Illuminate\View\View + */ + public function showEditComponentGroup(ComponentGroup $group) + { + return View::make('dashboard.components.groups.edit') + ->withPageTitle(trans('dashboard.components.groups.edit.title').' - '.trans('dashboard.dashboard')) + ->withGroup($group); + } + + /** + * Creates a new component. + * + * @return \Illuminate\Http\RedirectResponse + */ + public function postAddComponentGroup() + { + try { + $group = execute(new CreateComponentGroupCommand( + Binput::get('name'), + Binput::get('order', 0), + Binput::get('collapsed'), + Binput::get('visible') + )); + } catch (ValidationException $e) { + return cachet_redirect('dashboard.components.groups.create') + ->withInput(Binput::all()) + ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.components.groups.add.failure'))) + ->withErrors($e->getMessageBag()); + } + + return cachet_redirect('dashboard.components.groups') + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.components.groups.add.success'))); + } + + /** + * Updates a component group. + * + * @param \CachetHQ\Cachet\Models\ComponentGroup $group + * + * @return \Illuminate\Http\RedirectResponse + */ + public function updateComponentGroupAction(ComponentGroup $group) + { + try { + $group = execute(new UpdateComponentGroupCommand( + $group, + Binput::get('name'), + $group->order, + Binput::get('collapsed'), + Binput::get('visible') + )); + } catch (ValidationException $e) { + return cachet_redirect('dashboard.components.groups.edit', [$group->id]) + ->withInput(Binput::all()) + ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.components.groups.edit.failure'))) + ->withErrors($e->getMessageBag()); + } + + return cachet_redirect('dashboard.components.groups.edit', [$group->id]) + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.components.groups.edit.success'))); + } +} diff --git a/app/Http/Controllers/Dashboard/DashboardController.php b/app/Http/Controllers/Dashboard/DashboardController.php index 44a017c96f8..2d5281a19e8 100644 --- a/app/Http/Controllers/Dashboard/DashboardController.php +++ b/app/Http/Controllers/Dashboard/DashboardController.php @@ -11,17 +11,24 @@ namespace CachetHQ\Cachet\Http\Controllers\Dashboard; -use CachetHQ\Cachet\Integrations\Feed; +use CachetHQ\Cachet\Bus\Commands\User\WelcomeUserCommand; +use CachetHQ\Cachet\Integrations\Contracts\Feed; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\ComponentGroup; use CachetHQ\Cachet\Models\Incident; use CachetHQ\Cachet\Models\Subscriber; +use Illuminate\Contracts\Auth\Guard; use Illuminate\Routing\Controller; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Config; -use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\View; use Jenssegers\Date\Date; +/** + * This is the dashboard controller class. + * + * @author James Brooks + */ class DashboardController extends Controller { /** @@ -41,20 +48,29 @@ class DashboardController extends Controller /** * The feed integration. * - * @var \CachetHQ\Cachet\Integrations\Feed + * @var \CachetHQ\Cachet\Integrations\Contracts\Feed */ protected $feed; + /** + * The user session object. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $guard; + /** * Creates a new dashboard controller instance. * - * @param \CachetHQ\Cachet\Integrations\Feed $feed + * @param \CachetHQ\Cachet\Integrations\Contracts\Feed $feed + * @param \Illuminate\Contracts\Auth\Guard $guard * * @return void */ - public function __construct(Feed $feed) + public function __construct(Feed $feed, Guard $guard) { $this->feed = $feed; + $this->guard = $guard; $this->startDate = new Date(); $this->dateTimeZone = Config::get('cachet.timezone'); } @@ -66,7 +82,7 @@ public function __construct(Feed $feed) */ public function redirectAdmin() { - return Redirect::route('dashboard.index'); + return cachet_redirect('dashboard'); } /** @@ -79,13 +95,20 @@ public function showDashboard() $components = Component::orderBy('order')->get(); $incidents = $this->getIncidents(); $subscribers = $this->getSubscribers(); - $usedComponentGroups = Component::enabled()->where('group_id', '>', 0)->groupBy('group_id')->pluck('group_id'); - $componentGroups = ComponentGroup::whereIn('id', $usedComponentGroups)->orderBy('order')->get(); - $ungroupedComponents = Component::enabled()->where('group_id', 0)->orderBy('order')->orderBy('created_at')->get(); + + $componentGroups = $this->getVisibleGroupedComponents(); + $ungroupedComponents = Component::ungrouped()->get(); + + $welcomeUser = !Auth::user()->welcomed; + if ($welcomeUser) { + execute(new WelcomeUserCommand(Auth::user())); + } $entries = null; - if ($feed = $this->feed->latest()) { - $entries = array_slice($feed->channel->item, 0, 5); + if ($feed = $this->feed->latest() !== 1) { + if (is_object($feed)) { + $entries = array_slice($feed->channel->item, 0, 5); + } } return View::make('dashboard.index') @@ -95,18 +118,8 @@ public function showDashboard() ->withSubscribers($subscribers) ->withEntries($entries) ->withComponentGroups($componentGroups) - ->withUngroupedComponents($ungroupedComponents); - } - - /** - * Shows the notifications view. - * - * @return \Illuminate\View\View - */ - public function showNotifications() - { - return View::make('dashboard.notifications.index') - ->withPageTitle(trans('dashboard.notifications.notifications').' '.trans('dashboard.dashboard')); + ->withUngroupedComponents($ungroupedComponents) + ->withWelcomeUser($welcomeUser); } /** @@ -116,11 +129,11 @@ public function showNotifications() */ protected function getIncidents() { - $allIncidents = Incident::notScheduled()->whereBetween('created_at', [ + $allIncidents = Incident::whereBetween('occurred_at', [ $this->startDate->copy()->subDays(30)->format('Y-m-d').' 00:00:00', $this->startDate->format('Y-m-d').' 23:59:59', - ])->orderBy('created_at', 'desc')->get()->groupBy(function (Incident $incident) { - return (new Date($incident->created_at)) + ])->orderBy('occurred_at', 'desc')->get()->groupBy(function (Incident $incident) { + return (new Date($incident->occurred_at)) ->setTimezone($this->dateTimeZone)->toDateString(); }); @@ -172,4 +185,22 @@ protected function getSubscribers() return $allSubscribers; } + + /** + * Get visible grouped components. + * + * @return \Illuminate\Support\Collection + */ + protected function getVisibleGroupedComponents() + { + $componentGroupsBuilder = ComponentGroup::query(); + if (!$this->guard->check()) { + $componentGroupsBuilder = ComponentGroup::visible(); + } + + $usedComponentGroups = Component::grouped()->pluck('group_id'); + + return $componentGroupsBuilder->used($usedComponentGroups) + ->get(); + } } diff --git a/app/Http/Controllers/Dashboard/IncidentController.php b/app/Http/Controllers/Dashboard/IncidentController.php index 80b5bd507c1..f5555aa0bb9 100644 --- a/app/Http/Controllers/Dashboard/IncidentController.php +++ b/app/Http/Controllers/Dashboard/IncidentController.php @@ -12,18 +12,24 @@ namespace CachetHQ\Cachet\Http\Controllers\Dashboard; use AltThree\Validator\ValidationException; +use CachetHQ\Cachet\Bus\Commands\Incident\CreateIncidentCommand; use CachetHQ\Cachet\Bus\Commands\Incident\RemoveIncidentCommand; -use CachetHQ\Cachet\Bus\Commands\Incident\ReportIncidentCommand; use CachetHQ\Cachet\Bus\Commands\Incident\UpdateIncidentCommand; +use CachetHQ\Cachet\Integrations\Contracts\System; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\ComponentGroup; use CachetHQ\Cachet\Models\Incident; use CachetHQ\Cachet\Models\IncidentTemplate; use GrahamCampbell\Binput\Facades\Binput; +use Illuminate\Contracts\Auth\Guard; use Illuminate\Routing\Controller; -use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\View; +/** + * This is the incident controller. + * + * @author James Brooks + */ class IncidentController extends Controller { /** @@ -33,30 +39,33 @@ class IncidentController extends Controller */ protected $subMenu = []; + /** + * The guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * The system instance. + * + * @var \CachetHQ\Cachet\Integrations\Contracts\System + */ + protected $system; + /** * Creates a new incident controller instance. * + * @param \Illuminate\Contracts\Auth\Guard $auth + * * @return void */ - public function __construct() + public function __construct(Guard $auth, System $system) { - $this->subMenu = [ - 'incidents' => [ - 'title' => trans('dashboard.incidents.incidents'), - 'url' => route('dashboard.incidents.index'), - 'icon' => 'ion-android-checkmark-circle', - 'active' => true, - ], - 'schedule' => [ - 'title' => trans('dashboard.schedule.schedule'), - 'url' => route('dashboard.schedule.index'), - 'icon' => 'ion-android-calendar', - 'active' => false, - ], - ]; + $this->auth = $auth; + $this->system = $system; - View::share('sub_menu', $this->subMenu); - View::share('sub_title', trans('dashboard.incidents.title')); + View::share('subTitle', trans('dashboard.incidents.title')); } /** @@ -66,7 +75,7 @@ public function __construct() */ public function showIncidents() { - $incidents = Incident::notScheduled()->orderBy('created_at', 'desc')->get(); + $incidents = Incident::with('user')->orderBy('created_at', 'desc')->get(); return View::make('dashboard.incidents.index') ->withPageTitle(trans('dashboard.incidents.incidents').' - '.trans('dashboard.dashboard')) @@ -83,7 +92,8 @@ public function showAddIncident() return View::make('dashboard.incidents.add') ->withPageTitle(trans('dashboard.incidents.add.title').' - '.trans('dashboard.dashboard')) ->withComponentsInGroups(ComponentGroup::with('components')->get()) - ->withComponentsOutGroups(Component::where('group_id', 0)->get()) + ->withComponentsOutGroups(Component::where('group_id', '=', 0)->get()) + ->withNotificationsEnabled($this->system->canNotifySubscribers()) ->withIncidentTemplates(IncidentTemplate::all()); } @@ -107,26 +117,28 @@ public function showTemplates() public function createIncidentAction() { try { - $incident = dispatch(new ReportIncidentCommand( + $incident = execute(new CreateIncidentCommand( Binput::get('name'), Binput::get('status'), - Binput::get('message'), + Binput::get('message', null, false, false), Binput::get('visible', true), Binput::get('component_id'), Binput::get('component_status'), Binput::get('notify', false), - Binput::get('created_at'), + Binput::get('stickied', false), + Binput::get('occurred_at'), null, - null + [], + ['seo' => Binput::get('seo', [])] )); } catch (ValidationException $e) { - return Redirect::route('dashboard.incidents.add') + return cachet_redirect('dashboard.incidents.create') ->withInput(Binput::all()) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.incidents.add.failure'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('dashboard.incidents.index') + return cachet_redirect('dashboard.incidents') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.incidents.add.success'))); } @@ -166,7 +178,7 @@ public function deleteTemplateAction(IncidentTemplate $template) { $template->delete(); - return Redirect::route('dashboard.templates.index') + return cachet_redirect('dashboard.templates') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.incidents.templates.delete.success'))); } @@ -178,15 +190,18 @@ public function deleteTemplateAction(IncidentTemplate $template) public function createIncidentTemplateAction() { try { - IncidentTemplate::create(Binput::get('template')); + IncidentTemplate::create([ + 'name' => Binput::get('name'), + 'template' => Binput::get('template', null, false, false), + ]); } catch (ValidationException $e) { - return Redirect::route('dashboard.templates.add') + return cachet_redirect('dashboard.templates.create') ->withInput(Binput::all()) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.incidents.templates.add.failure'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('dashboard.templates.index') + return cachet_redirect('dashboard.templates') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.incidents.templates.add.success'))); } @@ -199,9 +214,9 @@ public function createIncidentTemplateAction() */ public function deleteIncidentAction(Incident $incident) { - dispatch(new RemoveIncidentCommand($incident)); + execute(new RemoveIncidentCommand($incident)); - return Redirect::route('dashboard.incidents.index') + return cachet_redirect('dashboard.incidents') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.incidents.delete.success'))); } @@ -218,7 +233,8 @@ public function showEditIncidentAction(Incident $incident) ->withPageTitle(trans('dashboard.incidents.edit.title').' - '.trans('dashboard.dashboard')) ->withIncident($incident) ->withComponentsInGroups(ComponentGroup::with('components')->get()) - ->withComponentsOutGroups(Component::where('group_id', 0)->get()); + ->withComponentsOutGroups(Component::where('group_id', '=', 0)->get()) + ->withNotificationsEnabled($this->system->canNotifySubscribers()); } /** @@ -231,7 +247,7 @@ public function showEditIncidentAction(Incident $incident) public function editIncidentAction(Incident $incident) { try { - $incident = dispatch(new UpdateIncidentCommand( + $incident = execute(new UpdateIncidentCommand( $incident, Binput::get('name'), Binput::get('status'), @@ -240,12 +256,14 @@ public function editIncidentAction(Incident $incident) Binput::get('component_id'), Binput::get('component_status'), Binput::get('notify', true), - Binput::get('created_at'), + Binput::get('stickied', false), + Binput::get('occurred_at'), null, - null + [], + ['seo' => Binput::get('seo', [])] )); } catch (ValidationException $e) { - return Redirect::route('dashboard.incidents.edit', ['id' => $incident->id]) + return cachet_redirect('dashboard.incidents.edit', ['id' => $incident->id]) ->withInput(Binput::all()) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.incidents.templates.edit.failure'))) ->withErrors($e->getMessageBag()); @@ -255,7 +273,7 @@ public function editIncidentAction(Incident $incident) $incident->component->update(['status' => Binput::get('component_status')]); } - return Redirect::route('dashboard.incidents.edit', ['id' => $incident->id]) + return cachet_redirect('dashboard.incidents.edit', ['id' => $incident->id]) ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.incidents.edit.success'))); } @@ -271,12 +289,12 @@ public function editTemplateAction(IncidentTemplate $template) try { $template->update(Binput::get('template')); } catch (ValidationException $e) { - return Redirect::route('dashboard.templates.edit', ['id' => $template->id]) + return cachet_redirect('dashboard.templates.edit', ['id' => $template->id]) ->withUpdatedTemplate($template) ->withTemplateErrors($e->getMessageBag()->getErrors()); } - return Redirect::route('dashboard.templates.edit', ['id' => $template->id]) + return cachet_redirect('dashboard.templates.edit', ['id' => $template->id]) ->withUpdatedTemplate($template); } } diff --git a/app/Http/Controllers/Dashboard/IncidentTemplateController.php b/app/Http/Controllers/Dashboard/IncidentTemplateController.php new file mode 100644 index 00000000000..853b5b2baec --- /dev/null +++ b/app/Http/Controllers/Dashboard/IncidentTemplateController.php @@ -0,0 +1,161 @@ + + */ +class IncidentTemplateController extends Controller +{ + /** + * Stores the sub-sidebar tree list. + * + * @var array + */ + protected $subMenu = []; + + /** + * The guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * The system instance. + * + * @var \CachetHQ\Cachet\Integrations\Contracts\System + */ + protected $system; + + /** + * Creates a new incident controller instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth, System $system) + { + $this->auth = $auth; + $this->system = $system; + + View::share('sub_title', trans('dashboard.incidents.title')); + } + + /** + * Shows the incident templates. + * + * @return \Illuminate\View\View + */ + public function showTemplates() + { + return View::make('dashboard.templates.index') + ->withPageTitle(trans('dashboard.incidents.templates.title').' - '.trans('dashboard.dashboard')) + ->withIncidentTemplates(IncidentTemplate::all()); + } + + /** + * Shows the add incident template view. + * + * @return \Illuminate\View\View + */ + public function showAddIncidentTemplate() + { + return View::make('dashboard.templates.add') + ->withPageTitle(trans('dashboard.incidents.templates.add.title').' - '.trans('dashboard.dashboard')); + } + + /** + * Shows the edit incident template view. + * + * @param \CachetHQ\Cachet\Models\IncidentTemplate $template + * + * @return \Illuminate\View\View + */ + public function showEditTemplateAction(IncidentTemplate $template) + { + return View::make('dashboard.templates.edit') + ->withPageTitle(trans('dashboard.incidents.templates.edit.title').' - '.trans('dashboard.dashboard')) + ->withTemplate($template); + } + + /** + * Deletes an incident template. + * + * @param \CachetHQ\Cachet\Models\IncidentTemplate $template + * + * @return \Illuminate\Http\RedirectResponse + */ + public function deleteTemplateAction(IncidentTemplate $template) + { + $template->delete(); + + return cachet_redirect('dashboard.templates') + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.incidents.templates.delete.success'))); + } + + /** + * Creates a new incident template. + * + * @return \Illuminate\Http\RedirectResponse + */ + public function createIncidentTemplateAction() + { + try { + IncidentTemplate::create([ + 'name' => Binput::get('name'), + 'template' => Binput::get('template', null, false, false), + ]); + } catch (ValidationException $e) { + return cachet_redirect('dashboard.templates.create') + ->withInput(Binput::all()) + ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.incidents.templates.add.failure'))) + ->withErrors($e->getMessageBag()); + } + + return cachet_redirect('dashboard.templates') + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.incidents.templates.add.success'))); + } + + /** + * Edit an incident template. + * + * @param \CachetHQ\Cachet\Models\IncidentTemplate $template + * + * @return \Illuminate\Http\RedirectResponse + */ + public function editTemplateAction(IncidentTemplate $template) + { + try { + $template->update(Binput::get('template')); + } catch (ValidationException $e) { + return cachet_redirect('dashboard.templates.edit', ['id' => $template->id]) + ->withUpdatedTemplate($template) + ->withTemplateErrors($e->getMessageBag()->getErrors()); + } + + return cachet_redirect('dashboard.templates.edit', ['id' => $template->id]) + ->withUpdatedTemplate($template); + } +} diff --git a/app/Http/Controllers/Dashboard/IncidentUpdateController.php b/app/Http/Controllers/Dashboard/IncidentUpdateController.php new file mode 100644 index 00000000000..092809e374d --- /dev/null +++ b/app/Http/Controllers/Dashboard/IncidentUpdateController.php @@ -0,0 +1,172 @@ + + */ +class IncidentUpdateController extends Controller +{ + /** + * Stores the sub-sidebar tree list. + * + * @var array + */ + protected $subMenu = []; + + /** + * The guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * The system instance. + * + * @var \CachetHQ\Cachet\Integrations\Contracts\System + */ + protected $system; + + /** + * Creates a new incident controller instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth, System $system) + { + $this->auth = $auth; + $this->system = $system; + + View::share('sub_title', trans('dashboard.incidents.title')); + } + + /** + * Shows the incident update form. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * + * @return \Illuminate\View\View + */ + public function showIncidentUpdates(Incident $incident) + { + return View::make('dashboard.incidents.updates.index')->withIncident($incident); + } + + /** + * Shows the incident update form. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * + * @return \Illuminate\View\View + */ + public function showCreateIncidentUpdateAction(Incident $incident) + { + return View::make('dashboard.incidents.updates.add') + ->withIncident($incident) + ->withIncidentTemplates(IncidentTemplate::all()) + ->withNotificationsEnabled($this->system->canNotifySubscribers()); + } + + /** + * Creates a new incident update. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * + * @return \Illuminate\Http\RedirectResponse + */ + public function createIncidentUpdateAction(Incident $incident) + { + try { + $incidentUpdate = execute(new CreateIncidentUpdateCommand( + $incident, + Binput::get('status'), + Binput::get('message'), + Binput::get('component_id'), + Binput::get('component_status'), + $this->auth->user() + )); + } catch (ValidationException $e) { + return cachet_redirect('dashboard.incidents.updates.create', ['id' => $incident->id]) + ->withInput(Binput::all()) + ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.incidents.updates.add.failure'))) + ->withErrors($e->getMessageBag()); + } + + if ($incident->component) { + $incident->component->update(['status' => Binput::get('component_status')]); + } + + return cachet_redirect('dashboard.incidents') + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.incidents.updates.success'))); + } + + /** + * Shows the edit incident view. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * @param \CachetHQ\Cachet\Models\IncidentUpdate $incidentUpdate + * + * @return \Illuminate\View\View + */ + public function showEditIncidentUpdateAction(Incident $incident, IncidentUpdate $incidentUpdate) + { + return View::make('dashboard.incidents.updates.edit') + ->withIncident($incident) + ->withUpdate($incidentUpdate) + ->withNotificationsEnabled($this->system->canNotifySubscribers()); + } + + /** + * Edit an incident update. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * @param \CachetHQ\Cachet\Models\IncidentUpdate $incidentUpdate + * + * @return \Illuminate\Http\RedirectResponse + */ + public function editIncidentUpdateAction(Incident $incident, IncidentUpdate $incidentUpdate) + { + try { + $incidentUpdate = execute(new UpdateIncidentUpdateCommand( + $incidentUpdate, + Binput::get('status'), + Binput::get('message'), + $this->auth->user() + )); + } catch (ValidationException $e) { + return cachet_redirect('dashboard.incidents.updates.edit', ['incident' => $incident->id, 'incident_update' => $incidentUpdate->id]) + ->withInput(Binput::all()) + ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.incidents.updates.edit.failure'))) + ->withErrors($e->getMessageBag()); + } + + return cachet_redirect('dashboard.incidents.updates', ['incident' => $incident->id]) + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.incidents.updates.edit.success'))); + } +} diff --git a/app/Http/Controllers/Dashboard/MetricController.php b/app/Http/Controllers/Dashboard/MetricController.php index 447e9fedbed..1a0b601c745 100644 --- a/app/Http/Controllers/Dashboard/MetricController.php +++ b/app/Http/Controllers/Dashboard/MetricController.php @@ -12,14 +12,13 @@ namespace CachetHQ\Cachet\Http\Controllers\Dashboard; use AltThree\Validator\ValidationException; -use CachetHQ\Cachet\Bus\Commands\Metric\AddMetricCommand; +use CachetHQ\Cachet\Bus\Commands\Metric\CreateMetricCommand; use CachetHQ\Cachet\Bus\Commands\Metric\RemoveMetricCommand; use CachetHQ\Cachet\Bus\Commands\Metric\UpdateMetricCommand; use CachetHQ\Cachet\Models\Metric; use CachetHQ\Cachet\Models\MetricPoint; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; -use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\View; class MetricController extends Controller @@ -71,7 +70,7 @@ public function createMetricAction() $metricData = Binput::get('metric'); try { - dispatch(new AddMetricCommand( + execute(new CreateMetricCommand( $metricData['name'], $metricData['suffix'], $metricData['description'], @@ -80,16 +79,18 @@ public function createMetricAction() $metricData['display_chart'], $metricData['places'], $metricData['default_view'], - $metricData['threshold'] + $metricData['threshold'], + 0, // Default order + $metricData['visible'] )); } catch (ValidationException $e) { - return Redirect::route('dashboard.metrics.add') + return cachet_redirect('dashboard.metrics.create') ->withInput(Binput::all()) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.metrics.add.failure'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('dashboard.metrics.index') + return cachet_redirect('dashboard.metrics') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.metrics.add.success'))); } @@ -113,9 +114,9 @@ public function showAddMetricPoint() */ public function deleteMetricAction(Metric $metric) { - dispatch(new RemoveMetricCommand($metric)); + execute(new RemoveMetricCommand($metric)); - return Redirect::route('dashboard.metrics.index') + return cachet_redirect('dashboard.metrics') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.metrics.delete.success'))); } @@ -143,7 +144,7 @@ public function showEditMetricAction(Metric $metric) public function editMetricAction(Metric $metric) { try { - dispatch(new UpdateMetricCommand( + execute(new UpdateMetricCommand( $metric, Binput::get('name', null, false), Binput::get('suffix', null, false), @@ -153,16 +154,18 @@ public function editMetricAction(Metric $metric) Binput::get('display_chart', null, false), Binput::get('places', null, false), Binput::get('default_view', null, false), - Binput::get('threshold', null, false) + Binput::get('threshold', null, false), + null, + Binput::get('visible', null, false) )); } catch (ValidationException $e) { - return Redirect::route('dashboard.metrics.edit', ['id' => $metric->id]) + return cachet_redirect('dashboard.metrics.edit', [$metric->id]) ->withInput(Binput::all()) ->withTitle(sprintf('%s', trans('dashboard.notifications.whoops'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('dashboard.metrics.edit', ['id' => $metric->id]) + return cachet_redirect('dashboard.metrics.edit', [$metric->id]) ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.metrics.edit.success'))); } } diff --git a/app/Http/Controllers/Dashboard/ScheduleController.php b/app/Http/Controllers/Dashboard/ScheduleController.php index bead6cfd3d6..c06216a916f 100644 --- a/app/Http/Controllers/Dashboard/ScheduleController.php +++ b/app/Http/Controllers/Dashboard/ScheduleController.php @@ -12,17 +12,21 @@ namespace CachetHQ\Cachet\Http\Controllers\Dashboard; use AltThree\Validator\ValidationException; -use CachetHQ\Cachet\Bus\Commands\Incident\ReportMaintenanceCommand; -use CachetHQ\Cachet\Dates\DateFactory; -use CachetHQ\Cachet\Models\Incident; +use CachetHQ\Cachet\Bus\Commands\Schedule\CreateScheduleCommand; +use CachetHQ\Cachet\Bus\Commands\Schedule\DeleteScheduleCommand; +use CachetHQ\Cachet\Bus\Commands\Schedule\UpdateScheduleCommand; +use CachetHQ\Cachet\Integrations\Contracts\System; use CachetHQ\Cachet\Models\IncidentTemplate; +use CachetHQ\Cachet\Models\Schedule; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; -use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\View; -use Illuminate\Support\MessageBag; -use Jenssegers\Date\Date; +/** + * This is the schedule controller class. + * + * @author James Brooks + */ class ScheduleController extends Controller { /** @@ -32,30 +36,22 @@ class ScheduleController extends Controller */ protected $subMenu = []; + /** + * The system instance. + * + * @var \CachetHQ\Cachet\Integrations\Contracts\System + */ + protected $system; + /** * Creates a new schedule controller instance. * * @return void */ - public function __construct() + public function __construct(System $system) { - $this->subMenu = [ - 'incidents' => [ - 'title' => trans('dashboard.incidents.incidents'), - 'url' => route('dashboard.incidents.index'), - 'icon' => 'ion-android-checkmark-circle', - 'active' => false, - ], - 'schedule' => [ - 'title' => trans('dashboard.schedule.schedule'), - 'url' => route('dashboard.schedule.index'), - 'icon' => 'ion-android-calendar', - 'active' => true, - ], - ]; - - View::share('sub_menu', $this->subMenu); - View::share('sub_title', trans('dashboard.incidents.title')); + $this->system = $system; + View::share('subTitle', trans('dashboard.schedule.title')); } /** @@ -65,9 +61,9 @@ public function __construct() */ public function showIndex() { - $schedule = Incident::scheduled()->orderBy('created_at')->get(); + $schedule = Schedule::orderBy('created_at')->get(); - return View::make('dashboard.schedule.index') + return View::make('dashboard.maintenance.index') ->withPageTitle(trans('dashboard.schedule.schedule').' - '.trans('dashboard.dashboard')) ->withSchedule($schedule); } @@ -81,48 +77,52 @@ public function showAddSchedule() { $incidentTemplates = IncidentTemplate::all(); - return View::make('dashboard.schedule.add') + return View::make('dashboard.maintenance.add') ->withPageTitle(trans('dashboard.schedule.add.title').' - '.trans('dashboard.dashboard')) - ->withIncidentTemplates($incidentTemplates); + ->withIncidentTemplates($incidentTemplates) + ->withNotificationsEnabled($this->system->canNotifySubscribers()); } /** - * Creates a new scheduled maintenance "incident". + * Creates a new scheduled maintenance. * * @return \Illuminate\Http\RedirectResponse */ public function addScheduleAction() { try { - $incident = dispatch(new ReportMaintenanceCommand( + execute(new CreateScheduleCommand( Binput::get('name'), - Binput::get('message'), - Binput::get('notify'), - Binput::get('scheduled_at') + Binput::get('message', null, false, false), + Binput::get('status', Schedule::UPCOMING), + Binput::get('scheduled_at'), + Binput::get('completed_at'), + Binput::get('components', []), + Binput::get('notify', false) )); } catch (ValidationException $e) { - return Redirect::route('dashboard.schedule.add') + return cachet_redirect('dashboard.schedule.create') ->withInput(Binput::all()) - ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.schedule.add.failure'))) + ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.schedule.edit.failure'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('dashboard.schedule.index') + return cachet_redirect('dashboard.schedule') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.schedule.add.success'))); } /** * Shows the edit schedule maintenance form. * - * @param \CachetHQ\Cachet\Models\Incident $schedule + * @param \CachetHQ\Cachet\Models\Schedule $schedule * * @return \Illuminate\View\View */ - public function showEditSchedule(Incident $schedule) + public function showEditSchedule(Schedule $schedule) { $incidentTemplates = IncidentTemplate::all(); - return View::make('dashboard.schedule.edit') + return View::make('dashboard.maintenance.edit') ->withPageTitle(trans('dashboard.schedule.edit.title').' - '.trans('dashboard.dashboard')) ->withIncidentTemplates($incidentTemplates) ->withSchedule($schedule); @@ -131,53 +131,45 @@ public function showEditSchedule(Incident $schedule) /** * Updates the given incident. * - * @param \CachetHQ\Cachet\Models\Incident $schedule + * @param \CachetHQ\Cachet\Models\Schedule $schedule * * @return \Illuminate\Http\RedirectResponse */ - public function editScheduleAction(Incident $schedule) + public function editScheduleAction(Schedule $schedule) { - $scheduleData = Binput::get('incident'); - - // Parse the schedule date. - $scheduledAt = app(DateFactory::class)->create('d/m/Y H:i', $scheduleData['scheduled_at']); - - if ($scheduledAt->isPast()) { - $messageBag = new MessageBag(); - $messageBag->add('scheduled_at', trans('validation.date', ['attribute' => 'scheduled time you supplied'])); - - return Redirect::route('dashboard.schedule.edit', ['id' => $schedule->id])->withErrors($messageBag); - } - - $scheduleData['scheduled_at'] = $scheduledAt; - // Bypass the incident.status field. - $scheduleData['status'] = 0; - try { - $schedule->update($scheduleData); + $schedule = execute(new UpdateScheduleCommand( + $schedule, + Binput::get('name', null), + Binput::get('message', null), + Binput::get('status', null), + Binput::get('scheduled_at', null), + Binput::get('completed_at', null), + Binput::get('components', []) + )); } catch (ValidationException $e) { - return Redirect::route('dashboard.schedule.edit', ['id' => $schedule->id]) + return cachet_redirect('dashboard.schedule.edit', [$schedule->id]) ->withInput(Binput::all()) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.schedule.edit.failure'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('dashboard.schedule.edit', ['id' => $schedule->id]) + return cachet_redirect('dashboard.schedule.edit', [$schedule->id]) ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.schedule.edit.success'))); } /** * Deletes a given schedule. * - * @param \CachetHQ\Cachet\Models\Incident $schedule + * @param \CachetHQ\Cachet\Models\Schedule $schedule * * @return \Illuminate\Http\RedirectResponse */ - public function deleteScheduleAction(Incident $schedule) + public function deleteScheduleAction(Schedule $schedule) { - $schedule->delete(); + execute(new DeleteScheduleCommand($schedule)); - return Redirect::route('dashboard.schedule.index') + return cachet_redirect('dashboard.schedule') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.schedule.delete.success'))); } } diff --git a/app/Http/Controllers/Dashboard/SettingsController.php b/app/Http/Controllers/Dashboard/SettingsController.php index af40ff7fa15..f128e22711e 100644 --- a/app/Http/Controllers/Dashboard/SettingsController.php +++ b/app/Http/Controllers/Dashboard/SettingsController.php @@ -11,18 +11,24 @@ namespace CachetHQ\Cachet\Http\Controllers\Dashboard; -use CachetHQ\Cachet\Integrations\Credits; +use CachetHQ\Cachet\Bus\Commands\System\Config\UpdateConfigCommand; +use CachetHQ\Cachet\Integrations\Contracts\Credits; use CachetHQ\Cachet\Models\User; +use CachetHQ\Cachet\Notifications\System\SystemTestNotification; use CachetHQ\Cachet\Settings\Repository; use Exception; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; +use Illuminate\Support\Facades\Artisan; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Lang; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\View; use Illuminate\Support\Str; +use Monolog\Handler\SyslogHandler; class SettingsController extends Controller { @@ -43,52 +49,64 @@ public function __construct() $this->subMenu = [ 'setup' => [ 'title' => trans('dashboard.settings.app-setup.app-setup'), - 'url' => route('dashboard.settings.setup'), + 'url' => cachet_route('dashboard.settings.setup'), 'icon' => 'ion-gear-b', 'active' => false, ], 'theme' => [ 'title' => trans('dashboard.settings.theme.theme'), - 'url' => route('dashboard.settings.theme'), + 'url' => cachet_route('dashboard.settings.theme'), 'icon' => 'ion-paintbrush', 'active' => false, ], 'stylesheet' => [ 'title' => trans('dashboard.settings.stylesheet.stylesheet'), - 'url' => route('dashboard.settings.stylesheet'), + 'url' => cachet_route('dashboard.settings.stylesheet'), 'icon' => 'ion-paintbucket', 'active' => false, ], 'customization' => [ 'title' => trans('dashboard.settings.customization.customization'), - 'url' => route('dashboard.settings.customization'), + 'url' => cachet_route('dashboard.settings.customization'), 'icon' => 'ion-wand', 'active' => false, ], 'localization' => [ 'title' => trans('dashboard.settings.localization.localization'), - 'url' => route('dashboard.settings.localization'), + 'url' => cachet_route('dashboard.settings.localization'), 'icon' => 'ion-earth', 'active' => false, ], 'security' => [ 'title' => trans('dashboard.settings.security.security'), - 'url' => route('dashboard.settings.security'), + 'url' => cachet_route('dashboard.settings.security'), 'icon' => 'ion-lock-combination', 'active' => false, ], 'analytics' => [ 'title' => trans('dashboard.settings.analytics.analytics'), - 'url' => route('dashboard.settings.analytics'), + 'url' => cachet_route('dashboard.settings.analytics'), 'icon' => 'ion-stats-bars', 'active' => false, ], + 'log' => [ + 'title' => trans('dashboard.settings.log.log'), + 'url' => cachet_route('dashboard.settings.log'), + 'icon' => 'ion-document-text', + 'active' => false, + ], 'credits' => [ 'title' => trans('dashboard.settings.credits.credits'), - 'url' => route('dashboard.settings.credits'), + 'url' => cachet_route('dashboard.settings.credits'), 'icon' => 'ion-ios-list', 'active' => false, ], + 'mail' => [ + 'title' => trans('dashboard.settings.mail.mail'), + 'url' => cachet_route('dashboard.settings.mail'), + 'icon' => 'ion-paper-airplane', + 'active' => false, + ], 'about' => [ 'title' => CACHET_VERSION, 'url' => 'javascript: void(0);', @@ -98,8 +116,8 @@ public function __construct() ]; View::share([ - 'sub_title' => trans('dashboard.settings.settings'), - 'sub_menu' => $this->subMenu, + 'subTitle' => trans('dashboard.settings.settings'), + 'subMenu' => $this->subMenu, ]); } @@ -193,7 +211,7 @@ public function showSecurityView() { $this->subMenu['security']['active'] = true; - $unsecureUsers = User::whereNull('google_2fa_secret')->orWhere('google_2fa_secret', '')->get(); + $unsecureUsers = User::whereNull('google_2fa_secret')->orWhere('google_2fa_secret', '=', '')->get(); Session::flash('redirect_to', $this->subMenu['security']['url']); @@ -243,6 +261,71 @@ public function showCreditsView() ->withSubMenu($this->subMenu); } + /** + * Show the most recent log. + * + * @return \Illuminate\View\View + */ + public function showLogView() + { + $this->subMenu['log']['active'] = true; + + $log = Log::getLogger(); + + $logContents = ''; + + collect($log->getHandlers())->reject(function ($handler) { + return $handler instanceof SyslogHandler; + })->each(function ($handler) use (&$logContents, $log) { + if (file_exists($path = $log->getHandlers()[0]->getUrl())) { + $logContents = file_get_contents($path); + } + }); + + return View::make('dashboard.settings.log')->withLog($logContents)->withSubMenu($this->subMenu); + } + + /** + * Show the mail settings view. + * + * @return \Illuminate\View\View + */ + public function showMailView() + { + $this->subMenu['mail']['active'] = true; + + return View::make('dashboard.settings.mail')->withConfig(Config::get('mail')); + } + + /** + * Test the mail config. + * + * @return \Illuminate\Http\RedirectResponse + */ + public function testMail() + { + Auth::user()->notify(new SystemTestNotification()); + + return cachet_redirect('dashboard.settings.mail') + ->withSuccess(trans('dashboard.notifications.awesome')); + } + + /** + * Handle updating of the settings. + * + * @return \Illuminate\Http\RedirectResponse + */ + public function postMail() + { + $config = Binput::get('config'); + + execute(new UpdateConfigCommand($config)); + + return cachet_redirect('dashboard.settings.mail') + ->withInput(Binput::all()) + ->withSuccess(trans('dashboard.notifications.awesome')); + } + /** * Updates the status page settings. * @@ -274,6 +357,14 @@ public function postSettings() } } + if (isset($parameters['stylesheet'])) { + if ($stylesheet = Binput::get('stylesheet', null, false, false)) { + $setting->set('stylesheet', $stylesheet); + } else { + $setting->delete('stylesheet'); + } + } + if (Binput::hasFile('app_banner')) { $this->handleUpdateBanner($setting); } @@ -284,6 +375,7 @@ public function postSettings() 'remove_banner', 'header', 'footer', + 'stylesheet', ]; try { @@ -302,6 +394,10 @@ public function postSettings() Lang::setLocale(Binput::get('app_locale')); } + if (Binput::has('always_authenticate')) { + Artisan::call('route:clear'); + } + return Redirect::back()->withSuccess(trans('dashboard.settings.edit.success')); } @@ -315,6 +411,7 @@ public function postSettings() protected function handleUpdateBanner(Repository $setting) { $file = Binput::file('app_banner'); + $redirectUrl = $this->subMenu['theme']['url']; // Image Validation. // Image size in bytes. diff --git a/app/Http/Controllers/Dashboard/SubscriberController.php b/app/Http/Controllers/Dashboard/SubscriberController.php index a62cd0b8236..17de83eb4a2 100644 --- a/app/Http/Controllers/Dashboard/SubscriberController.php +++ b/app/Http/Controllers/Dashboard/SubscriberController.php @@ -16,8 +16,8 @@ use CachetHQ\Cachet\Bus\Commands\Subscriber\UnsubscribeSubscriberCommand; use CachetHQ\Cachet\Models\Subscriber; use GrahamCampbell\Binput\Facades\Binput; +use Illuminate\Contracts\Config\Repository; use Illuminate\Routing\Controller; -use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\View; class SubscriberController extends Controller @@ -31,7 +31,7 @@ public function showSubscribers() { return View::make('dashboard.subscribers.index') ->withPageTitle(trans('dashboard.subscribers.subscribers').' - '.trans('dashboard.dashboard')) - ->withSubscribers(Subscriber::all()); + ->withSubscribers(Subscriber::with('subscriptions.component')->get()); } /** @@ -52,20 +52,22 @@ public function showAddSubscriber() */ public function createSubscriberAction() { + $verified = app(Repository::class)->get('setting.skip_subscriber_verification'); + try { $subscribers = preg_split("/\r\n|\n|\r/", Binput::get('email')); foreach ($subscribers as $subscriber) { - dispatch(new SubscribeSubscriberCommand($subscriber)); + execute(new SubscribeSubscriberCommand($subscriber, $verified)); } } catch (ValidationException $e) { - return Redirect::route('dashboard.subscribers.add') + return cachet_redirect('dashboard.subscribers.create') ->withInput(Binput::all()) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.subscribers.add.failure'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('dashboard.subscribers.add') + return cachet_redirect('dashboard.subscribers.create') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.subscribers.add.success'))); } @@ -80,8 +82,8 @@ public function createSubscriberAction() */ public function deleteSubscriberAction(Subscriber $subscriber) { - dispatch(new UnsubscribeSubscriberCommand($subscriber)); + execute(new UnsubscribeSubscriberCommand($subscriber)); - return Redirect::route('dashboard.subscribers.index'); + return cachet_redirect('dashboard.subscribers'); } } diff --git a/app/Http/Controllers/Dashboard/TeamController.php b/app/Http/Controllers/Dashboard/TeamController.php index 1786adc2de9..b762161907f 100644 --- a/app/Http/Controllers/Dashboard/TeamController.php +++ b/app/Http/Controllers/Dashboard/TeamController.php @@ -12,13 +12,12 @@ namespace CachetHQ\Cachet\Http\Controllers\Dashboard; use AltThree\Validator\ValidationException; -use CachetHQ\Cachet\Bus\Commands\User\AddTeamMemberCommand; -use CachetHQ\Cachet\Bus\Commands\User\InviteTeamMemberCommand; +use CachetHQ\Cachet\Bus\Commands\User\CreateUserCommand; +use CachetHQ\Cachet\Bus\Commands\User\InviteUserCommand; use CachetHQ\Cachet\Bus\Commands\User\RemoveUserCommand; use CachetHQ\Cachet\Models\User; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; -use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\View; class TeamController extends Controller @@ -81,20 +80,20 @@ public function showInviteTeamMemberView() public function postAddUser() { try { - dispatch(new AddTeamMemberCommand( + execute(new CreateUserCommand( Binput::get('username'), Binput::get('password'), Binput::get('email'), Binput::get('level') )); } catch (ValidationException $e) { - return Redirect::route('dashboard.team.add') + return cachet_redirect('dashboard.team.create') ->withInput(Binput::except('password')) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.team.add.failure'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('dashboard.team.add') + return cachet_redirect('dashboard.team.create') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.team.add.success'))); } @@ -112,13 +111,13 @@ public function postUpdateUser(User $user) try { $user->update($userData); } catch (ValidationException $e) { - return Redirect::route('dashboard.team.edit', ['id' => $user->id]) + return cachet_redirect('dashboard.team.edit', [$user->id]) ->withInput($userData) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.team.edit.failure'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('dashboard.team.edit', ['id' => $user->id]) + return cachet_redirect('dashboard.team.edit', [$user->id]) ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.team.edit.success'))); } @@ -130,17 +129,17 @@ public function postUpdateUser(User $user) public function postInviteUser() { try { - dispatch(new InviteTeamMemberCommand( + execute(new InviteUserCommand( array_unique(array_filter((array) Binput::get('emails'))) )); } catch (ValidationException $e) { - return Redirect::route('dashboard.team.invite') + return cachet_redirect('dashboard.team.invite') ->withInput(Binput::except('password')) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.team.invite.failure'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('dashboard.team.invite') + return cachet_redirect('dashboard.team.invite') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.team.invite.success'))); } @@ -153,9 +152,9 @@ public function postInviteUser() */ public function deleteUser(User $user) { - dispatch(new RemoveUserCommand($user)); + execute(new RemoveUserCommand($user)); - return Redirect::route('dashboard.team.index') + return cachet_redirect('dashboard.team') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.team.delete.success'))); } } diff --git a/app/Http/Controllers/Dashboard/UserController.php b/app/Http/Controllers/Dashboard/UserController.php index 882551b74af..ba01e862b6d 100644 --- a/app/Http/Controllers/Dashboard/UserController.php +++ b/app/Http/Controllers/Dashboard/UserController.php @@ -12,13 +12,16 @@ namespace CachetHQ\Cachet\Http\Controllers\Dashboard; use AltThree\Validator\ValidationException; +use CachetHQ\Cachet\Bus\Events\User\UserDisabledTwoAuthEvent; +use CachetHQ\Cachet\Bus\Events\User\UserEnabledTwoAuthEvent; +use CachetHQ\Cachet\Bus\Events\User\UserRegeneratedApiTokenEvent; use CachetHQ\Cachet\Models\User; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\Auth; -use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\View; -use PragmaRX\Google2FA\Vendor\Laravel\Facade as Google2FA; +use PragmaRX\Google2FA\Google2FA; class UserController extends Controller { @@ -36,31 +39,37 @@ public function showUser() /** * Updates the current user. * + * @throws \PragmaRX\Google2FA\Exceptions\IncompatibleWithGoogleAuthenticatorException + * @throws \PragmaRX\Google2FA\Exceptions\InvalidCharactersException + * * @return \Illuminate\View\View */ public function postUser() { $userData = array_filter(Binput::only(['username', 'email', 'password', 'google2fa'])); - $enable2FA = (bool) array_pull($userData, 'google2fa'); + $enable2FA = (bool) Arr::pull($userData, 'google2fa'); // Let's enable/disable auth if ($enable2FA && !Auth::user()->hasTwoFactor) { - $userData['google_2fa_secret'] = Google2FA::generateSecretKey(); + event(new UserEnabledTwoAuthEvent(Auth::user())); + $google2fa = new Google2FA(); + $userData['google_2fa_secret'] = $google2fa->generateSecretKey(); } elseif (!$enable2FA) { + event(new UserDisabledTwoAuthEvent(Auth::user())); $userData['google_2fa_secret'] = ''; } try { Auth::user()->update($userData); } catch (ValidationException $e) { - return Redirect::route('dashboard.user') + return cachet_redirect('dashboard.user') ->withInput($userData) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('dashboard.team.edit.failure'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('dashboard.user') + return cachet_redirect('dashboard.user') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('dashboard.team.edit.success'))); } @@ -76,6 +85,8 @@ public function regenerateApiKey(User $user) $user->api_key = User::generateApiKey(); $user->save(); - return Redirect::route('dashboard.user'); + event(new UserRegeneratedApiTokenEvent($user)); + + return cachet_redirect('dashboard.user'); } } diff --git a/app/Http/Controllers/FeedController.php b/app/Http/Controllers/FeedController.php deleted file mode 100644 index e9510fd94e5..00000000000 --- a/app/Http/Controllers/FeedController.php +++ /dev/null @@ -1,112 +0,0 @@ -feed = app('feed'); - $this->feed->title = Config::get('setting.app_name'); - $this->feed->description = trans('cachet.feed'); - $this->feed->link = Str::canonicalize(Config::get('setting.app_domain')); - $this->feed->ctype = 'text/xml'; - $this->feed->setDateFormat('datetime'); - } - - /** - * Generates an Atom feed of all incidents. - * - * @param \CachetHQ\Cachet\Models\ComponentGroup|null $group - * - * @return \Illuminate\Http\Response - */ - public function atomAction(ComponentGroup $group = null) - { - return $this->feedAction($group, false); - } - - /** - * Generates a Rss feed of all incidents. - * - * @param \CachetHQ\Cachet\Models\ComponentGroup|null $group - * - * @return \Illuminate\Http\Response - */ - public function rssAction(ComponentGroup $group = null) - { - $this->feed->lang = Config::get('setting.app_locale'); - - return $this->feedAction($group, true); - } - - /** - * Generates a Rss feed of all incidents. - * - * @param \CachetHQ\Cachet\Models\ComponentGroup|null $group - * @param bool $isRss - * - * @return \Illuminate\Http\Response - */ - private function feedAction(ComponentGroup &$group, $isRss) - { - if ($group->exists) { - $group->components->map(function ($component) use ($isRss) { - $component->incidents()->visible()->orderBy('created_at', 'desc')->get()->map(function ($incident) use ($isRss) { - $this->feedAddItem($incident, $isRss); - }); - }); - } else { - Incident::visible()->orderBy('created_at', 'desc')->get()->map(function ($incident) use ($isRss) { - $this->feedAddItem($incident, $isRss); - }); - } - - return $this->feed->render($isRss ? 'rss' : 'atom'); - } - - /** - * Adds an item to the feed. - * - * @param \CachetHQ\Cachet\Models\Incident $incident - * @param bool $isRss - */ - private function feedAddItem(Incident $incident, $isRss) - { - $this->feed->add( - $incident->name, - Config::get('setting.app_name'), - Str::canonicalize(route('incident', ['id' => $incident->id])), - $isRss ? $incident->created_at->toRssString() : $incident->created_at->toAtomString(), - $isRss ? $incident->message : Markdown::convertToHtml($incident->message) - ); - } -} diff --git a/app/Http/Controllers/SetupController.php b/app/Http/Controllers/SetupController.php index ed289ec9e7b..52bf51f7a3b 100644 --- a/app/Http/Controllers/SetupController.php +++ b/app/Http/Controllers/SetupController.php @@ -11,21 +11,26 @@ namespace CachetHQ\Cachet\Http\Controllers; +use CachetHQ\Cachet\Bus\Commands\System\Config\UpdateConfigCommand; use CachetHQ\Cachet\Models\User; use CachetHQ\Cachet\Settings\Repository; -use Dotenv\Dotenv; -use Dotenv\Exception\InvalidPathException; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; +use Illuminate\Support\Arr; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Config; -use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\Request; use Illuminate\Support\Facades\Response; -use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\View; +/** + * This is the setup controller. + * + * @author James Brooks + * @author Graham Campbell + * @author Joseph Cohen + */ class SetupController extends Controller { /** @@ -53,11 +58,25 @@ class SetupController extends Controller 'sendmail' => 'Sendmail', 'mailgun' => 'Mailgun', 'mandrill' => 'Mandrill', - // 'ses' => 'Amazon SES', this will be available only if aws/aws-sdk-php is installed + 'ses' => 'Amazon SES', 'sparkpost' => 'SparkPost', 'log' => 'Log (Testing)', ]; + /** + * Array of queue drivers. + * + * @var string[] + */ + protected $queueDrivers = [ + 'null' => 'None', + 'sync' => 'Synchronous', + 'database' => 'Database', + 'beanstalkd' => 'Beanstalk', + 'sqs' => 'Amazon SQS', + 'redis' => 'Redis', + ]; + /** * Array of step1 rules. * @@ -89,6 +108,7 @@ public function __construct() $this->rulesStep1 = [ 'env.cache_driver' => 'required|in:'.implode(',', array_keys($this->cacheDrivers)), 'env.session_driver' => 'required|in:'.implode(',', array_keys($this->cacheDrivers)), + 'env.queue_driver' => 'required|in:'.implode(',', array_keys($this->queueDrivers)), 'env.mail_driver' => 'required|in:'.implode(',', array_keys($this->mailDrivers)), ]; @@ -114,24 +134,53 @@ public function __construct() */ public function getIndex() { - $supportedLanguages = Request::getLanguages(); + $requestedLanguages = Request::getLanguages(); $userLanguage = Config::get('app.locale'); + $langs = Config::get('langs'); - foreach ($supportedLanguages as $language) { + foreach ($requestedLanguages as $language) { $language = str_replace('_', '-', $language); - if (isset($this->langs[$language])) { + if (isset($langs[$language])) { $userLanguage = $language; break; } } - return View::make('setup') + app('translator')->setLocale($userLanguage); + + // Since .env may already be configured, we should show that data! + $cacheConfig = [ + 'driver' => Config::get('cache.default'), + ]; + + $sessionConfig = [ + 'driver' => Config::get('session.driver'), + ]; + + $queueConfig = [ + 'driver' => Config::get('queue.default'), + ]; + + $mailConfig = [ + 'driver' => Config::get('mail.driver'), + 'host' => Config::get('mail.host'), + 'from' => Config::get('mail.from'), + 'username' => Config::get('mail.username'), + 'password' => Config::get('mail.password'), + ]; + + return View::make('setup.index') ->withPageTitle(trans('setup.setup')) ->withCacheDrivers($this->cacheDrivers) + ->withQueueDrivers($this->queueDrivers) ->withMailDrivers($this->mailDrivers) ->withUserLanguage($userLanguage) - ->withAppUrl(Request::root()); + ->withAppUrl(Request::root()) + ->withCacheConfig($cacheConfig) + ->withSessionConfig($sessionConfig) + ->withQueueConfig($queueConfig) + ->withMailConfig($mailConfig); } /** @@ -146,11 +195,15 @@ public function postStep1() $v = Validator::make($postData, $this->rulesStep1); $v->sometimes('env.mail_host', 'required', function ($input) { - return $input->mail_driver === 'smtp'; + return $input->env['mail_driver'] === 'smtp'; }); - $v->sometimes(['env.mail_address', 'env.mail_username', 'env.mail_password'], 'required', function ($input) { - return $input->mail_driver !== 'log'; + $v->sometimes(['env.mail_address', 'env.mail_password'], 'required', function ($input) { + return !in_array($input->env['mail_driver'], ['log', 'smtp']); + }); + + $v->sometimes(['env.mail_username'], 'required', function ($input) { + return !in_array($input->env['mail_driver'], ['sendmail', 'log']); }); if ($v->passes()) { @@ -191,7 +244,7 @@ public function postStep3() if ($v->passes()) { // Pull the user details out. - $userDetails = array_pull($postData, 'user'); + $userDetails = Arr::pull($postData, 'user'); $user = User::create([ 'username' => $userDetails['username'], @@ -204,60 +257,28 @@ public function postStep3() $setting = app(Repository::class); - $settings = array_pull($postData, 'settings'); + $settings = Arr::pull($postData, 'settings'); foreach ($settings as $settingName => $settingValue) { $setting->set($settingName, $settingValue); } - $envData = array_pull($postData, 'env'); + $envData = Arr::pull($postData, 'env'); // Write the env to the .env file. - foreach ($envData as $envKey => $envValue) { - $this->writeEnv($envKey, $envValue); - } - - Session::flash('setup.done', true); + execute(new UpdateConfigCommand($envData)); if (Request::ajax()) { return Response::json(['status' => 1]); } - return Redirect::to('dashboard'); + return cachet_redirect('dashboard'); } if (Request::ajax()) { return Response::json(['errors' => $v->getMessageBag()], 400); } - return Redirect::route('setup.index')->withInput()->withErrors($v->getMessageBag()); - } - - /** - * Writes to the .env file with given parameters. - * - * @param string $key - * @param mixed $value - * - * @return void - */ - protected function writeEnv($key, $value) - { - $dir = app()->environmentPath(); - $file = app()->environmentFile(); - $path = "{$dir}/{$file}"; - - try { - (new Dotenv($dir, $file))->load(); - - $envKey = strtoupper($key); - $envValue = env($envKey) ?: 'null'; - - file_put_contents($path, str_replace( - $envKey.'='.$envValue, $envKey.'='.$value, file_get_contents($path) - )); - } catch (InvalidPathException $e) { - // - } + return cachet_redirect('setup')->withInput()->withErrors($v->getMessageBag()); } } diff --git a/app/Http/Controllers/SignupController.php b/app/Http/Controllers/SignupController.php index 2eda8d87a7a..6c7db1522d4 100644 --- a/app/Http/Controllers/SignupController.php +++ b/app/Http/Controllers/SignupController.php @@ -18,7 +18,6 @@ use CachetHQ\Cachet\Models\User; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; -use Illuminate\Support\Facades\Redirect; use Illuminate\Support\Facades\View; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -70,22 +69,22 @@ public function postSignup($code = null) } try { - dispatch(new SignupUserCommand( + execute(new SignupUserCommand( Binput::get('username'), Binput::get('password'), Binput::get('email'), User::LEVEL_USER )); } catch (ValidationException $e) { - return Redirect::route('signup.invite', ['code' => $invite->code]) + return cachet_redirect('signup.invite', [$invite->code]) ->withInput(Binput::except('password')) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('cachet.signup.failure'))) ->withErrors($e->getMessageBag()); } - dispatch(new ClaimInviteCommand($invite)); + execute(new ClaimInviteCommand($invite)); - return Redirect::route('status-page') + return cachet_redirect('status-page') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.signup.success'))); } } diff --git a/app/Http/Controllers/StatusPageController.php b/app/Http/Controllers/StatusPageController.php index 782d8a08d79..12766de5af0 100644 --- a/app/Http/Controllers/StatusPageController.php +++ b/app/Http/Controllers/StatusPageController.php @@ -11,14 +11,14 @@ namespace CachetHQ\Cachet\Http\Controllers; -use AltThree\Badger\Facades\Badger; -use CachetHQ\Cachet\Dates\DateFactory; +use CachetHQ\Badger\Facades\Badger; use CachetHQ\Cachet\Http\Controllers\Api\AbstractApiController; use CachetHQ\Cachet\Models\Component; use CachetHQ\Cachet\Models\Incident; use CachetHQ\Cachet\Models\Metric; +use CachetHQ\Cachet\Models\Schedule; use CachetHQ\Cachet\Repositories\Metric\MetricRepository; -use Exception; +use CachetHQ\Cachet\Services\Dates\DateFactory; use GrahamCampbell\Binput\Facades\Binput; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\Auth; @@ -28,25 +28,15 @@ use Jenssegers\Date\Date; use McCool\LaravelAutoPresenter\Facades\AutoPresenter; +/** + * This is the status page controller class. + * + * @author James Brooks + * @author Graham Campbell + * @author Joseph Cohen + */ class StatusPageController extends AbstractApiController { - /** - * @var \CachetHQ\Cachet\Repositories\Metric\MetricRepository - */ - protected $metricRepository; - - /** - * Construct a new status page controller instance. - * - * @param \CachetHQ\Cachet\Repositories\Metric\MetricRepository $metricRepository - * - * @return void - */ - public function __construct(MetricRepository $metricRepository) - { - $this->metricRepository = $metricRepository; - } - /** * Displays the status page. * @@ -54,62 +44,91 @@ public function __construct(MetricRepository $metricRepository) */ public function showIndex() { - $today = Date::now(); - $startDate = Date::now(); - - // Check if we have another starting date - if (Binput::has('start_date')) { - try { - // If date provided is valid - $oldDate = Date::createFromFormat('Y-m-d', Binput::get('start_date')); - - // If trying to get a future date fallback to today - if ($today->gt($oldDate)) { - $startDate = $oldDate; - } - } catch (Exception $e) { - // Fallback to today + $onlyDisruptedDays = Config::get('setting.only_disrupted_days'); + $appIncidentDays = (int) Config::get('setting.app_incident_days', 1); + + $startDate = Date::createFromFormat('Y-m-d', Binput::get('start_date', Date::now()->toDateString())); + $endDate = $startDate->copy()->subDays($appIncidentDays); + + $canPageForward = false; + $canPageBackward = false; + $previousDate = null; + $nextDate = null; + + if ($onlyDisruptedDays) { + // In this case, start_date GET parameter means the page + $page = (int) Binput::get('start_date', 0); + + $allIncidentDays = Incident::where('visible', '>=', (int) !Auth::check()) + ->select('occurred_at') + ->whereBetween('occurred_at', [ + $endDate->format('Y-m-d').' 00:00:00', + $startDate->format('Y-m-d').' 23:59:59', + ]) + ->distinct() + ->orderBy('occurred_at', 'desc') + ->get() + ->map(function (Incident $incident) { + return app(DateFactory::class)->make($incident->occurred_at)->toDateString(); + })->unique() + ->values(); + + $numIncidentDays = count($allIncidentDays); + $numPages = round($numIncidentDays / max($appIncidentDays, 1)); + + $selectedDays = $allIncidentDays->slice($page * $appIncidentDays, $appIncidentDays)->all(); + + if (count($selectedDays) > 0) { + $startDate = Date::createFromFormat('Y-m-d', array_values($selectedDays)[0]); + $endDate = Date::createFromFormat('Y-m-d', array_values(array_slice($selectedDays, -1))[0]); } - } - $daysToShow = Config::get('setting.app_incident_days', 0) - 1; - if ($daysToShow < 0) { - $daysToShow = 0; - $incidentDays = []; + $canPageForward = $page > 0; + $canPageBackward = ($page + 1) < $numPages; + $previousDate = $page + 1; + $nextDate = $page - 1; } else { - $incidentDays = range(0, $daysToShow); + $date = Date::now(); + + $canPageForward = (bool) $startDate->lt($date->sub('1 day')); + $canPageBackward = Incident::where('occurred_at', '<', $date->format('Y-m-d'))->count() > 0; + $previousDate = $startDate->copy()->subDays($appIncidentDays)->toDateString(); + $nextDate = $startDate->copy()->addDays($appIncidentDays)->toDateString(); } - $incidentVisibility = Auth::check() ? 0 : 1; + $allIncidents = Incident::with('component', 'updates.incident') + ->where('visible', '>=', (int) !Auth::check())->whereBetween('occurred_at', [ + $endDate->format('Y-m-d').' 00:00:00', + $startDate->format('Y-m-d').' 23:59:59', + ])->orderBy('occurred_at', 'desc')->get()->groupBy(function (Incident $incident) { + return app(DateFactory::class)->make($incident->occurred_at)->toDateString(); + }); - $allIncidents = Incident::notScheduled()->where('visible', '>=', $incidentVisibility)->whereBetween('created_at', [ - $startDate->copy()->subDays($daysToShow)->format('Y-m-d').' 00:00:00', - $startDate->format('Y-m-d').' 23:59:59', - ])->orderBy('scheduled_at', 'desc')->orderBy('created_at', 'desc')->get()->groupBy(function (Incident $incident) { - return app(DateFactory::class)->make($incident->is_scheduled ? $incident->scheduled_at : $incident->created_at)->toDateString(); - }); + if (!$onlyDisruptedDays) { + $incidentDays = array_pad([], $appIncidentDays, null); - // Add in days that have no incidents - foreach ($incidentDays as $i) { - $date = app(DateFactory::class)->make($startDate)->subDays($i); + // Add in days that have no incidents + foreach ($incidentDays as $i => $day) { + $date = app(DateFactory::class)->make($startDate)->subDays($i); - if (!isset($allIncidents[$date->toDateString()])) { - $allIncidents[$date->toDateString()] = []; + if (!isset($allIncidents[$date->toDateString()])) { + $allIncidents[$date->toDateString()] = []; + } } } // Sort the array so it takes into account the added days $allIncidents = $allIncidents->sortBy(function ($value, $key) { return strtotime($key); - }, SORT_REGULAR, true)->all(); + }, SORT_REGULAR, true); return View::make('index') - ->withDaysToShow($daysToShow) + ->withDaysToShow($appIncidentDays) ->withAllIncidents($allIncidents) - ->withCanPageForward((bool) $today->gt($startDate)) - ->withCanPageBackward(Incident::notScheduled()->where('created_at', '<', $startDate->format('Y-m-d'))->count() > 0) - ->withPreviousDate($startDate->copy()->subDays($daysToShow)->toDateString()) - ->withNextDate($startDate->copy()->addDays($daysToShow)->toDateString()); + ->withCanPageForward($canPageForward) + ->withCanPageBackward($canPageBackward) + ->withPreviousDate($previousDate) + ->withNextDate($nextDate); } /** @@ -121,8 +140,19 @@ public function showIndex() */ public function showIncident(Incident $incident) { - return View::make('single-incident') - ->withIncident($incident); + return View::make('single-incident')->withIncident($incident); + } + + /** + * Show a single schedule. + * + * @param \CachetHQ\Cachet\Models\Schedule $schedule + * + * @return \Illuminate\View\View + */ + public function showSchedule(Schedule $schedule) + { + return View::make('single-schedule')->withSchedule($schedule); } /** @@ -134,22 +164,19 @@ public function showIncident(Incident $incident) */ public function getMetrics(Metric $metric) { - $metricData = []; - $type = Binput::get('filter', 'last_hour'); + $type = Binput::get('filter', AutoPresenter::decorate($metric)->view_name); + $metrics = app(MetricRepository::class); switch ($type) { - case 'last_hour': - $metricData = $this->metricRepository->listPointsLastHour($metric); + case 'last_hour': $metricData = $metrics->listPointsLastHour($metric); break; - case 'today': - $metricData = $this->metricRepository->listPointsToday($metric); + case 'today': $metricData = $metrics->listPointsToday($metric); break; - case 'week': - $metricData = $this->metricRepository->listPointsForWeek($metric); + case 'week': $metricData = $metrics->listPointsForWeek($metric); break; - case 'month': - $metricData = $this->metricRepository->listPointsForMonth($metric); + case 'month': $metricData = $metrics->listPointsForMonth($metric); break; + default: $metricData = []; } return $this->item([ @@ -168,21 +195,17 @@ public function getMetrics(Metric $metric) public function showComponentBadge(Component $component) { $component = AutoPresenter::decorate($component); - $color = null; switch ($component->status_color) { - case 'reds': - $color = Config::get('setting.style_reds', '#ff6f6f'); + case 'reds': $color = Config::get('setting.style_reds', '#FF6F6F'); break; - case 'blues': - $color = Config::get('setting.style_blues', '#3498db'); + case 'blues': $color = Config::get('setting.style_blues', '#3498DB'); break; - case 'greens': - $color = Config::get('setting.style_greens', '#7ED321'); + case 'greens': $color = Config::get('setting.style_greens', '#7ED321'); break; - case 'yellows': - $color = Config::get('setting.style_yellows', '#F7CA18'); + case 'yellows': $color = Config::get('setting.style_yellows', '#F7CA18'); break; + default: $color = null; } $badge = Badger::generate( diff --git a/app/Http/Controllers/SubscribeController.php b/app/Http/Controllers/SubscribeController.php index 104dfd8cfb3..afa866a9610 100644 --- a/app/Http/Controllers/SubscribeController.php +++ b/app/Http/Controllers/SubscribeController.php @@ -18,13 +18,17 @@ use CachetHQ\Cachet\Bus\Commands\Subscriber\UpdateSubscriberSubscriptionCommand; use CachetHQ\Cachet\Bus\Commands\Subscriber\VerifySubscriberCommand; use CachetHQ\Cachet\Models\Component; +use CachetHQ\Cachet\Models\ComponentGroup; use CachetHQ\Cachet\Models\Subscriber; use CachetHQ\Cachet\Models\Subscription; +use CachetHQ\Cachet\Notifications\Subscriber\ManageSubscriptionNotification; use GrahamCampbell\Binput\Facades\Binput; use GrahamCampbell\Markdown\Facades\Markdown; +use Illuminate\Contracts\Auth\Guard; +use Illuminate\Contracts\Config\Repository; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\Config; -use Illuminate\Support\Facades\Redirect; +use Illuminate\Support\Facades\URL; use Illuminate\Support\Facades\View; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -36,6 +40,25 @@ */ class SubscribeController extends Controller { + /** + * The illuminate guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new subscribe controller instance. + * + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Guard $auth) + { + $this->auth = $auth; + } + /** * Show the subscribe by email page. * @@ -56,24 +79,27 @@ public function postSubscribe() { $email = Binput::get('email'); $subscriptions = Binput::get('subscriptions'); + $verified = app(Repository::class)->get('setting.skip_subscriber_verification'); try { - $verified = false; - - $subscription = dispatch(new SubscribeSubscriberCommand($email, $verified)); + $subscription = execute(new SubscribeSubscriberCommand($email, $verified)); } catch (ValidationException $e) { - return Redirect::route('status-page') + return cachet_redirect('status-page') ->withInput(Binput::all()) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('cachet.subscriber.email.failure'))) ->withErrors($e->getMessageBag()); } - $message = $subscription->is_verified ? - trans('cachet.subscriber.email.already-subscribed', ['email' => $email]) : - trans('cachet.subscriber.email.subscribed'); + // Send the subscriber a link to manage their subscription. + $subscription->notify(new ManageSubscriptionNotification()); - return Redirect::route('subscribe.manage', $subscription->verify_code) - ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), $message)); + return redirect()->back()->withSuccess( + sprintf( + '%s %s', + trans('dashboard.notifications.awesome'), + trans('cachet.subscriber.email.manage_subscription') + ) + ); } /** @@ -89,18 +115,18 @@ public function getVerify($code = null) throw new NotFoundHttpException(); } - $subscriber = Subscriber::where('verify_code', $code)->first(); + $subscriber = Subscriber::where('verify_code', '=', $code)->first(); if (!$subscriber) { throw new BadRequestHttpException(); } if (!$subscriber->is_verified) { - dispatch(new VerifySubscriberCommand($subscriber)); + execute(new VerifySubscriberCommand($subscriber)); } - return Redirect::route('status-page') - ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.verified'))); + return redirect()->to(URL::signedRoute(cachet_route_generator('subscribe.manage'), ['code' => $code])) + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.subscribed'))); } /** @@ -124,12 +150,12 @@ public function getUnsubscribe($code = null, $subscription = null) } if ($subscription) { - dispatch(new UnsubscribeSubscriptionCommand(Subscription::forSubscriber($subscriber->id)->firstOrFail())); + execute(new UnsubscribeSubscriptionCommand(Subscription::forSubscriber($subscriber->id)->firstOrFail())); } else { - dispatch(new UnsubscribeSubscriberCommand($subscriber, $subscription)); + execute(new UnsubscribeSubscriberCommand($subscriber)); } - return Redirect::route('status-page') + return cachet_redirect('status-page') ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.unsubscribed'))); } @@ -146,16 +172,22 @@ public function showManage($code = null) throw new NotFoundHttpException(); } + $includePrivate = $this->auth->check(); + $subscriber = Subscriber::where('verify_code', '=', $code)->first(); + $usedComponentGroups = Component::enabled()->authenticated($includePrivate)->where('group_id', '>', 0)->groupBy('group_id')->pluck('group_id'); + $componentGroups = ComponentGroup::whereIn('id', $usedComponentGroups)->orderBy('order')->get(); + $ungroupedComponents = Component::enabled()->authenticated($includePrivate)->where('group_id', '=', 0)->orderBy('order')->orderBy('created_at')->get(); if (!$subscriber) { throw new BadRequestHttpException(); } return View::make('subscribe.manage') - ->withComponents(Component::all()) + ->withUngroupedComponents($ungroupedComponents) ->withSubscriber($subscriber) - ->withSubscriptions($subscriber->subscriptions->pluck('component_id')->all()); + ->withSubscriptions($subscriber->subscriptions->pluck('component_id')->all()) + ->withComponentGroups($componentGroups); } /** @@ -178,17 +210,15 @@ public function postManage($code = null) } try { - dispatch(new UpdateSubscriberSubscriptionCommand($subscriber, Binput::get('subscriptions'))); + execute(new UpdateSubscriberSubscriptionCommand($subscriber, Binput::get('subscriptions'))); } catch (ValidationException $e) { - dd($e->getMessageBag()); - - return Redirect::route('subscribe.manage', $subscriber->verify_code) + return redirect()->to(URL::signedRoute(cachet_route_generator('subscribe.manage'), ['code' => $subscriber->verify_code])) ->withInput(Binput::all()) ->withTitle(sprintf('%s %s', trans('dashboard.notifications.whoops'), trans('cachet.subscriber.email.failure'))) ->withErrors($e->getMessageBag()); } - return Redirect::route('subscribe.manage', $subscriber->verify_code) - ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.subscribed'))); + return redirect()->to(URL::signedRoute(cachet_route_generator('subscribe.manage'), ['code' => $subscriber->verify_code])) + ->withSuccess(sprintf('%s %s', trans('dashboard.notifications.awesome'), trans('cachet.subscriber.email.updated-subscribe'))); } } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 9e0da573e60..ee7e3b40aa9 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -11,7 +11,23 @@ namespace CachetHQ\Cachet\Http; +use Barryvdh\Cors\HandleCors; +use CachetHQ\Cachet\Http\Middleware\Admin; +use CachetHQ\Cachet\Http\Middleware\ApiAuthentication; +use CachetHQ\Cachet\Http\Middleware\Authenticate; +use CachetHQ\Cachet\Http\Middleware\CacheControl; +use CachetHQ\Cachet\Http\Middleware\Localize; +use CachetHQ\Cachet\Http\Middleware\ReadyForUse; +use CachetHQ\Cachet\Http\Middleware\RedirectIfAuthenticated; +use CachetHQ\Cachet\Http\Middleware\RemoteUserAuthenticate; +use CachetHQ\Cachet\Http\Middleware\SetupAlreadyCompleted; +use CachetHQ\Cachet\Http\Middleware\SubscribersConfigured; +use CachetHQ\Cachet\Http\Middleware\Throttler; +use CachetHQ\Cachet\Http\Middleware\TrustProxies; +use Illuminate\Auth\Middleware\Authorize; use Illuminate\Foundation\Http\Kernel as HttpKernel; +use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode; +use Illuminate\Routing\Middleware\ValidateSignature; class Kernel extends HttpKernel { @@ -21,28 +37,8 @@ class Kernel extends HttpKernel * @var array */ protected $middleware = [ - 'Fideloper\Proxy\TrustProxies', - 'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode', - ]; - - /** - * The application's route middleware groups. - * - * @var array - */ - protected $middlewareGroups = [ - 'web' => [ - 'Illuminate\Cookie\Middleware\EncryptCookies', - 'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse', - 'Illuminate\Session\Middleware\StartSession', - 'Illuminate\View\Middleware\ShareErrorsFromSession', - 'Illuminate\Foundation\Http\Middleware\VerifyCsrfToken', - ], - 'api' => [ - 'Barryvdh\Cors\HandleCors', - 'CachetHQ\Cachet\Http\Middleware\Acceptable', - 'CachetHQ\Cachet\Http\Middleware\Timezone', - ], + TrustProxies::class, + CheckForMaintenanceMode::class, ]; /** @@ -51,14 +47,19 @@ class Kernel extends HttpKernel * @var array */ protected $routeMiddleware = [ - 'admin' => 'CachetHQ\Cachet\Http\Middleware\Admin', - 'auth' => 'CachetHQ\Cachet\Http\Middleware\Authenticate', - 'auth.api' => 'CachetHQ\Cachet\Http\Middleware\ApiAuthentication', - 'guest' => 'CachetHQ\Cachet\Http\Middleware\RedirectIfAuthenticated', - 'localize' => 'CachetHQ\Cachet\Http\Middleware\Localize', - 'ready' => 'CachetHQ\Cachet\Http\Middleware\ReadyForUse', - 'setup' => 'CachetHQ\Cachet\Http\Middleware\SetupAlreadyCompleted', - 'subscribers' => 'CachetHQ\Cachet\Http\Middleware\SubscribersConfigured', - 'throttle' => 'AltThree\Throttle\ThrottlingMiddleware', + 'admin' => Admin::class, + 'auth.api' => ApiAuthentication::class, + 'auth.remoteuser' => RemoteUserAuthenticate::class, + 'auth' => Authenticate::class, + 'cache' => CacheControl::class, + 'can' => Authorize::class, + 'cors' => HandleCors::class, + 'guest' => RedirectIfAuthenticated::class, + 'localize' => Localize::class, + 'ready' => ReadyForUse::class, + 'setup' => SetupAlreadyCompleted::class, + 'signed' => ValidateSignature::class, + 'subscribers' => SubscribersConfigured::class, + 'throttle' => Throttler::class, ]; } diff --git a/app/Http/Middleware/Acceptable.php b/app/Http/Middleware/Acceptable.php index 2c22a6a21e2..97974fa72b6 100644 --- a/app/Http/Middleware/Acceptable.php +++ b/app/Http/Middleware/Acceptable.php @@ -15,6 +15,12 @@ use Illuminate\Http\Request; use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException; +/** + * This is the acceptable middleware class. + * + * @author Graham Campbell + * @author James Brooks + */ class Acceptable { /** diff --git a/app/Http/Middleware/Admin.php b/app/Http/Middleware/Admin.php index 5088b091ac2..4180c3665d1 100644 --- a/app/Http/Middleware/Admin.php +++ b/app/Http/Middleware/Admin.php @@ -16,6 +16,13 @@ use Illuminate\Http\Request; use Symfony\Component\HttpKernel\Exception\HttpException; +/** + * This is the admin middleware class. + * + * @author Joseph Cohen + * @author Graham Campbell + * @author James Brooks + */ class Admin { /** diff --git a/app/Http/Middleware/ApiAuthentication.php b/app/Http/Middleware/ApiAuthentication.php index f4c10611d6f..c02b6c089c5 100644 --- a/app/Http/Middleware/ApiAuthentication.php +++ b/app/Http/Middleware/ApiAuthentication.php @@ -18,6 +18,13 @@ use Illuminate\Http\Request; use Symfony\Component\HttpKernel\Exception\HttpException; +/** + * This is the api authentication middleware class. + * + * @author Joseph Cohen + * @author Graham Campbell + * @author James Brooks + */ class ApiAuthentication { /** diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index 0400413194c..9b5562cb317 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -16,6 +16,13 @@ use Illuminate\Http\Request; use Symfony\Component\HttpKernel\Exception\HttpException; +/** + * This is the authenticate middleware class. + * + * @author Joseph Cohen + * @author Graham Campbell + * @author James Brooks + */ class Authenticate { /** diff --git a/app/Http/Middleware/CacheControl.php b/app/Http/Middleware/CacheControl.php new file mode 100644 index 00000000000..fa54dfe094f --- /dev/null +++ b/app/Http/Middleware/CacheControl.php @@ -0,0 +1,37 @@ +header('Cache-Control', 'public,max-age='.$maxAge); + + return $response; + } +} diff --git a/app/Http/Middleware/Localize.php b/app/Http/Middleware/Localize.php index 718e2ddb74d..52469c41515 100644 --- a/app/Http/Middleware/Localize.php +++ b/app/Http/Middleware/Localize.php @@ -11,38 +11,47 @@ namespace CachetHQ\Cachet\Http\Middleware; +use CachetHQ\Cachet\Settings\Repository as SettingsRepository; use Closure; -use Illuminate\Config\Repository; +use Illuminate\Contracts\Config\Repository as ConfigRepository; use Illuminate\Http\Request; use Jenssegers\Date\Date; +/** + * This is the localize middleware class. + * + * @author James Brooks + * @author Joseph Cohen + * @author Graham Campbell + */ class Localize { /** - * Array of languages Cachet can use. + * The config repository instance. * - * @var array + * @var \Illuminate\Contracts\Config\Repository */ - protected $langs; + protected $config; /** - * The config repository instance. + * The settings repository instance. * - * @var \Illuminate\Config\Repository + * @var \CachetHQ\Cachet\Settings\Repository */ - protected $config; + protected $settings; /** * Constructs a new localize middleware instance. * - * @param \Illuminate\Config\Repository $config + * @param \Illuminate\Contracts\Config\Repository $config + * @param \CachetHQ\Cachet\Settings\Repository $settings * * @return void */ - public function __construct(Repository $config) + public function __construct(ConfigRepository $config, SettingsRepository $settings) { $this->config = $config; - $this->langs = $config->get('langs'); + $this->settings = $settings; } /** @@ -55,17 +64,18 @@ public function __construct(Repository $config) */ public function handle(Request $request, Closure $next) { - if (!(bool) $this->config->get('setting.automatic_localization')) { + if (!(bool) $this->settings->get('automatic_localization')) { return $next($request); } - $supportedLanguages = $request->getLanguages(); + $requestedLanguages = $request->getLanguages(); $userLanguage = $this->config->get('app.locale'); + $langs = $this->config->get('langs'); - foreach ($supportedLanguages as $language) { + foreach ($requestedLanguages as $language) { $language = str_replace('_', '-', $language); - if (isset($this->langs[$language])) { + if (isset($langs[$language])) { $userLanguage = $language; break; } diff --git a/app/Http/Middleware/ReadyForUse.php b/app/Http/Middleware/ReadyForUse.php index 364c7f42a50..11b1afbbb80 100644 --- a/app/Http/Middleware/ReadyForUse.php +++ b/app/Http/Middleware/ReadyForUse.php @@ -11,14 +11,38 @@ namespace CachetHQ\Cachet\Http\Middleware; +use CachetHQ\Cachet\Settings\Repository; use Closure; -use Exception; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Config; -use Illuminate\Support\Facades\Redirect; +/** + * This is the ready for use middleware class. + * + * @author Graham Campbell + * @author James Brooks + * @author Joseph Cohen + */ class ReadyForUse { + /** + * The settings repository instance. + * + * @var \CachetHQ\Cachet\Settings\Repository + */ + protected $settings; + + /** + * Creates a new setup already completed middleware instance. + * + * @param \CachetHQ\Cachet\Settings\Repository $settings + * + * @return void + */ + public function __construct(Repository $settings) + { + $this->settings = $settings; + } + /** * Handle an incoming request. * @@ -29,12 +53,8 @@ class ReadyForUse */ public function handle(Request $request, Closure $next) { - try { - if (!Config::get('setting.app_name')) { - return Redirect::to('setup'); - } - } catch (Exception $e) { - return Redirect::to('setup'); + if (!$request->is('setup*') && !$this->settings->get('app_name')) { + return cachet_redirect('setup'); } return $next($request); diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index 7b79128b3a2..b8c95648544 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -13,9 +13,15 @@ use Closure; use Illuminate\Contracts\Auth\Guard; -use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; +/** + * This is the redirect if authenticated middleware class. + * + * @author Graham Campbell + * @author Joseph Cohen + * @author James Brooks + */ class RedirectIfAuthenticated { /** @@ -48,7 +54,7 @@ public function __construct(Guard $auth) public function handle(Request $request, Closure $next) { if ($this->auth->check()) { - return new RedirectResponse(route('dashboard.index')); + return cachet_redirect('dashboard'); } return $next($request); diff --git a/app/Http/Middleware/RemoteUserAuthenticate.php b/app/Http/Middleware/RemoteUserAuthenticate.php new file mode 100644 index 00000000000..075c0c4a13a --- /dev/null +++ b/app/Http/Middleware/RemoteUserAuthenticate.php @@ -0,0 +1,53 @@ +auth = $auth; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * + * @return mixed + */ + public function handle(Request $request, Closure $next) + { + if ($remoteUser = $request->server('REMOTE_USER')) { + $user = User::where('email', '=', $remoteUser)->first(); + + if ($user instanceof User && $this->auth->guest()) { + $this->auth->login($user); + } + } + + return $next($request); + } +} diff --git a/app/Http/Middleware/SetupAlreadyCompleted.php b/app/Http/Middleware/SetupAlreadyCompleted.php index 96db9729f5f..e0df0c8f5ed 100644 --- a/app/Http/Middleware/SetupAlreadyCompleted.php +++ b/app/Http/Middleware/SetupAlreadyCompleted.php @@ -11,13 +11,39 @@ namespace CachetHQ\Cachet\Http\Middleware; +use CachetHQ\Cachet\Settings\ReadException; +use CachetHQ\Cachet\Settings\Repository; use Closure; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Config; -use Illuminate\Support\Facades\Redirect; +/** + * This is the setup already completed middelware class. + * + * @author Graham Campbell + * @author James Brooks + * @author Joseph Cohen + */ class SetupAlreadyCompleted { + /** + * The settings repository instance. + * + * @var \CachetHQ\Cachet\Settings\Repository + */ + protected $settings; + + /** + * Creates a new setup already completed middleware instance. + * + * @param \CachetHQ\Cachet\Settings\Repository $settings + * + * @return void + */ + public function __construct(Repository $settings) + { + $this->settings = $settings; + } + /** * Handle an incoming request. * @@ -28,8 +54,12 @@ class SetupAlreadyCompleted */ public function handle(Request $request, Closure $next) { - if (Config::get('setting.app_name')) { - return Redirect::to('dashboard'); + try { + if ($this->settings->get('app_name')) { + return cachet_redirect('dashboard'); + } + } catch (ReadException $e) { + // not setup then! } return $next($request); diff --git a/app/Http/Middleware/SubscribersConfigured.php b/app/Http/Middleware/SubscribersConfigured.php index 50cdeedb6ed..116b20a5717 100644 --- a/app/Http/Middleware/SubscribersConfigured.php +++ b/app/Http/Middleware/SubscribersConfigured.php @@ -12,11 +12,36 @@ namespace CachetHQ\Cachet\Http\Middleware; use Closure; +use Illuminate\Contracts\Config\Repository; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Redirect; +/** + * This is the subscribers configured middleware class. + * + * @author James Brooks + * @author Graham Campbell + */ class SubscribersConfigured { + /** + * The config repository instance. + * + * @var \Illuminate\Contracts\Config\Repository + */ + protected $config; + + /** + * Creates a subscribers configured middleware instance. + * + * @param \Illuminate\Contracts\Config\Repository $config + * + * @return void + */ + public function __construct(Repository $config) + { + $this->config = $config; + } + /** * Handle an incoming request. * @@ -27,10 +52,6 @@ class SubscribersConfigured */ public function handle(Request $request, Closure $next) { - if (!subscribers_enabled()) { - return Redirect::route('status-page'); - } - return $next($request); } } diff --git a/app/Http/Middleware/Throttler.php b/app/Http/Middleware/Throttler.php new file mode 100644 index 00000000000..c8314963388 --- /dev/null +++ b/app/Http/Middleware/Throttler.php @@ -0,0 +1,125 @@ + + */ +class Throttler +{ + /** + * The rate limiter instance. + * + * @var \Illuminate\Cache\RateLimiter + */ + protected $limiter; + + /** + * Create a new throttler middleware instance. + * + * @param \Illuminate\Cache\RateLimiter $limiter + * + * @return void + */ + public function __construct(RateLimiter $limiter) + { + $this->limiter = $limiter; + } + + /** + * Handle an incoming request. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @param int|string $limit + * @param int|string $decay + * + * @throws \Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException + * + * @return mixed + */ + public function handle(Request $request, Closure $next, $limit = 60, $decay = 1) + { + return $this->safeHandle($request, $next, (int) $limit, (int) $decay); + } + + /** + * Handle an incoming request, with correct types. + * + * @param \Illuminate\Http\Request $request + * @param \Closure $next + * @param int $limit + * @param int $decay + * + * @throws \Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException + * + * @return mixed + */ + protected function safeHandle(Request $request, Closure $next, int $limit, int $decay) + { + $key = $request->fingerprint(); + + if ($this->limiter->tooManyAttempts($key, $limit, $decay)) { + throw $this->buildException($key, $limit); + } + + $this->limiter->hit($key, $decay); + + $response = $next($request); + + $response->headers->add($this->getHeaders($key, $limit)); + + return $response; + } + + /** + * Create a too many requests http exception. + * + * @param string $key + * @param int $limit + * + * @return \Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException + */ + protected function buildException(string $key, int $limit) + { + $after = $this->limiter->availableIn($key); + $exception = new TooManyRequestsHttpException($after, 'Rate limit exceeded.'); + $exception->setHeaders($this->getHeaders($key, $limit, $after, $exception->getHeaders())); + + return $exception; + } + + /** + * Get the limit header information. + * + * @param string $key + * @param int $limit + * @param int|null $after + * @param array $merge + * + * @return array + */ + protected function getHeaders(string $key, int $limit, int $after = null, array $merge = []) + { + $remaining = $after === null ? $this->limiter->retriesLeft($key, $limit) : 0; + $headers = ['X-RateLimit-Limit' => $limit, 'X-RateLimit-Remaining' => $remaining]; + + return array_merge($headers, $merge); + } +} diff --git a/app/Http/Middleware/Timezone.php b/app/Http/Middleware/Timezone.php index 8b56ddbbdbe..e0700714af9 100644 --- a/app/Http/Middleware/Timezone.php +++ b/app/Http/Middleware/Timezone.php @@ -15,6 +15,12 @@ use Illuminate\Contracts\Config\Repository; use Illuminate\Http\Request; +/** + * This is the timezone middleware class. + * + * @author James Brooks + * @author Graham Campbell + */ class Timezone { /** diff --git a/app/Http/Middleware/TrustProxies.php b/app/Http/Middleware/TrustProxies.php new file mode 100644 index 00000000000..83a86c5e6ff --- /dev/null +++ b/app/Http/Middleware/TrustProxies.php @@ -0,0 +1,50 @@ + + */ +class TrustProxies extends Middleware +{ + /** + * The trusted proxies for this application. + * + * @var array + */ + protected $proxies; + + /** + * The headers that should be used to detect proxies. + * + * @var int + */ + protected $headers = Request::HEADER_X_FORWARDED_ALL; + + /** + * Create new trust proxies instance. + * + * @return void + */ + public function __construct() + { + $proxies = Config::get('trustedproxies.proxies'); + + $this->proxies = empty($proxies) ? '*' : explode(',', trim($proxies)); + } +} diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php new file mode 100644 index 00000000000..cfd2fc055a5 --- /dev/null +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -0,0 +1,38 @@ + + */ +class VerifyCsrfToken extends Middleware +{ + /** + * Indicates whether the XSRF-TOKEN cookie should be set on the response. + * + * @var bool + */ + protected $addHttpCookie = true; + + /** + * The URIs that should be excluded from CSRF verification. + * + * @var array + */ + protected $except = [ + '/api/*', + ]; +} diff --git a/app/Http/Routes/ApiRoutes.php b/app/Http/Routes/ApiRoutes.php index 20744edbb07..b56902d3635 100644 --- a/app/Http/Routes/ApiRoutes.php +++ b/app/Http/Routes/ApiRoutes.php @@ -20,6 +20,13 @@ */ class ApiRoutes { + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = false; + /** * Define the api routes. * @@ -29,47 +36,62 @@ class ApiRoutes */ public function map(Registrar $router) { - $router->group(['namespace' => 'Api', 'prefix' => 'api/v1', 'middleware' => ['api']], function (Registrar $router) { - $router->group(['middleware' => ['auth.api']], function (Registrar $router) { - $router->get('ping', 'GeneralController@ping'); - $router->get('version', 'GeneralController@version'); + $router->group([ + 'namespace' => 'Api', + 'prefix' => 'api/v1', + ], function (Registrar $router) { + $router->group(['middleware' => ['auth.api', 'cors']], function (Registrar $router) { + $router->get('components', 'ComponentController@index'); + $router->get('components/groups', 'ComponentGroupController@index'); + $router->get('components/groups/{component_group}', 'ComponentGroupController@show'); + $router->get('components/{component}', 'ComponentController@show'); + + $router->get('incidents', 'IncidentController@index'); + + $router->get('incidents/templates', 'IncidentTemplateController@index'); + $router->get('incidents/templates/{incident_template}', 'IncidentTemplateController@show'); - $router->get('components', 'ComponentController@getComponents'); - $router->get('components/groups', 'ComponentGroupController@getGroups'); - $router->get('components/groups/{component_group}', 'ComponentGroupController@getGroup'); - $router->get('components/{component}', 'ComponentController@getComponent'); + $router->get('incidents/{incident}', 'IncidentController@show'); + $router->get('incidents/{incident}/updates', 'IncidentUpdateController@index'); + $router->get('incidents/{incident}/updates/{update}', 'IncidentUpdateController@show'); - $router->get('incidents', 'IncidentController@getIncidents'); - $router->get('incidents/{incident}', 'IncidentController@getIncident'); + $router->get('metrics', 'MetricController@index'); + $router->get('metrics/{metric}', 'MetricController@show'); + $router->get('metrics/{metric}/points', 'MetricPointController@index'); - $router->get('metrics', 'MetricController@getMetrics'); - $router->get('metrics/{metric}', 'MetricController@getMetric'); - $router->get('metrics/{metric}/points', 'MetricController@getMetricPoints'); + $router->get('schedules', 'ScheduleController@index'); + $router->get('schedules/{schedule}', 'ScheduleController@show'); }); $router->group(['middleware' => ['auth.api:true']], function (Registrar $router) { - $router->get('subscribers', 'SubscriberController@getSubscribers'); + $router->get('subscribers', 'SubscriberController@index'); - $router->post('components', 'ComponentController@postComponents'); - $router->post('components/groups', 'ComponentGroupController@postGroups'); - $router->post('incidents', 'IncidentController@postIncidents'); - $router->post('metrics', 'MetricController@postMetrics'); - $router->post('metrics/{metric}/points', 'MetricPointController@postMetricPoints'); - $router->post('subscribers', 'SubscriberController@postSubscribers'); + $router->post('components', 'ComponentController@store'); + $router->post('components/groups', 'ComponentGroupController@store'); + $router->post('incidents', 'IncidentController@store'); + $router->post('incidents/{incident}/updates', 'IncidentUpdateController@store'); + $router->post('metrics', 'MetricController@store'); + $router->post('metrics/{metric}/points', 'MetricPointController@store'); + $router->post('schedules', 'ScheduleController@store'); + $router->post('subscribers', 'SubscriberController@store'); - $router->put('components/groups/{component_group}', 'ComponentGroupController@putGroup'); - $router->put('components/{component}', 'ComponentController@putComponent'); - $router->put('incidents/{incident}', 'IncidentController@putIncident'); - $router->put('metrics/{metric}', 'MetricController@putMetric'); - $router->put('metrics/{metric}/points/{metric_point}', 'MetricPointController@putMetricPoint'); + $router->put('components/groups/{component_group}', 'ComponentGroupController@update'); + $router->put('components/{component}', 'ComponentController@update'); + $router->put('incidents/{incident}', 'IncidentController@update'); + $router->put('incidents/{incident}/updates/{update}', 'IncidentUpdateController@update'); + $router->put('metrics/{metric}', 'MetricController@update'); + $router->put('metrics/{metric}/points/{metric_point}', 'MetricPointController@update'); + $router->put('schedules/{schedule}', 'ScheduleController@update'); - $router->delete('components/groups/{component_group}', 'ComponentGroupController@deleteGroup'); - $router->delete('components/{component}', 'ComponentController@deleteComponent'); - $router->delete('incidents/{incident}', 'IncidentController@deleteIncident'); - $router->delete('metrics/{metric}', 'MetricController@deleteMetric'); - $router->delete('metrics/{metric}/points/{metric_point}', 'MetricPointController@deleteMetricPoint'); - $router->delete('subscribers/{subscriber}', 'SubscriberController@deleteSubscriber'); - $router->delete('subscriptions/{subscription}', 'SubscriberController@deleteSubscription'); + $router->delete('components/groups/{component_group}', 'ComponentGroupController@destroy'); + $router->delete('components/{component}', 'ComponentController@destroy'); + $router->delete('incidents/{incident}', 'IncidentController@destroy'); + $router->delete('incidents/{incident}/updates/{update}', 'IncidentUpdateController@destroy'); + $router->delete('metrics/{metric}', 'MetricController@destroy'); + $router->delete('metrics/{metric}/points/{metric_point}', 'MetricPointController@destroy'); + $router->delete('schedules/{schedule}', 'ScheduleController@destroy'); + $router->delete('subscribers/{subscriber}', 'SubscriberController@destroy'); + $router->delete('subscriptions/{subscription}', 'SubscriptionController@destroy'); }); }); } diff --git a/app/Http/Routes/ApiSystemRoutes.php b/app/Http/Routes/ApiSystemRoutes.php new file mode 100644 index 00000000000..92a7aa2e31a --- /dev/null +++ b/app/Http/Routes/ApiSystemRoutes.php @@ -0,0 +1,50 @@ + + */ +class ApiSystemRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = false; + + /** + * Define the api routes for the system status, ping and version. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'namespace' => 'Api', + 'prefix' => 'api/v1', + ], function (Registrar $router) { + $router->group(['middleware' => ['auth.api']], function (Registrar $router) { + $router->get('ping', 'GeneralController@ping'); + $router->get('version', 'GeneralController@version'); + $router->get('status', ['uses' => 'GeneralController@status', 'middleware' => ['cache']]); + }); + }); + } +} diff --git a/app/Http/Routes/AuthRoutes.php b/app/Http/Routes/AuthRoutes.php index f61477788e2..f1dd7fa96bd 100644 --- a/app/Http/Routes/AuthRoutes.php +++ b/app/Http/Routes/AuthRoutes.php @@ -20,6 +20,13 @@ */ class AuthRoutes { + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + /** * Define the auth routes. * @@ -29,30 +36,35 @@ class AuthRoutes */ public function map(Registrar $router) { - $router->group(['as' => 'auth.', 'middleware' => ['web', 'ready'], 'prefix' => 'auth'], function (Registrar $router) { + $router->group([ + 'middleware' => ['ready'], + 'prefix' => 'auth', + ], function (Registrar $router) { $router->get('login', [ + 'as' => 'get:auth.login', 'middleware' => 'guest', - 'as' => 'login', 'uses' => 'AuthController@showLogin', ]); $router->post('login', [ + 'as' => 'post:auth.login', 'middleware' => ['guest', 'throttle:10,10'], 'uses' => 'AuthController@postLogin', ]); $router->get('2fa', [ - 'as' => 'two-factor', + 'as' => 'get:auth.two-factor', 'uses' => 'AuthController@showTwoFactorAuth', ]); $router->post('2fa', [ + 'as' => 'post:auth.two-factor', 'middleware' => ['throttle:10,10'], 'uses' => 'AuthController@postTwoFactor', ]); $router->get('logout', [ - 'as' => 'logout', + 'as' => 'get:auth.logout', 'uses' => 'AuthController@logoutAction', 'middleware' => 'auth', ]); diff --git a/app/Http/Routes/Dashboard/ApiRoutes.php b/app/Http/Routes/Dashboard/ApiRoutes.php new file mode 100644 index 00000000000..46d186dc2bb --- /dev/null +++ b/app/Http/Routes/Dashboard/ApiRoutes.php @@ -0,0 +1,51 @@ + + * @author Connor S. Parks + */ +class ApiRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + + /** + * Define the dashboard api routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['auth'], + 'namespace' => 'Dashboard', + 'prefix' => 'dashboard/api', + ], function (Registrar $router) { + $router->get('incidents/templates', 'ApiController@getIncidentTemplate'); + $router->post('components/groups/order', 'ApiController@postUpdateComponentGroupOrder'); + $router->post('components/order', 'ApiController@postUpdateComponentOrder'); + $router->any('components/{component}', 'ApiController@postUpdateComponent'); + }); + } +} diff --git a/app/Http/Routes/Dashboard/BaseRoutes.php b/app/Http/Routes/Dashboard/BaseRoutes.php new file mode 100644 index 00000000000..61d7e742d8c --- /dev/null +++ b/app/Http/Routes/Dashboard/BaseRoutes.php @@ -0,0 +1,54 @@ + + * @author Connor S. Parks + */ +class BaseRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + + /** + * Define the dashboard base routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['auth'], + 'namespace' => 'Dashboard', + ], function (Registrar $router) { + $router->get('admin', 'DashboardController@redirectAdmin'); + + $router->group(['prefix' => 'dashboard'], function (Registrar $router) { + $router->get('/', [ + 'as' => 'get:dashboard', + 'uses' => 'DashboardController@showDashboard', + ]); + }); + }); + } +} diff --git a/app/Http/Routes/Dashboard/ComponentRoutes.php b/app/Http/Routes/Dashboard/ComponentRoutes.php new file mode 100644 index 00000000000..aa7852f827e --- /dev/null +++ b/app/Http/Routes/Dashboard/ComponentRoutes.php @@ -0,0 +1,100 @@ + + * @author Connor S. Parks + */ +class ComponentRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + + /** + * Define the dashboard component routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['auth'], + 'namespace' => 'Dashboard', + 'prefix' => 'dashboard/components', + ], function (Registrar $router) { + $router->get('/', [ + 'as' => 'get:dashboard.components', + 'uses' => 'ComponentController@showComponents', + ]); + + $router->get('create', [ + 'as' => 'get:dashboard.components.create', + 'uses' => 'ComponentController@showAddComponent', + ]); + $router->post('create', [ + 'as' => 'post:dashboard.components.create', + 'uses' => 'ComponentController@createComponentAction', + ]); + + $router->get('groups', [ + 'as' => 'get:dashboard.components.groups', + 'uses' => 'ComponentGroupController@showComponentGroups', + ]); + + $router->get('groups/create', [ + 'as' => 'get:dashboard.components.groups.create', + 'uses' => 'ComponentGroupController@showAddComponentGroup', + ]); + $router->post('groups/create', [ + 'as' => 'post:dashboard.components.groups.create', + 'uses' => 'ComponentGroupController@postAddComponentGroup', + ]); + + $router->get('groups/{component_group}', [ + 'as' => 'get:dashboard.components.groups.edit', + 'uses' => 'ComponentGroupController@showEditComponentGroup', + ]); + $router->post('groups/{component_group}', [ + 'as' => 'post:dashboard.components.groups.edit', + 'uses' => 'ComponentGroupController@updateComponentGroupAction', + ]); + $router->delete('groups/{component_group}', [ + 'as' => 'delete:dashboard.components.groups.delete', + 'uses' => 'ComponentGroupController@deleteComponentGroupAction', + ]); + + $router->get('{component}', [ + 'as' => 'get:dashboard.components.edit', + 'uses' => 'ComponentController@showEditComponent', + ]); + $router->post('{component}', [ + 'as' => 'post:dashboard.components.edit', + 'uses' => 'ComponentController@updateComponentAction', + ]); + $router->delete('{component}', [ + 'as' => 'delete:dashboard.components.delete', + 'uses' => 'ComponentController@deleteComponentAction', + ]); + }); + } +} diff --git a/app/Http/Routes/Dashboard/IncidentRoutes.php b/app/Http/Routes/Dashboard/IncidentRoutes.php new file mode 100644 index 00000000000..4eee1e5e8e7 --- /dev/null +++ b/app/Http/Routes/Dashboard/IncidentRoutes.php @@ -0,0 +1,94 @@ + + * @author Connor S. Parks + */ +class IncidentRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + + /** + * Define the dashboard incident routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['auth'], + 'namespace' => 'Dashboard', + 'prefix' => 'dashboard/incidents', + ], function (Registrar $router) { + $router->get('/', [ + 'as' => 'get:dashboard.incidents', + 'uses' => 'IncidentController@showIncidents', + ]); + + $router->get('create', [ + 'as' => 'get:dashboard.incidents.create', + 'uses' => 'IncidentController@showAddIncident', + ]); + $router->post('create', [ + 'as' => 'post:dashboard.incidents.create', + 'uses' => 'IncidentController@createIncidentAction', + ]); + + $router->get('{incident}', [ + 'as' => 'get:dashboard.incidents.edit', + 'uses' => 'IncidentController@showEditIncidentAction', + ]); + $router->post('{incident}', [ + 'as' => 'post:dashboard.incidents.edit', + 'uses' => 'IncidentController@editIncidentAction', + ]); + $router->delete('{incident}', [ + 'as' => 'delete:dashboard.incidents.delete', + 'uses' => 'IncidentController@deleteIncidentAction', + ]); + + $router->get('{incident}/updates', [ + 'as' => 'get:dashboard.incidents.updates', + 'uses' => 'IncidentUpdateController@showIncidentUpdates', + ]); + $router->get('{incident}/updates/create', [ + 'as' => 'get:dashboard.incidents.updates.create', + 'uses' => 'IncidentUpdateController@showCreateIncidentUpdateAction', + ]); + $router->post('{incident}/updates/create', [ + 'as' => 'post:dashboard.incidents.updates.create', + 'uses' => 'IncidentUpdateController@createIncidentUpdateAction', + ]); + $router->get('{incident}/updates/{incident_update}', [ + 'as' => 'get:dashboard.incidents.updates.edit', + 'uses' => 'IncidentUpdateController@showEditIncidentUpdateAction', + ]); + $router->post('{incident}/updates/{incident_update}', [ + 'as' => 'post:dashboard.incidents.updates.edit', + 'uses' => 'IncidentUpdateController@editIncidentUpdateAction', + ]); + }); + } +} diff --git a/app/Http/Routes/Dashboard/MetricRoutes.php b/app/Http/Routes/Dashboard/MetricRoutes.php new file mode 100644 index 00000000000..3f28899d866 --- /dev/null +++ b/app/Http/Routes/Dashboard/MetricRoutes.php @@ -0,0 +1,73 @@ + + * @author Connor S. Parks + */ +class MetricRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + + /** + * Define the dashboard metric routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['auth'], + 'namespace' => 'Dashboard', + 'prefix' => 'dashboard/metrics', + ], function (Registrar $router) { + $router->get('/', [ + 'as' => 'get:dashboard.metrics', + 'uses' => 'MetricController@showMetrics', + ]); + + $router->get('create', [ + 'as' => 'get:dashboard.metrics.create', + 'uses' => 'MetricController@showAddMetric', + ]); + $router->post('create', [ + 'as' => 'post:dashboard.metrics.create', + 'uses' => 'MetricController@createMetricAction', + ]); + + $router->get('{metric}', [ + 'as' => 'get:dashboard.metrics.edit', + 'uses' => 'MetricController@showEditMetricAction', + ]); + $router->post('{metric}', [ + 'as' => 'post:dashboard.metrics.edit', + 'uses' => 'MetricController@editMetricAction', + ]); + $router->delete('{metric}', [ + 'as' => 'delete:dashboard.metrics.delete', + 'uses' => 'MetricController@deleteMetricAction', + ]); + }); + } +} diff --git a/app/Http/Routes/Dashboard/ScheduleRoutes.php b/app/Http/Routes/Dashboard/ScheduleRoutes.php new file mode 100644 index 00000000000..8591d1500c9 --- /dev/null +++ b/app/Http/Routes/Dashboard/ScheduleRoutes.php @@ -0,0 +1,73 @@ + + * @author Connor S. Parks + */ +class ScheduleRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + + /** + * Define the dashboard schedule routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['auth'], + 'namespace' => 'Dashboard', + 'prefix' => 'dashboard/schedule', + ], function (Registrar $router) { + $router->get('/', [ + 'as' => 'get:dashboard.schedule', + 'uses' => 'ScheduleController@showIndex', + ]); + + $router->get('create', [ + 'as' => 'get:dashboard.schedule.create', + 'uses' => 'ScheduleController@showAddSchedule', + ]); + $router->post('create', [ + 'as' => 'post:dashboard.schedule.create', + 'uses' => 'ScheduleController@addScheduleAction', + ]); + + $router->get('{schedule}', [ + 'as' => 'get:dashboard.schedule.edit', + 'uses' => 'ScheduleController@showEditSchedule', + ]); + $router->post('{schedule}', [ + 'as' => 'post:dashboard.schedule.edit', + 'uses' => 'ScheduleController@editScheduleAction', + ]); + $router->delete('{schedule}', [ + 'as' => 'delete:dashboard.schedule.delete', + 'uses' => 'ScheduleController@deleteScheduleAction', + ]); + }); + } +} diff --git a/app/Http/Routes/Dashboard/SettingRoutes.php b/app/Http/Routes/Dashboard/SettingRoutes.php new file mode 100644 index 00000000000..a963470d721 --- /dev/null +++ b/app/Http/Routes/Dashboard/SettingRoutes.php @@ -0,0 +1,100 @@ + + * @author Connor S. Parks + */ +class SettingRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + + /** + * Define the dashboard setting routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['auth'], + 'namespace' => 'Dashboard', + 'prefix' => 'dashboard/settings', + ], function (Registrar $router) { + $router->get('setup', [ + 'as' => 'get:dashboard.settings.setup', + 'uses' => 'SettingsController@showSetupView', + ]); + $router->get('analytics', [ + 'as' => 'get:dashboard.settings.analytics', + 'uses' => 'SettingsController@showAnalyticsView', + ]); + $router->get('localization', [ + 'as' => 'get:dashboard.settings.localization', + 'uses' => 'SettingsController@showLocalizationView', + ]); + $router->get('security', [ + 'as' => 'get:dashboard.settings.security', + 'uses' => 'SettingsController@showSecurityView', + ]); + $router->get('theme', [ + 'as' => 'get:dashboard.settings.theme', + 'uses' => 'SettingsController@showThemeView', + ]); + $router->get('stylesheet', [ + 'as' => 'get:dashboard.settings.stylesheet', + 'uses' => 'SettingsController@showStylesheetView', + ]); + $router->get('customization', [ + 'as' => 'get:dashboard.settings.customization', + 'uses' => 'SettingsController@showCustomizationView', + ]); + $router->get('credits', [ + 'as' => 'get:dashboard.settings.credits', + 'uses' => 'SettingsController@showCreditsView', + ]); + $router->get('log', [ + 'as' => 'get:dashboard.settings.log', + 'uses' => 'SettingsController@showLogView', + ]); + $router->get('mail', [ + 'as' => 'get:dashboard.settings.mail', + 'uses' => 'SettingsController@showMailView', + ]); + $router->post('mail', [ + 'as' => 'post:dashboard.settings.mail', + 'uses' => 'SettingsController@postMail', + ]); + $router->post('mail/test', [ + 'as' => 'post:dashboard.settings.mail.test', + 'uses' => 'SettingsController@testMail', + ]); + + $router->post('/', [ + 'as' => 'post:dashboard.settings', + 'uses' => 'SettingsController@postSettings', + ]); + }); + } +} diff --git a/app/Http/Routes/Dashboard/SubscriberRoutes.php b/app/Http/Routes/Dashboard/SubscriberRoutes.php new file mode 100644 index 00000000000..129d786f8bd --- /dev/null +++ b/app/Http/Routes/Dashboard/SubscriberRoutes.php @@ -0,0 +1,65 @@ + + * @author Connor S. Parks + */ +class SubscriberRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + + /** + * Define the dashboard subscriber routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['auth'], + 'namespace' => 'Dashboard', + 'prefix' => 'dashboard/subscribers', + ], function (Registrar $router) { + $router->get('/', [ + 'as' => 'get:dashboard.subscribers', + 'uses' => 'SubscriberController@showSubscribers', + ]); + + $router->get('create', [ + 'as' => 'get:dashboard.subscribers.create', + 'uses' => 'SubscriberController@showAddSubscriber', + ]); + $router->post('create', [ + 'as' => 'post:dashboard.subscribers.create', + 'uses' => 'SubscriberController@createSubscriberAction', + ]); + + $router->delete('{subscriber}/delete', [ + 'as' => 'delete:dashboard.subscribers.delete', + 'uses' => 'SubscriberController@deleteSubscriberAction', + ]); + }); + } +} diff --git a/app/Http/Routes/Dashboard/TeamRoutes.php b/app/Http/Routes/Dashboard/TeamRoutes.php new file mode 100644 index 00000000000..8872859227a --- /dev/null +++ b/app/Http/Routes/Dashboard/TeamRoutes.php @@ -0,0 +1,84 @@ + + * @author Connor S. Parks + */ +class TeamRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + + /** + * Define the dashboard team routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['auth'], + 'namespace' => 'Dashboard', + 'prefix' => 'dashboard/team', + ], function (Registrar $router) { + $router->get('/', [ + 'as' => 'get:dashboard.team', + 'uses' => 'TeamController@showTeamView', + ]); + + $router->group(['middleware' => 'admin'], function (Registrar $router) { + $router->get('create', [ + 'as' => 'get:dashboard.team.create', + 'uses' => 'TeamController@showAddTeamMemberView', + ]); + $router->post('create', [ + 'as' => 'post:dashboard.team.create', + 'uses' => 'TeamController@postAddUser', + ]); + + $router->get('invite', [ + 'as' => 'get:dashboard.team.invite', + 'uses' => 'TeamController@showInviteTeamMemberView', + ]); + $router->post('invite', [ + 'as' => 'post:dashboard.team.invite', + 'uses' => 'TeamController@postInviteUser', + ]); + + $router->get('{user}', [ + 'as' => 'get:dashboard.team.edit', + 'uses' => 'TeamController@showTeamMemberView', + ]); + $router->post('{user}', [ + 'as' => 'post::dashboard.team.edit', + 'uses' => 'TeamController@postUpdateUser', + ]); + $router->delete('{user}', [ + 'as' => 'delete:dashboard.team.delete', + 'uses' => 'TeamController@deleteUser', + ]); + }); + }); + } +} diff --git a/app/Http/Routes/Dashboard/TemplateRoutes.php b/app/Http/Routes/Dashboard/TemplateRoutes.php new file mode 100644 index 00000000000..ee4ed5df269 --- /dev/null +++ b/app/Http/Routes/Dashboard/TemplateRoutes.php @@ -0,0 +1,73 @@ + + * @author Connor S. Parks + */ +class TemplateRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + + /** + * Define the dashboard template routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['auth'], + 'namespace' => 'Dashboard', + 'prefix' => 'dashboard/templates', + ], function (Registrar $router) { + $router->get('/', [ + 'as' => 'get:dashboard.templates', + 'uses' => 'IncidentTemplateController@showTemplates', + ]); + + $router->get('create', [ + 'as' => 'get:dashboard.templates.create', + 'uses' => 'IncidentTemplateController@showAddIncidentTemplate', + ]); + $router->post('create', [ + 'as' => 'post:dashboard.templates.create', + 'uses' => 'IncidentTemplateController@createIncidentTemplateAction', + ]); + + $router->get('{incident_template}', [ + 'as' => 'get:dashboard.templates.edit', + 'uses' => 'IncidentTemplateController@showEditTemplateAction', + ]); + $router->post('{incident_template}', [ + 'as' => 'post:dashboard.templates.edit', + 'uses' => 'IncidentTemplateController@editTemplateAction', + ]); + $router->delete('{incident_template}', [ + 'as' => 'delete:dashboard.templates.delete', + 'uses' => 'IncidentTemplateController@deleteTemplateAction', + ]); + }); + } +} diff --git a/app/Http/Routes/Dashboard/UserRoutes.php b/app/Http/Routes/Dashboard/UserRoutes.php new file mode 100644 index 00000000000..15720a46446 --- /dev/null +++ b/app/Http/Routes/Dashboard/UserRoutes.php @@ -0,0 +1,60 @@ + + * @author Connor S. Parks + */ +class UserRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + + /** + * Define the dashboard user routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['auth'], + 'namespace' => 'Dashboard', + 'prefix' => 'dashboard/user', + ], function (Registrar $router) { + $router->get('/', [ + 'as' => 'get:dashboard.user', + 'uses' => 'UserController@showUser', + ]); + $router->post('/', [ + 'as' => 'post:dashboard.user', + 'uses' => 'UserController@postUser', + ]); + + $router->get('{user}/api/regen', [ + 'as' => 'get:dashboard.user.api.regen', + 'uses' => 'UserController@regenerateApiKey', + ]); + }); + } +} diff --git a/app/Http/Routes/DashboardRoutes.php b/app/Http/Routes/DashboardRoutes.php deleted file mode 100644 index b723baf6f2b..00000000000 --- a/app/Http/Routes/DashboardRoutes.php +++ /dev/null @@ -1,242 +0,0 @@ - - */ -class DashboardRoutes -{ - /** - * Define the dashboard routes. - * - * @param \Illuminate\Contracts\Routing\Registrar $router - * - * @return void - */ - public function map(Registrar $router) - { - $router->group(['middleware' => ['web', 'auth'], 'namespace' => 'Dashboard'], function (Registrar $router) { - $router->get('admin', 'DashboardController@redirectAdmin'); - - $router->group(['prefix' => 'dashboard', 'as' => 'dashboard.'], function (Registrar $router) { - $router->get('/', [ - 'as' => 'index', - 'uses' => 'DashboardController@showDashboard', - ]); - - $router->group(['as' => 'components.', 'prefix' => 'components'], function (Registrar $router) { - $router->get('/', [ - 'as' => 'index', - 'uses' => 'ComponentController@showComponents', - ]); - $router->get('add', [ - 'as' => 'add', - 'uses' => 'ComponentController@showAddComponent', - ]); - $router->post('add', 'ComponentController@createComponentAction'); - $router->get('groups', [ - 'as' => 'groups', - 'uses' => 'ComponentController@showComponentGroups', - ]); - $router->get('groups/add', [ - 'as' => 'groups.add', - 'uses' => 'ComponentController@showAddComponentGroup', - ]); - $router->get('groups/edit/{component_group}', [ - 'as' => 'groups.edit', - 'uses' => 'ComponentController@showEditComponentGroup', - ]); - $router->post('groups/edit/{component_group}', 'ComponentController@updateComponentGroupAction'); - $router->delete('groups/{component_group}/delete', 'ComponentController@deleteComponentGroupAction'); - $router->post('groups/add', 'ComponentController@postAddComponentGroup'); - $router->get('{component}/edit', [ - 'as' => 'edit', - 'uses' => 'ComponentController@showEditComponent', - ]); - $router->delete('{component}/delete', 'ComponentController@deleteComponentAction'); - $router->post('{component}/edit', 'ComponentController@updateComponentAction'); - }); - - $router->group(['as' => 'incidents.', 'prefix' => 'incidents'], function (Registrar $router) { - $router->get('/', [ - 'as' => 'index', - 'uses' => 'IncidentController@showIncidents', - ]); - $router->get('add', [ - 'as' => 'add', - 'uses' => 'IncidentController@showAddIncident', - ]); - $router->post('add', 'IncidentController@createIncidentAction'); - $router->delete('{incident}/delete', [ - 'as' => 'delete', - 'uses' => 'IncidentController@deleteIncidentAction', - ]); - $router->get('{incident}/edit', [ - 'as' => 'edit', - 'uses' => 'IncidentController@showEditIncidentAction', - ]); - $router->post('{incident}/edit', 'IncidentController@editIncidentAction'); - }); - - $router->group(['as' => 'schedule.', 'prefix' => 'schedule'], function (Registrar $router) { - $router->get('/', [ - 'as' => 'index', - 'uses' => 'ScheduleController@showIndex', - ]); - $router->get('add', [ - 'as' => 'add', - 'uses' => 'ScheduleController@showAddSchedule', - ]); - $router->post('add', 'ScheduleController@addScheduleAction'); - $router->get('{incident}/edit', [ - 'as' => 'edit', - 'uses' => 'ScheduleController@showEditSchedule', - ]); - $router->post('{incident}/edit', 'ScheduleController@editScheduleAction'); - $router->delete('{incident}/delete', [ - 'as' => 'delete', - 'uses' => 'ScheduleController@deleteScheduleAction', - ]); - }); - - $router->group(['as' => 'templates.', 'prefix' => 'templates'], function (Registrar $router) { - $router->get('/', [ - 'as' => 'index', - 'uses' => 'IncidentController@showTemplates', - ]); - $router->get('add', [ - 'as' => 'add', - 'uses' => 'IncidentController@showAddIncidentTemplate', - ]); - $router->post('add', 'IncidentController@createIncidentTemplateAction'); - $router->get('{incident_template}/edit', [ - 'as' => 'edit', - 'uses' => 'IncidentController@showEditTemplateAction', - ]); - $router->post('{incident_template}/edit', 'IncidentController@editTemplateAction'); - $router->delete('{incident_template}/delete', 'IncidentController@deleteTemplateAction'); - }); - - $router->group(['as' => 'subscribers.', 'prefix' => 'subscribers'], function (Registrar $router) { - $router->get('/', [ - 'as' => 'index', - 'uses' => 'SubscriberController@showSubscribers', - ]); - $router->get('add', [ - 'as' => 'add', - 'uses' => 'SubscriberController@showAddSubscriber', - ]); - $router->post('add', 'SubscriberController@createSubscriberAction'); - $router->delete('{subscriber}/delete', 'SubscriberController@deleteSubscriberAction'); - }); - - $router->group(['as' => 'metrics.', 'prefix' => 'metrics'], function (Registrar $router) { - $router->get('/', [ - 'as' => 'index', - 'uses' => 'MetricController@showMetrics', - ]); - $router->get('add', [ - 'as' => 'add', - 'uses' => 'MetricController@showAddMetric', - ]); - $router->post('add', 'MetricController@createMetricAction'); - $router->delete('{metric}/delete', 'MetricController@deleteMetricAction'); - $router->get('{metric}/edit', [ - 'as' => 'edit', - 'uses' => 'MetricController@showEditMetricAction', - ]); - $router->post('{metric}/edit', 'MetricController@editMetricAction'); - }); - - $router->group(['as' => 'team.', 'prefix' => 'team'], function (Registrar $router) { - $router->get('/', [ - 'as' => 'index', - 'uses' => 'TeamController@showTeamView', - ]); - - $router->group(['middleware' => 'admin'], function (Registrar $router) { - $router->get('add', [ - 'as' => 'add', - 'uses' => 'TeamController@showAddTeamMemberView', - ]); - $router->get('invite', [ - 'as' => 'invite', - 'uses' => 'TeamController@showInviteTeamMemberView', - ]); - $router->get('{user}', ['as' => 'edit', 'uses' => 'TeamController@showTeamMemberView']); - $router->post('add', 'TeamController@postAddUser'); - $router->post('invite', 'TeamController@postInviteUser'); - $router->post('{user}', 'TeamController@postUpdateUser'); - $router->delete('{user}/delete', 'TeamController@deleteUser'); - }); - }); - - $router->group(['as' => 'settings.', 'prefix' => 'settings'], function (Registrar $router) { - $router->get('setup', [ - 'as' => 'setup', - 'uses' => 'SettingsController@showSetupView', - ]); - $router->get('analytics', [ - 'as' => 'analytics', - 'uses' => 'SettingsController@showAnalyticsView', - ]); - $router->get('localization', [ - 'as' => 'localization', - 'uses' => 'SettingsController@showLocalizationView', - ]); - $router->get('security', [ - 'as' => 'security', - 'uses' => 'SettingsController@showSecurityView', - ]); - $router->get('theme', [ - 'as' => 'theme', - 'uses' => 'SettingsController@showThemeView', - ]); - $router->get('stylesheet', [ - 'as' => 'stylesheet', - 'uses' => 'SettingsController@showStylesheetView', - ]); - $router->get('customization', [ - 'as' => 'customization', - 'uses' => 'SettingsController@showCustomizationView', - ]); - $router->get('credits', [ - 'as' => 'credits', - 'uses' => 'SettingsController@showCreditsView', - ]); - $router->post('/', 'SettingsController@postSettings'); - }); - - $router->group(['prefix' => 'user'], function (Registrar $router) { - $router->get('/', [ - 'as' => 'user', - 'uses' => 'UserController@showUser', - ]); - $router->post('/', 'UserController@postUser'); - $router->get('{user}/api/regen', 'UserController@regenerateApiKey'); - }); - - $router->group(['prefix' => 'api'], function (Registrar $router) { - $router->get('incidents/templates', 'ApiController@getIncidentTemplate'); - $router->post('components/groups/order', 'ApiController@postUpdateComponentGroupOrder'); - $router->post('components/order', 'ApiController@postUpdateComponentOrder'); - $router->post('components/{component}', 'ApiController@postUpdateComponent'); - }); - }); - }); - } -} diff --git a/app/Http/Routes/FeedRoutes.php b/app/Http/Routes/FeedRoutes.php deleted file mode 100644 index f5d1f3ee6a5..00000000000 --- a/app/Http/Routes/FeedRoutes.php +++ /dev/null @@ -1,43 +0,0 @@ - - */ -class FeedRoutes -{ - /** - * Define the status page routes. - * - * @param \Illuminate\Contracts\Routing\Registrar $router - * - * @return void - */ - public function map(Registrar $router) - { - $router->group(['middleware' => ['web', 'ready']], function (Registrar $router) { - $router->get('/atom/{component_group?}', [ - 'as' => 'feed.atom', - 'uses' => 'FeedController@atomAction', - ]); - $router->get('/rss/{component_group?}', [ - 'as' => 'feed.rss', - 'uses' => 'FeedController@rssAction', - ]); - }); - } -} diff --git a/app/Http/Routes/Setup/ApiRoutes.php b/app/Http/Routes/Setup/ApiRoutes.php new file mode 100644 index 00000000000..8a3a3897779 --- /dev/null +++ b/app/Http/Routes/Setup/ApiRoutes.php @@ -0,0 +1,59 @@ + + */ +class ApiRoutes +{ + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = false; + + /** + * Define the setup routes. + * + * @param \Illuminate\Contracts\Routing\Registrar $router + * + * @return void + */ + public function map(Registrar $router) + { + $router->group([ + 'middleware' => ['setup'], + 'prefix' => 'setup', + ], function (Registrar $router) { + $router->post('step1', [ + 'as' => 'post:setup.step1', + 'uses' => 'SetupController@postStep1', + ]); + + $router->post('step2', [ + 'as' => 'post:setup.step2', + 'uses' => 'SetupController@postStep2', + ]); + + $router->post('step3', [ + 'as' => 'post:setup.step3', + 'uses' => 'SetupController@postStep3', + ]); + }); + } +} diff --git a/app/Http/Routes/SetupRoutes.php b/app/Http/Routes/SetupRoutes.php index d2a33515476..eb1319546bd 100644 --- a/app/Http/Routes/SetupRoutes.php +++ b/app/Http/Routes/SetupRoutes.php @@ -21,6 +21,13 @@ */ class SetupRoutes { + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + /** * Define the setup routes. * @@ -30,11 +37,14 @@ class SetupRoutes */ public function map(Registrar $router) { - $router->group(['middleware' => ['web', 'setup']], function (Registrar $router) { - $router->get('setup', 'SetupController@getIndex'); - $router->post('setup/step1', 'SetupController@postStep1'); - $router->post('setup/step2', 'SetupController@postStep2'); - $router->post('setup/step3', 'SetupController@postStep3'); + $router->group([ + 'middleware' => ['setup'], + 'prefix' => 'setup', + ], function (Registrar $router) { + $router->get('/', [ + 'as' => 'get:setup', + 'uses' => 'SetupController@getIndex', + ]); }); } } diff --git a/app/Http/Routes/SignupRoutes.php b/app/Http/Routes/SignupRoutes.php index 8e9d7f466c2..8530726175a 100644 --- a/app/Http/Routes/SignupRoutes.php +++ b/app/Http/Routes/SignupRoutes.php @@ -20,6 +20,13 @@ */ class SignupRoutes { + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + /** * Define the signup routes. * @@ -29,13 +36,17 @@ class SignupRoutes */ public function map(Registrar $router) { - $router->group(['middleware' => ['web', 'ready', 'guest'], 'as' => 'signup.'], function (Registrar $router) { - $router->get('signup/invite/{code}', [ - 'as' => 'invite', + $router->group([ + 'middleware' => ['ready', 'guest'], + 'prefix' => 'signup', + ], function (Registrar $router) { + $router->get('invite/{code}', [ + 'as' => 'get:signup.invite', 'uses' => 'SignupController@getSignup', ]); - $router->post('signup/invite/{code}', [ + $router->post('invite/{code}', [ + 'as' => 'post:signup.invite', 'uses' => 'SignupController@postSignup', ]); }); diff --git a/app/Http/Routes/StatusPageRoutes.php b/app/Http/Routes/StatusPageRoutes.php index ede2b7e1b69..20bd69089af 100644 --- a/app/Http/Routes/StatusPageRoutes.php +++ b/app/Http/Routes/StatusPageRoutes.php @@ -20,6 +20,13 @@ */ class StatusPageRoutes { + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + /** * Define the status page routes. * @@ -29,23 +36,33 @@ class StatusPageRoutes */ public function map(Registrar $router) { - $router->group(['middleware' => ['web', 'ready', 'localize']], function (Registrar $router) { + $router->group([ + 'middleware' => ['ready', 'localize'], + ], function (Registrar $router) { $router->get('/', [ - 'as' => 'status-page', + 'as' => 'get:status-page', 'uses' => 'StatusPageController@showIndex', ]); - $router->get('incident/{incident}', [ - 'as' => 'incident', + $router->get('incidents/{incident}', [ + 'as' => 'get:incident', 'uses' => 'StatusPageController@showIncident', ]); + $router->get('schedules/{schedule}', [ + 'as' => 'get:schedule', + 'uses' => 'StatusPageController@showSchedule', + ]); + $router->get('metrics/{metric}', [ - 'as' => 'metrics', + 'as' => 'get:metric', 'uses' => 'StatusPageController@getMetrics', ]); - $router->get('component/{component}/shield', 'StatusPageController@showComponentBadge'); + $router->get('component/{component}/shield', [ + 'as' => 'get:component_shield', + 'uses' => 'StatusPageController@showComponentBadge', + ]); }); } } diff --git a/app/Http/Routes/SubscribeRoutes.php b/app/Http/Routes/SubscribeRoutes.php index cc0dc0f2aae..8c5279d43e9 100644 --- a/app/Http/Routes/SubscribeRoutes.php +++ b/app/Http/Routes/SubscribeRoutes.php @@ -20,6 +20,13 @@ */ class SubscribeRoutes { + /** + * Defines if these routes are for the browser. + * + * @var bool + */ + public static $browser = true; + /** * Define the subscribe routes. * @@ -29,33 +36,36 @@ class SubscribeRoutes */ public function map(Registrar $router) { - $router->group(['middleware' => ['web', 'ready', 'localize', 'subscribers'], 'as' => 'subscribe.'], function (Registrar $router) { + $router->group([ + 'middleware' => ['ready', 'localize', 'subscribers'], + ], function (Registrar $router) { $router->get('subscribe', [ - 'as' => 'subscribe', + 'as' => 'get:subscribe', 'uses' => 'SubscribeController@showSubscribe', ]); - $router->post('subscribe', [ + 'as' => 'post:subscribe', 'uses' => 'SubscribeController@postSubscribe', ]); $router->get('subscribe/manage/{code}', [ - 'as' => 'manage', - 'uses' => 'SubscribeController@showManage', + 'as' => 'get:subscribe.manage', + 'middleware' => ['signed'], + 'uses' => 'SubscribeController@showManage', ]); - $router->post('subscribe/manage/{code}', [ - 'as' => 'manage', + 'as' => 'post:subscribe.manage', 'uses' => 'SubscribeController@postManage', ]); $router->get('subscribe/verify/{code}', [ - 'as' => 'verify', - 'uses' => 'SubscribeController@getVerify', + 'as' => 'get:subscribe.verify', + 'middleware' => ['signed'], + 'uses' => 'SubscribeController@getVerify', ]); $router->get('unsubscribe/{code}/{subscription?}', [ - 'as' => 'unsubscribe', + 'as' => 'get:subscribe.unsubscribe', 'uses' => 'SubscribeController@getUnsubscribe', ]); }); diff --git a/app/Integrations/Contracts/Beacon.php b/app/Integrations/Contracts/Beacon.php new file mode 100644 index 00000000000..61571403a11 --- /dev/null +++ b/app/Integrations/Contracts/Beacon.php @@ -0,0 +1,34 @@ + + */ +interface Beacon +{ + /** + * Has the install enabled Cachet beacon? + * + * @return bool + */ + public function enabled(); + + /** + * Send a beacon to our server. + * + * @return void + */ + public function send(); +} diff --git a/app/Integrations/Contracts/Credits.php b/app/Integrations/Contracts/Credits.php new file mode 100644 index 00000000000..192907ca437 --- /dev/null +++ b/app/Integrations/Contracts/Credits.php @@ -0,0 +1,27 @@ + + */ +interface Credits +{ + /** + * Returns the latest credits. + * + * @return array|null + */ + public function latest(); +} diff --git a/app/Integrations/Contracts/Feed.php b/app/Integrations/Contracts/Feed.php new file mode 100644 index 00000000000..2c7682f448e --- /dev/null +++ b/app/Integrations/Contracts/Feed.php @@ -0,0 +1,27 @@ + + */ +interface Feed +{ + /** + * Returns the latest entries. + * + * @return array|null + */ + public function latest(); +} diff --git a/app/Integrations/Contracts/Releases.php b/app/Integrations/Contracts/Releases.php new file mode 100644 index 00000000000..f1526c8e07f --- /dev/null +++ b/app/Integrations/Contracts/Releases.php @@ -0,0 +1,27 @@ + + */ +interface Releases +{ + /** + * Returns the latest release. + * + * @return string + */ + public function latest(); +} diff --git a/app/Integrations/Contracts/System.php b/app/Integrations/Contracts/System.php new file mode 100644 index 00000000000..a064e71065f --- /dev/null +++ b/app/Integrations/Contracts/System.php @@ -0,0 +1,48 @@ + + */ +interface System +{ + /** + * Get the entire system status. + * + * @return array + */ + public function getStatus(); + + /** + * Determine if Cachet is allowed to send notifications to users, subscribers or third party tools. + * + * @return bool + */ + public function canNotifySubscribers(); + + /** + * Get the cachet version. + * + * @return string + */ + public function getVersion(); + + /** + * Get the table prefix. + * + * @return string + */ + public function getTablePrefix(); +} diff --git a/app/Integrations/Core/Beacon.php b/app/Integrations/Core/Beacon.php new file mode 100644 index 00000000000..f4a283ab835 --- /dev/null +++ b/app/Integrations/Core/Beacon.php @@ -0,0 +1,123 @@ + + */ +class Beacon implements BeaconContract +{ + /** + * The beacon url. + * + * @var string + */ + const URL = 'https://cachethq.io/beacon'; + + /** + * The illuminate config instance. + * + * @var \Illuminate\Contracts\Config\Repository + */ + protected $config; + + /** + * Create a new beacon instance. + * + * @param \Illuminate\Contracts\Config\Repository $config + * + * @return void + */ + public function __construct(Repository $config) + { + $this->config = $config; + } + + /** + * Has the install enabled Cachet beacon? + * + * @return bool + */ + public function enabled() + { + return $this->config->get('cachet.beacon'); + } + + /** + * Send a beacon to our server. + * + * @return void + */ + public function send() + { + // We don't want any accidental sending of beacons if the installation has explicitly said no. + if (!$this->enabled()) { + return; + } + + $setting = app(Setting::class); + + if (!$installId = $setting->get('install_id', null)) { + $installId = sha1(Str::random(20)); + + $setting->set('install_id', $installId); + } + + $payload = [ + 'install_id' => $installId, + 'version' => CACHET_VERSION, + 'docker' => $this->config->get('cachet.is_docker'), + 'database' => $this->config->get('database.default'), + 'data' => [ + 'components' => Component::all()->count(), + 'incidents' => Incident::all()->count(), + 'metrics' => Metric::all()->count(), + 'users' => User::all()->count(), + 'actions' => Action::all()->count(), + 'tags' => Tag::all()->count(), + 'schedules' => Schedule::all()->count(), + ], + ]; + + try { + $client = new Client(); + $client->post(self::URL, [ + 'headers' => ['Accept' => 'application/json', 'User-Agent' => defined('CACHET_VERSION') ? 'cachet/'.constant('CACHET_VERSION') : 'cachet'], + 'json' => $payload, + ]); + } catch (Exception $e) { + event(new BeaconFailedToSendEvent()); + + return; + } + + event(new BeaconWasSentEvent()); + } +} diff --git a/app/Integrations/Credits.php b/app/Integrations/Core/Credits.php similarity index 85% rename from app/Integrations/Credits.php rename to app/Integrations/Core/Credits.php index a82105ccb57..e821c3b6f29 100644 --- a/app/Integrations/Credits.php +++ b/app/Integrations/Core/Credits.php @@ -9,13 +9,20 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Integrations; +namespace CachetHQ\Cachet\Integrations\Core; +use CachetHQ\Cachet\Integrations\Contracts\Credits as CreditsContract; use Exception; use GuzzleHttp\Client; use Illuminate\Contracts\Cache\Repository; -class Credits +/** + * This is the credits class. + * + * @author Graham Campbell + * @author James Brooks + */ +class Credits implements CreditsContract { /** * The default url. diff --git a/app/Integrations/Feed.php b/app/Integrations/Core/Feed.php similarity index 90% rename from app/Integrations/Feed.php rename to app/Integrations/Core/Feed.php index 033839b2708..1ab93c4d02d 100644 --- a/app/Integrations/Feed.php +++ b/app/Integrations/Core/Feed.php @@ -9,8 +9,9 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Integrations; +namespace CachetHQ\Cachet\Integrations\Core; +use CachetHQ\Cachet\Integrations\Contracts\Feed as FeedContract; use Exception; use GuzzleHttp\Client; use Illuminate\Contracts\Cache\Repository; @@ -20,14 +21,14 @@ * * @author James Brooks */ -class Feed +class Feed implements FeedContract { /** * The default url. * * @var string */ - const URL = 'https://blog.alt-three.com/tag/cachet/rss'; + const URL = 'https://alt-three.com/tag/cachet/rss'; /** * The failed status indicator. diff --git a/app/Integrations/Core/System.php b/app/Integrations/Core/System.php new file mode 100644 index 00000000000..b1f7183c1e7 --- /dev/null +++ b/app/Integrations/Core/System.php @@ -0,0 +1,143 @@ + + */ +class System implements SystemContract +{ + /** + * The illuminate config instance. + * + * @var \Illuminate\Contracts\Config\Repository + */ + protected $config; + + /** + * The illuminate guard instance. + * + * @var \Illuminate\Contracts\Auth\Guard + */ + protected $auth; + + /** + * Create a new system instance. + * + * @param \Illuminate\Contracts\Config\Repository $config + * @param \Illuminate\Contracts\Auth\Guard $auth + * + * @return void + */ + public function __construct(Repository $config, Guard $auth) + { + $this->config = $config; + $this->auth = $auth; + } + + /** + * Get the entire system status. + * + * @return array + */ + public function getStatus() + { + $includePrivate = $this->auth->check(); + + $totalComponents = Component::enabled()->authenticated($includePrivate)->count(); + $majorOutages = Component::enabled()->authenticated($includePrivate)->status(4)->count(); + $majorOutageRate = (int) $this->config->get('setting.major_outage_rate', '50'); + $isMajorOutage = $totalComponents ? ($majorOutages / $totalComponents) * 100 >= $majorOutageRate : false; + + // Default data + $status = [ + 'system_status' => 'info', + 'system_message' => trans_choice('cachet.service.bad', $totalComponents), + 'favicon' => 'favicon-high-alert', + ]; + + if ($isMajorOutage) { + $status = [ + 'system_status' => 'danger', + 'system_message' => trans_choice('cachet.service.major', $totalComponents), + 'favicon' => 'favicon-high-alert', + ]; + } elseif (Component::enabled()->authenticated($includePrivate)->notStatus(1)->count() === 0) { + // If all our components are ok, do we have any non-fixed incidents? + $incidents = Incident::orderBy('occurred_at', 'desc')->get()->filter(function ($incident) { + return $incident->status !== Incident::FIXED; + }); + $incidentCount = $incidents->count(); + $unresolvedCount = $incidents->filter(function ($incident) { + return !$incident->is_resolved; + })->count(); + + if ($incidentCount === 0 || ($incidentCount >= 1 && $unresolvedCount === 0)) { + $status = [ + 'system_status' => 'success', + 'system_message' => trans_choice('cachet.service.good', $totalComponents), + 'favicon' => 'favicon', + ]; + } + } elseif (Component::enabled()->authenticated($includePrivate)->whereIn('status', [2, 3])->count() > 0) { + $status['favicon'] = 'favicon-medium-alert'; + } + + return $status; + } + + /** + * Determine if Cachet is allowed to send notifications to users, subscribers or third party tools. + * + * @return bool + */ + public function canNotifySubscribers() + { + $maintenancePeriods = Schedule::inProgress()->count(); + if ($maintenancePeriods === 0) { + return true; + } + + return !$this->config->get('setting.suppress_notifications_in_maintenance'); + } + + /** + * Get the cachet version. + * + * @return string + */ + public function getVersion() + { + return CACHET_VERSION; + } + + /** + * Get the table prefix. + * + * @return string + */ + public function getTablePrefix() + { + $driver = $this->config->get('database.default'); + + return $this->config->get("database.connections.{$driver}.prefix"); + } +} diff --git a/app/Integrations/Releases.php b/app/Integrations/GitHub/Releases.php similarity index 88% rename from app/Integrations/Releases.php rename to app/Integrations/GitHub/Releases.php index bbb3bf9db7f..8d7935ad37b 100644 --- a/app/Integrations/Releases.php +++ b/app/Integrations/GitHub/Releases.php @@ -9,12 +9,14 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Integrations; +namespace CachetHQ\Cachet\Integrations\GitHub; +use CachetHQ\Cachet\Bus\Events\System\SystemCheckedForUpdatesEvent; +use CachetHQ\Cachet\Integrations\Contracts\Releases as ReleasesContract; use GuzzleHttp\Client; use Illuminate\Contracts\Cache\Repository; -class Releases +class Releases implements ReleasesContract { /** * The default url. @@ -81,6 +83,8 @@ public function latest() $headers['OAUTH-TOKEN'] = $this->token; } + event(new SystemCheckedForUpdatesEvent()); + return json_decode((new Client())->get($this->url, [ 'headers' => $headers, ])->getBody(), true); diff --git a/app/Models/Action.php b/app/Models/Action.php new file mode 100644 index 00000000000..be9cfcc1de6 --- /dev/null +++ b/app/Models/Action.php @@ -0,0 +1,78 @@ + + * @author James Brooks + */ +class Action extends Model +{ + use ValidatingTrait; + + /** + * The attributes that should be casted to native types. + * + * @var string[] + */ + protected $casts = [ + 'id' => 'int', + 'class_name' => 'string', + 'user_id' => 'int', + 'username' => 'string', + 'information' => 'string', + 'description' => 'string', + ]; + + /** + * A list of methods protected from mass assignment. + * + * @var string[] + */ + protected $guarded = ['_token', '_method']; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'id' => 'nullable|int|min:1', + 'class_name' => 'required|string', + 'user_id' => 'required|int|min:1', + 'username' => 'required|string', + 'information' => 'nullable|string', + 'description' => 'required|string', + ]; + + /** + * The relations to eager load on every query. + * + * @var string[] + */ + protected $with = ['user']; + + /** + * Get the user relation. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function user() + { + return $this->belongsTo(User::class); + } +} diff --git a/app/Models/Component.php b/app/Models/Component.php index a07d052dcb2..08da7157662 100644 --- a/app/Models/Component.php +++ b/app/Models/Component.php @@ -12,6 +12,8 @@ namespace CachetHQ\Cachet\Models; use AltThree\Validator\ValidatingTrait; +use CachetHQ\Cachet\Models\Traits\HasMeta; +use CachetHQ\Cachet\Models\Traits\HasTags; use CachetHQ\Cachet\Models\Traits\SearchableTrait; use CachetHQ\Cachet\Models\Traits\SortableTrait; use CachetHQ\Cachet\Presenters\ComponentPresenter; @@ -22,7 +24,12 @@ class Component extends Model implements HasPresenter { - use SearchableTrait, SoftDeletes, SortableTrait, ValidatingTrait; + use HasTags; + use HasMeta; + use SearchableTrait; + use SoftDeletes; + use SortableTrait; + use ValidatingTrait; /** * List of attributes that have default values. @@ -35,6 +42,7 @@ class Component extends Model implements HasPresenter 'description' => '', 'link' => '', 'enabled' => true, + 'meta' => null, ]; /** @@ -43,12 +51,15 @@ class Component extends Model implements HasPresenter * @var string[] */ protected $casts = [ - 'order' => 'int', - 'group_id' => 'int', + 'name' => 'string', 'description' => 'string', + 'status' => 'int', + 'order' => 'int', 'link' => 'string', - 'deleted_at' => 'date', + 'group_id' => 'int', 'enabled' => 'bool', + 'meta' => 'json', + 'deleted_at' => 'date', ]; /** @@ -60,11 +71,11 @@ class Component extends Model implements HasPresenter 'name', 'description', 'status', - 'tags', 'link', 'order', 'group_id', 'enabled', + 'meta', ]; /** @@ -73,9 +84,12 @@ class Component extends Model implements HasPresenter * @var string[] */ public $rules = [ - 'name' => 'required|string', - 'status' => 'int|required', - 'link' => 'url', + 'name' => 'required|string', + 'status' => 'required|int', + 'order' => 'nullable|int', + 'group_id' => 'nullable|int', + 'link' => 'nullable|url', + 'enabled' => 'required|bool', ]; /** @@ -107,7 +121,7 @@ class Component extends Model implements HasPresenter ]; /** - * Components can belong to a group. + * Get the group relation. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ @@ -117,7 +131,7 @@ public function group() } /** - * Lookup all of the incidents reported on the component. + * Get the incidents relation. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ @@ -126,16 +140,6 @@ public function incidents() return $this->hasMany(Incident::class, 'component_id', 'id'); } - /** - * Components can have many tags. - * - * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany - */ - public function tags() - { - return $this->belongsToMany(Tag::class); - } - /** * Finds all components by status. * @@ -146,7 +150,7 @@ public function tags() */ public function scopeStatus(Builder $query, $status) { - return $query->where('status', $status); + return $query->where('status', '=', $status); } /** @@ -171,7 +175,24 @@ public function scopeNotStatus(Builder $query, $status) */ public function scopeEnabled(Builder $query) { - return $query->where('enabled', true); + return $query->where('enabled', '=', true); + } + + /** + * Find all components which are within visible groups. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param bool $authenticated + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeAuthenticated(Builder $query, $authenticated) + { + return $query->when(!$authenticated, function (Builder $query) { + return $query->whereDoesntHave('group', function (Builder $query) { + $query->where('visible', ComponentGroup::VISIBLE_AUTHENTICATED); + }); + }); } /** @@ -183,21 +204,36 @@ public function scopeEnabled(Builder $query) */ public function scopeDisabled(Builder $query) { - return $query->where('enabled', false); + return $query->where('enabled', '=', false); } /** - * Returns all of the tags on this component. + * Finds all ungrouped components. * - * @return string + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder */ - public function getTagsListAttribute() + public function scopeUngrouped(Builder $query) { - $tags = $this->tags->map(function ($tag) { - return $tag->name; - }); + return $query->enabled() + ->where('group_id', '=', 0) + ->orderBy('order') + ->orderBy('created_at'); + } - return implode(', ', $tags->toArray()); + /** + * Finds all grouped components. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeGrouped(Builder $query) + { + return $query->enabled() + ->where('group_id', '>', 0) + ->groupBy('group_id'); } /** diff --git a/app/Models/ComponentGroup.php b/app/Models/ComponentGroup.php index b9a3603d92b..f5a8af8ded5 100644 --- a/app/Models/ComponentGroup.php +++ b/app/Models/ComponentGroup.php @@ -15,12 +15,34 @@ use CachetHQ\Cachet\Models\Traits\SearchableTrait; use CachetHQ\Cachet\Models\Traits\SortableTrait; use CachetHQ\Cachet\Presenters\ComponentGroupPresenter; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Collection; use McCool\LaravelAutoPresenter\HasPresenter; +/** + * This is the component group model class. + * + * @author James Brooks + */ class ComponentGroup extends Model implements HasPresenter { - use SearchableTrait, SortableTrait, ValidatingTrait; + use SearchableTrait; + use SortableTrait; + use ValidatingTrait; + /** + * Viewable only authenticated users. + * + * @var int + */ + const VISIBLE_AUTHENTICATED = 0; + + /** + * Viewable by public. + * + * @var int + */ + const VISIBLE_GUEST = 1; /** * The model's attributes. @@ -30,6 +52,7 @@ class ComponentGroup extends Model implements HasPresenter protected $attributes = [ 'order' => 0, 'collapsed' => 0, + 'visible' => 0, ]; /** @@ -41,6 +64,7 @@ class ComponentGroup extends Model implements HasPresenter 'name' => 'string', 'order' => 'int', 'collapsed' => 'int', + 'visible' => 'int', ]; /** @@ -48,7 +72,7 @@ class ComponentGroup extends Model implements HasPresenter * * @var string[] */ - protected $fillable = ['name', 'order', 'collapsed']; + protected $fillable = ['name', 'order', 'collapsed', 'visible']; /** * The validation rules. @@ -57,8 +81,9 @@ class ComponentGroup extends Model implements HasPresenter */ public $rules = [ 'name' => 'required|string', - 'order' => 'int', - 'collapsed' => 'int', + 'order' => 'required|int', + 'collapsed' => 'required|int|between:0,4', + 'visible' => 'required|bool', ]; /** @@ -71,6 +96,7 @@ class ComponentGroup extends Model implements HasPresenter 'name', 'order', 'collapsed', + 'visible', ]; /** @@ -83,6 +109,7 @@ class ComponentGroup extends Model implements HasPresenter 'name', 'order', 'collapsed', + 'visible', ]; /** @@ -93,13 +120,13 @@ class ComponentGroup extends Model implements HasPresenter protected $with = ['enabled_components', 'enabled_components_lowest']; /** - * A group can have many components. + * Get the components relation. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function components() { - return $this->hasMany(Component::class, 'group_id', 'id')->orderBy('order'); + return $this->hasMany(Component::class, 'group_id', 'id'); } /** @@ -119,7 +146,7 @@ public function incidents() */ public function enabled_components() { - return $this->components()->enabled(); + return $this->components()->enabled()->orderBy('order'); } /** @@ -141,4 +168,30 @@ public function getPresenterClass() { return ComponentGroupPresenter::class; } + + /** + * Finds all component groups which are visible to public. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeVisible(Builder $query) + { + return $query->where('visible', '=', self::VISIBLE_GUEST); + } + + /** + * Finds all used component groups. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @param \Illuminate\Support\Collection $usedComponentGroups + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeUsed(Builder $query, Collection $usedComponentGroups) + { + return $query->whereIn('id', $usedComponentGroups) + ->orderBy('order'); + } } diff --git a/app/Models/Incident.php b/app/Models/Incident.php index 9ea702b575e..b1ddb58c06a 100644 --- a/app/Models/Incident.php +++ b/app/Models/Incident.php @@ -12,18 +12,78 @@ namespace CachetHQ\Cachet\Models; use AltThree\Validator\ValidatingTrait; +use CachetHQ\Cachet\Models\Traits\HasMeta; +use CachetHQ\Cachet\Models\Traits\HasTags; use CachetHQ\Cachet\Models\Traits\SearchableTrait; use CachetHQ\Cachet\Models\Traits\SortableTrait; use CachetHQ\Cachet\Presenters\IncidentPresenter; -use Carbon\Carbon; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use McCool\LaravelAutoPresenter\HasPresenter; +/** + * This is the incident model. + * + * @author James Brooks + * @author Joseph Cohen + * @author Graham Campbell + */ class Incident extends Model implements HasPresenter { - use SearchableTrait, SoftDeletes, SortableTrait, ValidatingTrait; + use HasMeta; + use HasTags; + use SearchableTrait; + use SoftDeletes; + use SortableTrait; + use ValidatingTrait; + + /** + * Status for incident being investigated. + * + * @var int + */ + const INVESTIGATING = 1; + + /** + * Status for incident having been identified. + * + * @var int + */ + const IDENTIFIED = 2; + + /** + * Status for incident being watched. + * + * @var int + */ + const WATCHED = 3; + + /** + * Status for incident now being fixed. + * + * @var int + */ + const FIXED = 4; + + /** + * The accessors to append to the model's array form. + * + * @var string[] + */ + protected $appends = [ + 'is_resolved', + ]; + + /** + * The model's attributes. + * + * @var string[] + */ + protected $attributes = [ + 'stickied' => false, + 'notifications' => false, + ]; /** * The attributes that should be casted to native types. @@ -31,9 +91,14 @@ class Incident extends Model implements HasPresenter * @var string[] */ protected $casts = [ - 'visible' => 'int', - 'scheduled_at' => 'date', - 'deleted_at' => 'date', + 'component_id' => 'int', + 'status' => 'int', + 'user_id' => 'int', + 'visible' => 'int', + 'stickied' => 'bool', + 'notifications' => 'bool', + 'occurred_at' => 'datetime', + 'deleted_at' => 'date', ]; /** @@ -42,12 +107,15 @@ class Incident extends Model implements HasPresenter * @var string[] */ protected $fillable = [ + 'user_id', 'component_id', 'name', 'status', 'visible', + 'stickied', + 'notifications', 'message', - 'scheduled_at', + 'occurred_at', 'created_at', 'updated_at', ]; @@ -58,11 +126,14 @@ class Incident extends Model implements HasPresenter * @var string[] */ public $rules = [ - 'component_id' => 'int', - 'name' => 'required', - 'status' => 'required|int', - 'visible' => 'required|bool', - 'message' => 'required', + 'user_id' => 'nullable|int', + 'component_id' => 'nullable|int', + 'name' => 'required|string', + 'status' => 'required|int', + 'visible' => 'required|bool', + 'stickied' => 'required|bool', + 'notifications' => 'nullable|bool', + 'message' => 'required|string', ]; /** @@ -72,10 +143,12 @@ class Incident extends Model implements HasPresenter */ protected $searchable = [ 'id', + 'user_id', 'component_id', 'name', 'status', 'visible', + 'stickied', ]; /** @@ -85,70 +158,91 @@ class Incident extends Model implements HasPresenter */ protected $sortable = [ 'id', + 'user_id', 'name', 'status', 'visible', + 'stickied', 'message', + 'occurred_at', ]; /** - * Finds all visible incidents. + * The relations to eager load on every query. * - * @param \Illuminate\Database\Eloquent\Builder $query + * @var string[] + */ + protected $with = [ + 'meta', + 'updates', + ]; + + /** + * Get the component relation. * - * @return \Illuminate\Database\Eloquent\Builder + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ - public function scopeVisible(Builder $query) + public function component() { - return $query->where('visible', 1); + return $this->belongsTo(Component::class, 'component_id', 'id'); } /** - * Finds all scheduled incidents (maintenance). + * Get the updates relation. * - * @param \Illuminate\Database\Eloquent\Builder $query + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function updates() + { + return $this->hasMany(IncidentUpdate::class)->orderBy('created_at', 'desc'); + } + + /** + * Get the user relation. * - * @return \Illuminate\Database\Eloquent\Builder + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ - public function scopeScheduled(Builder $query) + public function user() { - return $query->where('status', 0)->where('scheduled_at', '>=', Carbon::now()->toDateTimeString()); + return $this->belongsTo(User::class); } /** - * Finds all non-scheduled incidents. + * Finds all visible incidents. * * @param \Illuminate\Database\Eloquent\Builder $query * * @return \Illuminate\Database\Eloquent\Builder */ - public function scopeNotScheduled(Builder $query) + public function scopeVisible(Builder $query) { - return $query->where('status', '>', 0)->orWhere(function ($query) { - $query->where('status', 0)->where(function ($query) { - $query->whereNull('scheduled_at')->orWhere('scheduled_at', '<=', Carbon::now()->toDateTimeString()); - }); - }); + return $query->where('visible', '=', 1); } /** - * An incident belongs to a component. + * Finds all stickied incidents. * - * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder */ - public function component() + public function scopeStickied(Builder $query) { - return $this->belongsTo(Component::class, 'component_id', 'id'); + return $query->where('stickied', '=', true); } /** - * Returns whether the "incident" is scheduled or not. + * Is the incident resolved? * * @return bool */ - public function getIsScheduledAttribute() + public function getIsResolvedAttribute() { - return $this->getOriginal('scheduled_at') !== null; + if ($updates = $this->updates->first()) { + return (int) $updates->status === self::FIXED; + } + + return (int) $this->status === self::FIXED; } /** diff --git a/app/Models/IncidentComponent.php b/app/Models/IncidentComponent.php new file mode 100644 index 00000000000..13218d15206 --- /dev/null +++ b/app/Models/IncidentComponent.php @@ -0,0 +1,78 @@ + + */ +class IncidentComponent extends Model +{ + use ValidatingTrait; + + /** + * The attributes that should be casted to native types. + * + * @var string[] + */ + protected $casts = [ + 'incident_id' => 'int', + 'component_id' => 'int', + 'status_id' => 'int', + ]; + + /** + * The fillable properties. + * + * @var string[] + */ + protected $fillable = [ + 'incident_id', + 'component_id', + 'status_id', + ]; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'incident_id' => 'required|int', + 'component_id' => 'required|int', + 'status_id' => 'required|int', + ]; + + /** + * Get the incident relation. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function incident() + { + return $this->belongsTo(Incident::class); + } + + /** + * Get the component relation. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function component() + { + return $this->belongsTo(Component::class); + } +} diff --git a/app/Models/IncidentTemplate.php b/app/Models/IncidentTemplate.php index c93b87543d1..88b833d3bd1 100644 --- a/app/Models/IncidentTemplate.php +++ b/app/Models/IncidentTemplate.php @@ -26,6 +26,7 @@ class IncidentTemplate extends Model */ protected $casts = [ 'name' => 'string', + 'slug' => 'string', 'template' => 'string', ]; @@ -34,7 +35,7 @@ class IncidentTemplate extends Model * * @var string[] */ - protected $fillable = ['name', 'template']; + protected $fillable = ['name', 'slug', 'template']; /** * The validation rules. @@ -42,32 +43,38 @@ class IncidentTemplate extends Model * @var string[] */ public $rules = [ - 'name' => 'required', - 'template' => 'required', + 'name' => 'required|string', + 'template' => 'required|string', ]; /** * Overrides the models boot method. + * + * @return void */ public static function boot() { parent::boot(); self::saving(function ($template) { - $template->slug = Str::slug($template->name); + if (!$template->slug) { + $template->slug = Str::slug($template->name); + } }); } /** * Finds a template by the slug. * - * @param \Illuminate\Database\Query\Builder $query - * @param string $slug + * @param string $slug + * @param string[] $columns * * @return \Illuminate\Database\Query\Builder */ - public function scopeForSlug($query, $slug) + public static function forSlug($slug, $columns = ['*']) { - return $query->where('slug', $slug); + $template = static::where('slug', '=', $slug)->firstOrFail($columns); + + return $template; } } diff --git a/app/Models/IncidentUpdate.php b/app/Models/IncidentUpdate.php new file mode 100644 index 00000000000..0591a248562 --- /dev/null +++ b/app/Models/IncidentUpdate.php @@ -0,0 +1,106 @@ + + */ +class IncidentUpdate extends Model implements HasPresenter +{ + use SortableTrait; + use ValidatingTrait; + + /** + * The attributes that should be casted to native types. + * + * @var string[] + */ + protected $casts = [ + 'incident_id' => 'int', + 'status' => 'int', + 'message' => 'string', + 'user_id' => 'int', + ]; + + /** + * The fillable properties. + * + * @var string[] + */ + protected $fillable = [ + 'incident_id', + 'status', + 'message', + 'user_id', + ]; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'incident_id' => 'required|int', + 'status' => 'required|int', + 'message' => 'required|string', + 'user_id' => 'required|int', + ]; + + /** + * The sortable fields. + * + * @var string[] + */ + protected $sortable = [ + 'id', + 'status', + 'user_id', + ]; + + /** + * Get the incident relation. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function incident() + { + return $this->belongsTo(Incident::class); + } + + /** + * Get the user relation. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function user() + { + return $this->belongsTo(User::class); + } + + /** + * Get the presenter class. + * + * @return string + */ + public function getPresenterClass() + { + return IncidentUpdatePresenter::class; + } +} diff --git a/app/Models/Invite.php b/app/Models/Invite.php index a77bb4848e6..292735c5849 100644 --- a/app/Models/Invite.php +++ b/app/Models/Invite.php @@ -12,9 +12,19 @@ namespace CachetHQ\Cachet\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Notifications\Notifiable; +use Illuminate\Support\Str; +/** + * This is the invite class. + * + * @author Joseph Cohen + * @author James Brooks + */ class Invite extends Model { + use Notifiable; + /** * The attributes that should be casted to native types. * @@ -33,6 +43,8 @@ class Invite extends Model /** * Overrides the models boot method. + * + * @return void */ public static function boot() { @@ -40,21 +52,11 @@ public static function boot() self::creating(function ($invite) { if (!$invite->code) { - $invite->code = self::generateInviteCode(); + $invite->code = Str::random(20); } }); } - /** - * Returns an invite code. - * - * @return string - */ - public static function generateInviteCode() - { - return str_random(20); - } - /** * Determines if the invite was claimed. * diff --git a/app/Models/Meta.php b/app/Models/Meta.php new file mode 100644 index 00000000000..6c391d200ee --- /dev/null +++ b/app/Models/Meta.php @@ -0,0 +1,80 @@ + + */ +class Meta extends Model +{ + use ValidatingTrait; + + /** + * The attributes that should be casted to native types. + * + * @var string[] + */ + protected $casts = [ + 'id' => 'int', + 'key' => 'string', + 'value' => 'json', + 'meta_id' => 'int', + 'meta_type' => 'string', + ]; + + /** + * The fillable properties. + * + * @var string[] + */ + protected $fillable = [ + 'key', + 'value', + 'meta_id', + 'meta_type', + ]; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'id' => 'nullable|int|min:1', + 'key' => 'required|string', + 'value' => 'nullable', + 'meta_id' => 'required|int', + 'meta_type' => 'required|string', + ]; + + /** + * The table associated with the model. + * + * @var string + */ + protected $table = 'meta'; + + /** + * Get all of the owning meta models. + * + * @return \Illuminate\Database\Eloquent\Relations\MorphTo + */ + public function meta() + { + return $this->morphTo(); + } +} diff --git a/app/Models/Metric.php b/app/Models/Metric.php index 3ef826f368a..c3e6483ecfb 100644 --- a/app/Models/Metric.php +++ b/app/Models/Metric.php @@ -12,15 +12,20 @@ namespace CachetHQ\Cachet\Models; use AltThree\Validator\ValidatingTrait; +use AltThree\Validator\ValidationException; +use CachetHQ\Cachet\Models\Traits\HasMeta; use CachetHQ\Cachet\Models\Traits\SortableTrait; use CachetHQ\Cachet\Presenters\MetricPresenter; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\MessageBag; use McCool\LaravelAutoPresenter\HasPresenter; class Metric extends Model implements HasPresenter { - use SortableTrait, ValidatingTrait; + use HasMeta; + use SortableTrait; + use ValidatingTrait; /** * The calculation type of sum. @@ -36,6 +41,27 @@ class Metric extends Model implements HasPresenter */ const CALC_AVG = 1; + /** + * Viewable only authenticated users. + * + * @var int + */ + const VISIBLE_AUTHENTICATED = 0; + + /** + * Viewable by public. + * + * @var int + */ + const VISIBLE_GUEST = 1; + + /** + * Viewable by nobody. + * + * @var int + */ + const VISIBLE_HIDDEN = 2; + /** * The model's attributes. * @@ -50,6 +76,7 @@ class Metric extends Model implements HasPresenter 'default_view' => 1, 'threshold' => 5, 'order' => 0, + 'visible' => 1, ]; /** @@ -66,6 +93,7 @@ class Metric extends Model implements HasPresenter 'default_view' => 'int', 'threshold' => 'int', 'order' => 'int', + 'visible' => 'int', ]; /** @@ -84,6 +112,7 @@ class Metric extends Model implements HasPresenter 'default_view', 'threshold', 'order', + 'visible', ]; /** @@ -94,12 +123,11 @@ class Metric extends Model implements HasPresenter public $rules = [ 'name' => 'required', 'suffix' => 'required', - 'display_chart' => 'bool', - 'default_value' => 'numeric', - 'places' => 'numeric|between:0,4', - 'default_view' => 'numeric|between:0,3', - 'threshold' => 'numeric|between:0,10', - 'threshold' => 'int', + 'display_chart' => 'required|bool', + 'default_value' => 'required|numeric', + 'places' => 'required|numeric|between:0,4', + 'default_view' => 'required|numeric|between:0,3', + 'visible' => 'required|numeric|between:0,2', ]; /** @@ -114,16 +142,32 @@ class Metric extends Model implements HasPresenter 'default_value', 'calc_type', 'order', + 'visible', ]; /** - * Metrics contain many metric points. + * Overrides the models boot method. + * + * @return void + */ + public static function boot() + { + parent::boot(); + + // When deleting a metric, delete the points too. + self::deleting(function ($model) { + $model->points()->delete(); + }); + } + + /** + * Get the points relation. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function points() { - return $this->hasMany(MetricPoint::class, 'metric_id', 'id'); + return $this->hasMany(MetricPoint::class, 'metric_id', 'id')->latest(); } /** @@ -135,7 +179,19 @@ public function points() */ public function scopeDisplayable(Builder $query) { - return $query->where('display_chart', 1); + return $query->where('display_chart', '=', true)->where('visible', '<>', self::VISIBLE_HIDDEN); + } + + /** + * Finds all metrics which are visible to public. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeVisible(Builder $query) + { + return $query->where('visible', '=', self::VISIBLE_GUEST); } /** @@ -145,7 +201,27 @@ public function scopeDisplayable(Builder $query) */ public function getShouldDisplayAttribute() { - return $this->display_chart === 1; + return $this->display_chart; + } + + /** + * Validate the model before save. + * + * @throws \AltThree\Validator\ValidationException + * + * @return void + */ + public function validate() + { + $messages = []; + + if (60 % $this->threshold !== 0) { + $messages[] = 'Threshold must divide by 60.'; + } + + if ($messages) { + throw new ValidationException(new MessageBag($messages)); + } } /** diff --git a/app/Models/MetricPoint.php b/app/Models/MetricPoint.php index fadaae07224..6e64940036a 100644 --- a/app/Models/MetricPoint.php +++ b/app/Models/MetricPoint.php @@ -13,13 +13,31 @@ use AltThree\Validator\ValidatingTrait; use CachetHQ\Cachet\Presenters\MetricPointPresenter; +use Carbon\Carbon; +use DateTime; use Illuminate\Database\Eloquent\Model; use McCool\LaravelAutoPresenter\HasPresenter; +/** + * This is the metric point model class. + * + * @author James Brooks + * @author Joseph Cohen + * @author Graham Campbell + */ class MetricPoint extends Model implements HasPresenter { use ValidatingTrait; + /** + * The accessors to append to the model's array form. + * + * @var string[] + */ + protected $appends = [ + 'calculated_value', + ]; + /** * The model's attributes. * @@ -59,11 +77,11 @@ class MetricPoint extends Model implements HasPresenter * @var string[] */ public $rules = [ - 'value' => 'numeric|required', + 'value' => 'required|numeric', ]; /** - * A metric point belongs to a metric unit. + * Get the metric relation. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ @@ -73,21 +91,40 @@ public function metric() } /** - * Override the value attribute. + * Show the actual calculated value; as per (value * counter). * - * @param mixed $value + * @return int + */ + public function getCalculatedValueAttribute() + { + return $this->value * $this->counter; + } + + /** + * Round the created at value into intervals of 30 seconds. * - * @return float + * @param string $createdAt + * + * @return string|void */ - public function getActiveValueAttribute($value) + public function setCreatedAtAttribute($createdAt) { - if ($this->metric->calc_type === Metric::CALC_SUM) { - return round((float) $value * $this->counter, $this->metric->places); - } elseif ($this->metric->calc_type === Metric::CALC_AVG) { - return round((float) $value * $this->counter, $this->metric->places); + if (!$createdAt) { + return; } - return round((float) $value, $this->metric->places); + if (!$createdAt instanceof DateTime) { + $createdAt = Carbon::parse($createdAt); + } + + $timestamp = $createdAt->format('U'); + $timestamp = 30 * round($timestamp / 30); + + $date = Carbon::createFromFormat('U', $timestamp)->toDateTimeString(); + + $this->attributes['created_at'] = $date; + + return $date; } /** diff --git a/app/Models/Schedule.php b/app/Models/Schedule.php new file mode 100644 index 00000000000..93a7e3bbdf0 --- /dev/null +++ b/app/Models/Schedule.php @@ -0,0 +1,219 @@ + self::UPCOMING, + 'completed_at' => null, + ]; + + /** + * The attributes that should be casted to native types. + * + * @var string[] + */ + protected $casts = [ + 'name' => 'string', + 'message' => 'string', + 'status' => 'int', + 'scheduled_at' => 'datetime', + 'completed_at' => 'datetime', + ]; + + /** + * The fillable properties. + * + * @var string[] + */ + protected $fillable = [ + 'name', + 'message', + 'status', + 'scheduled_at', + 'completed_at', + 'created_at', + 'updated_at', + ]; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'name' => 'required|string', + 'message' => 'nullable|string', + 'status' => 'required|int|between:0,2', + ]; + + /** + * The searchable fields. + * + * @var string[] + */ + protected $searchable = [ + 'id', + 'name', + 'status', + ]; + + /** + * The sortable fields. + * + * @var string[] + */ + protected $sortable = [ + 'id', + 'name', + 'status', + 'scheduled_at', + 'completed_at', + 'created_at', + 'updated_at', + ]; + + /** + * The relations to eager load on every query. + * + * @var string[] + */ + protected $with = ['components']; + + /** + * Get the components relation. + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function components() + { + return $this->hasMany(ScheduleComponent::class); + } + + /** + * Scope schedules that are uncompleted. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeUncompleted(Builder $query) + { + return $query->whereIn('status', [self::UPCOMING, self::IN_PROGRESS])->where(function (Builder $query) { + return $query->whereNull('completed_at'); + }); + } + + /** + * Scope schedules that are in progress. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeInProgress(Builder $query) + { + return $query->where('scheduled_at', '<=', Carbon::now())->where('status', '<>', self::COMPLETE)->where(function ($query) { + $query->whereNull('completed_at'); + }); + } + + /** + * Scopes schedules to those in the future. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeScheduledInFuture($query) + { + return $query->whereIn('status', [self::UPCOMING, self::IN_PROGRESS])->where('scheduled_at', '>=', Carbon::now()); + } + + /** + * Scopes schedules to those scheduled in the past. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeScheduledInPast($query) + { + return $query->whereIn('status', [self::UPCOMING, self::IN_PROGRESS])->where('scheduled_at', '<=', Carbon::now()); + } + + /** + * Scopes schedules to those completed in the past. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeCompletedInPast($query) + { + return $query->where('status', '=', self::COMPLETE)->where('completed_at', '<=', Carbon::now()); + } + + /** + * Get the presenter class. + * + * @return string + */ + public function getPresenterClass() + { + return SchedulePresenter::class; + } +} diff --git a/app/Models/ScheduleComponent.php b/app/Models/ScheduleComponent.php new file mode 100644 index 00000000000..a77abcd2781 --- /dev/null +++ b/app/Models/ScheduleComponent.php @@ -0,0 +1,73 @@ + 'int', + 'component_id' => 'int', + 'component_status' => 'int', + ]; + + /** + * The fillable properties. + * + * @var string[] + */ + protected $fillable = [ + 'schedule_id', + 'component_id', + 'component_status', + ]; + + /** + * The validation rules. + * + * @var string[] + */ + public $rules = [ + 'schedule_id' => 'required|int', + 'component_id' => 'required|int', + 'component_status' => 'required|int', + ]; + + /** + * Get the schedule relation. + * + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function schedule() + { + return $this->belongsTo(Schedule::class); + } + + /** + * Get the component relation. + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function component() + { + return $this->hasOne(Component::class); + } +} diff --git a/app/Models/Setting.php b/app/Models/Setting.php index 0ea02148e12..54ea2b77a13 100644 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -15,6 +15,13 @@ class Setting extends Model { + /** + * List of attributes that have default values. + * + * @var string[] + */ + protected $attributes = ['value' => '']; + /** * The attributes that should be casted to native types. * @@ -31,11 +38,4 @@ class Setting extends Model * @var string[] */ protected $fillable = ['name', 'value']; - - /** - * List of attributes that have default values. - * - * @var string[] - */ - protected $attributes = ['value' => '']; } diff --git a/app/Models/Subscriber.php b/app/Models/Subscriber.php index f5789e3d3b7..e10a093b16a 100644 --- a/app/Models/Subscriber.php +++ b/app/Models/Subscriber.php @@ -12,13 +12,25 @@ namespace CachetHQ\Cachet\Models; use AltThree\Validator\ValidatingTrait; +use CachetHQ\Cachet\Models\Traits\HasMeta; use CachetHQ\Cachet\Presenters\SubscriberPresenter; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; +use Illuminate\Notifications\Notifiable; +use Illuminate\Support\Str; use McCool\LaravelAutoPresenter\HasPresenter; +/** + * This is the subscriber model. + * + * @author Joseph Cohen + * @author James Brooks + * @author Graham Campbell + */ class Subscriber extends Model implements HasPresenter { + use HasMeta; + use Notifiable; use ValidatingTrait; /** @@ -27,10 +39,12 @@ class Subscriber extends Model implements HasPresenter * @var string[] */ protected $casts = [ - 'email' => 'string', - 'verify_code' => 'string', - 'verified_at' => 'date', - 'global' => 'bool', + 'email' => 'string', + 'phone_number' => 'string', + 'slack_webhook_url' => 'string', + 'verify_code' => 'string', + 'verified_at' => 'date', + 'global' => 'bool', ]; /** @@ -38,7 +52,13 @@ class Subscriber extends Model implements HasPresenter * * @var string[] */ - protected $fillable = ['email']; + protected $fillable = [ + 'email', + 'phone_number', + 'slack_webhook_url', + 'verified_at', + 'global', + ]; /** * The validation rules. @@ -46,7 +66,9 @@ class Subscriber extends Model implements HasPresenter * @var string[] */ public $rules = [ - 'email' => 'required|email', + 'email' => 'nullable|email', + 'phone_number' => 'nullable|string', + 'slack_webhook_url' => 'nullable|url', ]; /** @@ -58,6 +80,8 @@ class Subscriber extends Model implements HasPresenter /** * Overrides the models boot method. + * + * @return void */ public static function boot() { @@ -71,7 +95,7 @@ public static function boot() } /** - * A subscriber has many subscriptions. + * Get the subscriptions relation. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ @@ -101,7 +125,7 @@ public function scopeIsVerified(Builder $query) */ public function scopeIsGlobal(Builder $query) { - return $query->where('global', true); + return $query->where('global', '=', true); } /** @@ -116,7 +140,7 @@ public function scopeForComponent(Builder $query, $component_id) { return $query->select('subscribers.*') ->join('subscriptions', 'subscribers.id', '=', 'subscriptions.subscriber_id') - ->where('subscriptions.component_id', $component_id); + ->where('subscriptions.component_id', '=', $component_id); } /** @@ -136,7 +160,27 @@ public function getIsVerifiedAttribute() */ public static function generateVerifyCode() { - return str_random(42); + return Str::random(42); + } + + /** + * Route notifications for the Nexmo channel. + * + * @return string + */ + public function routeNotificationForNexmo() + { + return $this->phone_number; + } + + /** + * Route notifications for the Slack channel. + * + * @return string + */ + public function routeNotificationForSlack() + { + return $this->slack_webhook_url; } /** diff --git a/app/Models/Subscription.php b/app/Models/Subscription.php index 3a1396c7a22..c878c3c2add 100644 --- a/app/Models/Subscription.php +++ b/app/Models/Subscription.php @@ -45,12 +45,12 @@ class Subscription extends Model * @var string[] */ public $rules = [ - 'subscriber_id' => 'int|required', - 'component_id' => 'int', + 'subscriber_id' => 'required|int', + 'component_id' => 'nullable|int', ]; /** - * A subscription belongs to a subscriber. + * Get the subscriber relation. * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ @@ -60,7 +60,7 @@ public function subscriber() } /** - * A subscription has one component. + * Get the component relation. * * @return \Illuminate\Database\Eloquent\Relations\HasOne */ @@ -79,7 +79,7 @@ public function component() */ public function scopeForSubscriber(Builder $query, $subscriber_id) { - return $query->where('subscriber_id', $subscriber_id); + return $query->where('subscriber_id', '=', $subscriber_id); } /** @@ -92,7 +92,7 @@ public function scopeForSubscriber(Builder $query, $subscriber_id) */ public function scopeForComponent(Builder $query, $component_id) { - return $query->where('component_id', $component_id); + return $query->where('component_id', '=', $component_id); } /** @@ -108,7 +108,7 @@ public function scopeIsVerifiedForComponent(Builder $query, $component_id) return $query->select('subscriptions.*') ->join('subscribers', 'subscriptions.subscriber_id', '=', 'subscribers.id') ->where(function ($query) { - $query->where('subscriptions.component_id', $component_id) + $query->where('subscriptions.component_id', '=', $component_id) ->orWhere('subscribers.global'); }) ->whereNotNull('subscribers.verified_at'); diff --git a/app/Models/Tag.php b/app/Models/Tag.php index 9e64f096b38..022ceb8c528 100644 --- a/app/Models/Tag.php +++ b/app/Models/Tag.php @@ -34,6 +34,8 @@ class Tag extends Model /** * Overrides the models boot method. + * + * @return void */ public static function boot() { @@ -45,7 +47,7 @@ public static function boot() } /** - * Tags can have many components. + * Get the components relation. * * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany */ @@ -53,4 +55,31 @@ public function components() { return $this->belongsToMany(Component::class); } + + /** + * @param array|\ArrayAccess $values + * + * @return \CachetHQ\Cachet\Models\Tag|static + */ + public static function findOrCreate($values) + { + $tags = collect($values)->map(function ($value) { + if ($value instanceof self) { + return $value; + } + + $tag = static::where('name', '=', $value)->first(); + + if (!$tag instanceof self) { + $tag = static::create([ + 'name' => $value, + 'slug' => Str::slug($value), + ]); + } + + return $tag; + }); + + return is_string($values) ? $tags->first() : $tags; + } } diff --git a/app/Models/Traits/HasMeta.php b/app/Models/Traits/HasMeta.php new file mode 100644 index 00000000000..3571cf0a7e6 --- /dev/null +++ b/app/Models/Traits/HasMeta.php @@ -0,0 +1,32 @@ + + */ +trait HasMeta +{ + /** + * Get the meta relation. + * + * @return \Illuminate\Database\Eloquent\Relations\MorphMany + */ + public function meta() + { + return $this->morphMany(Meta::class, 'meta'); + } +} diff --git a/app/Models/Traits/HasTags.php b/app/Models/Traits/HasTags.php new file mode 100644 index 00000000000..b707e050ff7 --- /dev/null +++ b/app/Models/Traits/HasTags.php @@ -0,0 +1,196 @@ + + */ +trait HasTags +{ + /** + * @var array + */ + protected $queuedTags = []; + + /** + * Boot the trait. + * + * @return void + */ + public static function bootHasTags() + { + static::created(function (Model $taggableModel) { + if (count($taggableModel->queuedTags) > 0) { + $taggableModel->attachTags($taggableModel->queuedTags); + + $taggableModel->queuedTags = []; + } + }); + + static::deleted(function (Model $deletedModel) { + $tags = $deletedModel->tags()->get(); + + $deletedModel->detachTags($tags); + }); + } + + /** + * Get the tags relation. + * + * @return \Illuminate\Database\Eloquent\Relations\MorphToMany + */ + public function tags() + { + return $this->morphToMany(Tag::class, 'taggable'); + } + + /** + * @param string|array|\ArrayAccess|\CachetHQ\Cachet\Models\Tag $tags + */ + public function setTagsAttribute($tags) + { + if (!$this->exists) { + $this->queuedTags = $tags; + + return; + } + + $this->attachTags($tags); + } + + /** + * @param \Illuminate\Database\Eloquent\Builder $query + * @param array|\ArrayAccess $tags + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeWithAllTags(Builder $query, $tags) + { + $tags = static::convertToTags($tags); + + $tags->each(function ($tag) use ($query) { + $query->whereHas('tags', function (Builder $query) use ($tag) { + return $query->where('tags.id', $tag ? $tag->id : 0); + }); + }); + + return $query; + } + + /** + * @param \Illuminate\Database\Eloquent\Builder $query + * @param array|\ArrayAccess $tags + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeWithAnyTags(Builder $query, $tags) + { + $tags = static::convertToTags($tags); + + return $query->whereHas('tags', function (Builder $query) use ($tags) { + $tagIds = collect($tags)->pluck('id'); + + $query->whereIn('tags.id', $tagIds); + }); + } + + /** + * @param array|\ArrayAccess|\CachetHQ\Cachet\Models\Tag $tags + * + * @return $this + */ + public function attachTags($tags) + { + $tags = collect(Tag::findOrCreate($tags)); + + $this->tags()->syncWithoutDetaching($tags->pluck('id')->toArray()); + + return $this; + } + + /** + * @param string|\CachetHQ\Cachet\Models\Tag $tag + * + * @return $this + */ + public function attachTag($tag) + { + return $this->attachTags([$tag]); + } + + /** + * @param array|\ArrayAccess $tags + * + * @return $this + */ + public function detachTags($tags) + { + $tags = static::convertToTags($tags); + + collect($tags) + ->filter() + ->each(function (Tag $tag) { + $this->tags()->detach($tag); + }); + + return $this; + } + + /** + * @param string|\CachetHQ\Cachet\Models\Tag $tag + * + * @return $this + */ + public function detachTag($tag) + { + return $this->detachTags([$tag]); + } + + /** + * @param array|\ArrayAccess $tags + * + * @return $this + */ + public function syncTags($tags) + { + $tags = collect(Tag::findOrCreate($tags)); + + $this->tags()->sync($tags->pluck('id')->toArray()); + + return $this; + } + + /** + * Convert a list of tags into a collection of \CachetHQ\Cachet\Models\Tag. + * + * @param array|\ArrayAccess $values + * + * @return \Illuminate\Support\Collection + */ + protected static function convertToTags($values) + { + return collect($values)->map(function ($value) { + if ($value instanceof Tag) { + return $value; + } + + return Tag::where('slug', '=', $value)->first(); + }); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 20daea4442d..7e568bd0510 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -12,18 +12,22 @@ namespace CachetHQ\Cachet\Models; use AltThree\Validator\ValidatingTrait; -use Illuminate\Auth\Authenticatable; -use Illuminate\Auth\Passwords\CanResetPassword; -use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; -use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Foundation\Auth\User as Authenticatable; +use Illuminate\Notifications\Notifiable; use Illuminate\Support\Facades\Hash; +use Illuminate\Support\Str; -class User extends Model implements AuthenticatableContract, CanResetPasswordContract +/** + * This is the user model. + * + * @author James Brooks + */ +class User extends Authenticatable { - use Authenticatable, CanResetPassword, ValidatingTrait; - + use Notifiable; + use ValidatingTrait; /** * The admin level of user. * @@ -38,6 +42,15 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon */ const LEVEL_USER = 2; + /** + * The model's attributes. + * + * @var string[] + */ + protected $attributes = [ + 'welcomed' => false, + ]; + /** * The attributes that should be casted to native types. * @@ -50,6 +63,23 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon 'api_key' => 'string', 'active' => 'bool', 'level' => 'int', + 'welcomed' => 'bool', + ]; + + /** + * The fillable properties. + * + * @var string[] + */ + protected $fillable = [ + 'username', + 'password', + 'google_2fa_secret', + 'email', + 'api_key', + 'active', + 'level', + 'welcomed', ]; /** @@ -81,6 +111,8 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon /** * Overrides the models boot method. + * + * @return void */ public static function boot() { @@ -94,29 +126,41 @@ public static function boot() } /** - * Hash any password being inserted by default. + * Scope all admin users. * - * @param string $password + * @param \Illuminate\Database\Eloquent\Builder $query * - * @return \CachetHQ\Cachet\Models\User + * @return \Illuminate\Database\Eloquent\Builder */ - public function setPasswordAttribute($password) + public function scopeAdmins(Builder $query) { - $this->attributes['password'] = Hash::make($password); + return $query->where('level', '=', self::LEVEL_ADMIN); + } - return $this; + /** + * Scope all active users. + * + * @param \Illuminate\Database\Eloquent\Builder $query + * + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeActive(Builder $query) + { + return $query->where('active', '=', true); } /** - * Returns a Gravatar URL for the users email address. + * Hash any password being inserted by default. * - * @param int $size + * @param string $password * - * @return string + * @return \CachetHQ\Cachet\Models\User */ - public function getGravatarAttribute($size = 200) + public function setPasswordAttribute($password) { - return sprintf('https://www.gravatar.com/avatar/%s?size=%d', md5($this->email), $size); + $this->attributes['password'] = Hash::make($password); + + return $this; } /** @@ -131,11 +175,7 @@ public function getGravatarAttribute($size = 200) */ public static function findByApiToken($token, $columns = ['*']) { - $user = static::where('api_key', $token)->first($columns); - - if (!$user) { - throw new ModelNotFoundException(); - } + $user = static::where('api_key', $token)->firstOrFail($columns); return $user; } @@ -147,7 +187,7 @@ public static function findByApiToken($token, $columns = ['*']) */ public static function generateApiKey() { - return str_random(20); + return Str::random(20); } /** diff --git a/app/Notifications/Component/ComponentStatusChangedNotification.php b/app/Notifications/Component/ComponentStatusChangedNotification.php new file mode 100644 index 00000000000..02d02d4ac3a --- /dev/null +++ b/app/Notifications/Component/ComponentStatusChangedNotification.php @@ -0,0 +1,155 @@ + + */ +class ComponentStatusChangedNotification extends Notification +{ + use Queueable; + + /** + * The component that changed. + * + * @var \CachetHQ\Cachet\Models\Component + */ + protected $component; + + /** + * The component status we're now at. + * + * @var int + */ + protected $status; + + /** + * Create a new notification instance. + * + * @param \CachetHQ\Cachet\Models\Component $component + * @param int $status + * + * @return void + */ + public function __construct(Component $component, $status) + { + $this->component = AutoPresenter::decorate($component); + $this->status = $status; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * + * @return string[] + */ + public function via($notifiable) + { + return ['mail', 'nexmo', 'slack']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $content = trans('notifications.component.status_update.mail.content', [ + 'name' => $this->component->name, + 'old_status' => $this->component->human_status, + 'new_status' => trans("cachet.components.status.{$this->status}"), + ]); + + return (new MailMessage()) + ->subject(trans('notifications.component.status_update.mail.subject')) + ->markdown('notifications.component.update', [ + 'componentName' => $this->component->name, + 'content' => $content, + 'unsubscribeText' => trans('cachet.subscriber.unsubscribe'), + 'unsubscribeUrl' => cachet_route('subscribe.unsubscribe', $notifiable->verify_code), + 'manageSubscriptionText' => trans('cachet.subscriber.manage_subscription'), + 'manageSubscriptionUrl' => cachet_route('subscribe.manage', $notifiable->verify_code), + ]); + } + + /** + * Get the Nexmo / SMS representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\NexmoMessage + */ + public function toNexmo($notifiable) + { + $content = trans('notifications.component.status_update.sms.content', [ + 'name' => $this->component->name, + 'old_status' => $this->component->human_status, + 'new_status' => trans("cachet.components.status.{$this->status}"), + ]); + + return (new NexmoMessage())->content($content); + } + + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\SlackMessage + */ + public function toSlack($notifiable) + { + $content = trans('notifications.component.status_update.slack.content', [ + 'name' => $this->component->name, + 'old_status' => $this->component->human_status, + 'new_status' => trans("cachet.components.status.{$this->status}"), + ]); + + $status = 'info'; + + if ($this->status <= 1) { + $status = 'success'; + } elseif ($this->status === 2) { + $status = 'warning'; + } elseif ($this->status >= 3) { + $status = 'error'; + } + + return (new SlackMessage()) + ->$status() + ->content(trans('notifications.component.status_update.slack.title')) + ->attachment(function ($attachment) use ($content, $notifiable) { + $attachment->title($content, cachet_route('status-page')) + ->fields(array_filter([ + 'Component' => $this->component->name, + 'Old Status' => $this->component->human_status, + 'New Status' => trans("cachet.components.status.{$this->status}"), + 'Link' => $this->component->link, + ])) + ->footer(trans('cachet.subscriber.unsubscribe', ['link' => cachet_route('subscribe.unsubscribe', $notifiable->verify_code)])); + }); + } +} diff --git a/app/Notifications/Incident/NewIncidentNotification.php b/app/Notifications/Incident/NewIncidentNotification.php new file mode 100644 index 00000000000..ac56c9dea95 --- /dev/null +++ b/app/Notifications/Incident/NewIncidentNotification.php @@ -0,0 +1,139 @@ + + */ +class NewIncidentNotification extends Notification +{ + use Queueable; + + /** + * The incident. + * + * @var \CachetHQ\Cachet\Models\Incident + */ + protected $incident; + + /** + * Create a new notification instance. + * + * @param \CachetHQ\Cachet\Models\Incident $incident + * + * @return void + */ + public function __construct(Incident $incident) + { + $this->incident = AutoPresenter::decorate($incident); + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * + * @return string[] + */ + public function via($notifiable) + { + return ['mail', 'nexmo', 'slack']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $content = trans('notifications.incident.new.mail.content', [ + 'name' => $this->incident->name, + ]); + + return (new MailMessage()) + ->subject(trans('notifications.incident.new.mail.subject')) + ->markdown('notifications.incident.new', [ + 'incident' => $this->incident, + 'content' => $content, + 'actionText' => trans('notifications.incident.new.mail.action'), + 'actionUrl' => cachet_route('incident', [$this->incident]), + 'unsubscribeText' => trans('cachet.subscriber.unsubscribe'), + 'unsubscribeUrl' => cachet_route('subscribe.unsubscribe', $notifiable->verify_code), + 'manageSubscriptionText' => trans('cachet.subscriber.manage_subscription'), + 'manageSubscriptionUrl' => cachet_route('subscribe.manage', $notifiable->verify_code), + ]); + } + + /** + * Get the Nexmo / SMS representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\NexmoMessage + */ + public function toNexmo($notifiable) + { + return (new NexmoMessage())->content(trans('notifications.incident.new.sms.content', [ + 'name' => $this->incident->name, + ])); + } + + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\SlackMessage + */ + public function toSlack($notifiable) + { + $content = trans('notifications.incident.new.slack.content', [ + 'app_name' => Config::get('setting.app_name'), + ]); + + $status = 'info'; + + if ($this->incident->status === Incident::FIXED) { + $status = 'success'; + } elseif ($this->incident->status === Incident::WATCHED) { + $status = 'warning'; + } else { + $status = 'error'; + } + + return (new SlackMessage()) + ->$status() + ->content($content) + ->attachment(function ($attachment) { + $attachment->title(trans('notifications.incident.new.slack.title', ['name' => $this->incident->name])) + ->timestamp($this->incident->getWrappedObject()->occurred_at) + ->fields(array_filter([ + 'ID' => "#{$this->incident->id}", + 'Link' => $this->incident->permalink, + ])); + }); + } +} diff --git a/app/Notifications/IncidentUpdate/IncidentUpdatedNotification.php b/app/Notifications/IncidentUpdate/IncidentUpdatedNotification.php new file mode 100644 index 00000000000..6c88b40370c --- /dev/null +++ b/app/Notifications/IncidentUpdate/IncidentUpdatedNotification.php @@ -0,0 +1,150 @@ + + */ +class IncidentUpdatedNotification extends Notification +{ + use Queueable; + + /** + * The incident update. + * + * @var \CachetHQ\Cachet\Models\IncidentUpdate + */ + protected $update; + + /** + * Create a new notification instance. + * + * @param \CachetHQ\Cachet\Models\IncidentUpdate $update + * + * @return void + */ + public function __construct(IncidentUpdate $update) + { + $this->update = AutoPresenter::decorate($update); + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * + * @return string[] + */ + public function via($notifiable) + { + return ['mail', 'nexmo', 'slack']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $content = trans('notifications.incident.update.mail.content', [ + 'name' => $this->update->incident->name, + 'time' => $this->update->created_at_diff, + ]); + + return (new MailMessage()) + ->subject(trans('notifications.incident.update.mail.subject')) + ->markdown('notifications.incident.update', [ + 'incident' => $this->update->incident, + 'update' => $this->update, + 'content' => $content, + 'actionText' => trans('notifications.incident.new.mail.action'), + 'actionUrl' => cachet_route('incident', [$this->update->incident]), + 'incidentName' => $this->update->incident->name, + 'newStatus' => $this->update->human_status, + 'unsubscribeText' => trans('cachet.subscriber.unsubscribe'), + 'unsubscribeUrl' => cachet_route('subscribe.unsubscribe', $notifiable->verify_code), + 'manageSubscriptionText' => trans('cachet.subscriber.manage_subscription'), + 'manageSubscriptionUrl' => cachet_route('subscribe.manage', $notifiable->verify_code), + ]); + } + + /** + * Get the Nexmo / SMS representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\NexmoMessage + */ + public function toNexmo($notifiable) + { + $content = trans('notifications.incident.update.sms.content', [ + 'name' => $this->update->incident->name, + ]); + + return (new NexmoMessage())->content($content); + } + + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\SlackMessage + */ + public function toSlack($notifiable) + { + $content = trans('notifications.incident.update.slack.content', [ + 'name' => $this->update->incident->name, + 'new_status' => $this->update->human_status, + ]); + + $status = 'info'; + + if ($this->update->status === Incident::FIXED) { + $status = 'success'; + } elseif ($this->update->status === Incident::WATCHED) { + $status = 'warning'; + } else { + $status = 'error'; + } + + return (new SlackMessage()) + ->$status() + ->content($content) + ->attachment(function ($attachment) use ($notifiable) { + $attachment->title(trans('notifications.incident.update.slack.title', [ + 'name' => $this->update->incident->name, + 'new_status' => $this->update->human_status, + ])) + ->timestamp($this->update->getWrappedObject()->created_at) + ->fields(array_filter([ + 'ID' => "#{$this->update->id}", + 'Link' => $this->update->permalink, + ])) + ->footer(trans('cachet.subscriber.unsubscribe', ['link' => cachet_route('subscribe.unsubscribe', $notifiable->verify_code)])); + }); + } +} diff --git a/app/Notifications/Schedule/NewScheduleNotification.php b/app/Notifications/Schedule/NewScheduleNotification.php new file mode 100644 index 00000000000..3b04bc679f6 --- /dev/null +++ b/app/Notifications/Schedule/NewScheduleNotification.php @@ -0,0 +1,130 @@ + + */ +class NewScheduleNotification extends Notification implements ShouldQueue +{ + use Queueable; + + /** + * The schedule. + * + * @var \CachetHQ\Cachet\Models\Schedule + */ + protected $schedule; + + /** + * Create a new notification instance. + * + * @param \CachetHQ\Cachet\Models\Schedule $schedule + * + * @return void + */ + public function __construct(Schedule $schedule) + { + $this->schedule = AutoPresenter::decorate($schedule); + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * + * @return string[] + */ + public function via($notifiable) + { + return ['mail', 'nexmo', 'slack']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $content = trans('notifications.schedule.new.mail.content', [ + 'name' => $this->schedule->name, + 'date' => $this->schedule->scheduled_at_formatted, + ]); + + return (new MailMessage()) + ->subject(trans('notifications.schedule.new.mail.subject')) + ->markdown('notifications.schedule.new', [ + 'content' => $content, + 'unsubscribeText' => trans('cachet.subscriber.unsubscribe'), + 'unsubscribeUrl' => cachet_route('subscribe.unsubscribe', $notifiable->verify_code), + 'manageSubscriptionText' => trans('cachet.subscriber.manage_subscription'), + 'manageSubscriptionUrl' => cachet_route('subscribe.manage', $notifiable->verify_code), + ]); + } + + /** + * Get the Nexmo / SMS representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\NexmoMessage + */ + public function toNexmo($notifiable) + { + $content = trans('notifications.schedule.new.sms.content', [ + 'name' => $this->schedule->name, + 'date' => $this->schedule->scheduled_at_formatted, + ]); + + return (new NexmoMessage())->content($content); + } + + /** + * Get the Slack representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\SlackMessage + */ + public function toSlack($notifiable) + { + $content = trans('notifications.schedule.new.slack.content', [ + 'name' => $this->schedule->name, + 'date' => $this->schedule->scheduled_at_formatted, + ]); + + return (new SlackMessage()) + ->content(trans('notifications.schedule.new.slack.title')) + ->attachment(function ($attachment) use ($content) { + $attachment->title($content) + ->timestamp($this->schedule->getWrappedObject()->scheduled_at) + ->fields(array_filter([ + 'ID' => "#{$this->schedule->id}", + 'Status' => $this->schedule->human_status, + ])); + }); + } +} diff --git a/app/Notifications/Subscriber/ManageSubscriptionNotification.php b/app/Notifications/Subscriber/ManageSubscriptionNotification.php new file mode 100644 index 00000000000..e8f883980f6 --- /dev/null +++ b/app/Notifications/Subscriber/ManageSubscriptionNotification.php @@ -0,0 +1,52 @@ + $notifiable->verify_code]); + + return (new MailMessage()) + ->subject(trans('notifications.subscriber.manage.mail.subject')) + ->greeting(trans('notifications.subscriber.manage.mail.title', ['app_name' => setting('app_name')])) + ->action(trans('notifications.subscriber.manage.mail.action'), $route) + ->line(trans('notifications.subscriber.manage.mail.content', ['app_name' => setting('app_name')])); + } +} diff --git a/app/Notifications/Subscriber/VerifySubscriptionNotification.php b/app/Notifications/Subscriber/VerifySubscriptionNotification.php new file mode 100644 index 00000000000..76da5dab236 --- /dev/null +++ b/app/Notifications/Subscriber/VerifySubscriptionNotification.php @@ -0,0 +1,58 @@ + + */ +class VerifySubscriptionNotification extends Notification +{ + use Queueable; + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * + * @return string[] + */ + public function via($notifiable) + { + return ['mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $route = URL::signedRoute(cachet_route_generator('subscribe.verify'), ['code' => $notifiable->verify_code]); + + return (new MailMessage()) + ->subject(trans('notifications.subscriber.verify.mail.subject')) + ->greeting(trans('notifications.subscriber.verify.mail.title', ['app_name' => Config::get('setting.app_name')])) + ->action(trans('notifications.subscriber.verify.mail.action'), $route) + ->line(trans('notifications.subscriber.verify.mail.content', ['app_name' => Config::get('setting.app_name')])); + } +} diff --git a/app/Notifications/System/SystemTestNotification.php b/app/Notifications/System/SystemTestNotification.php new file mode 100644 index 00000000000..941ff8b9af0 --- /dev/null +++ b/app/Notifications/System/SystemTestNotification.php @@ -0,0 +1,53 @@ + + */ +class SystemTestNotification extends Notification +{ + use Queueable; + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * + * @return string[] + */ + public function via($notifiable) + { + return ['mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + return (new MailMessage()) + ->subject(trans('notifications.system.test.mail.subject')) + ->greeting(trans('notifications.system.test.mail.title')) + ->line(trans('notifications.system.test.mail.content')); + } +} diff --git a/app/Notifications/User/InviteUserNotification.php b/app/Notifications/User/InviteUserNotification.php new file mode 100644 index 00000000000..0ebb906e3ce --- /dev/null +++ b/app/Notifications/User/InviteUserNotification.php @@ -0,0 +1,55 @@ + + */ +class InviteUserNotification extends Notification +{ + use Queueable; + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * + * @return string[] + */ + public function via($notifiable) + { + return ['mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + return (new MailMessage()) + ->subject(trans('notifications.user.invite.mail.subject')) + ->greeting(trans('notifications.user.invite.mail.title', ['app_name' => Config::get('setting.app_name')])) + ->action(trans('notifications.user.invite.mail.action'), cachet_route('signup.invite', [$notifiable->code])) + ->line(trans('notifications.user.invite.mail.content', ['app_name' => Config::get('setting.app_name')])); + } +} diff --git a/app/Presenters/ComponentGroupPresenter.php b/app/Presenters/ComponentGroupPresenter.php index 9aebc48369f..456831a4ddd 100644 --- a/app/Presenters/ComponentGroupPresenter.php +++ b/app/Presenters/ComponentGroupPresenter.php @@ -20,6 +20,13 @@ class ComponentGroupPresenter extends BasePresenter implements Arrayable { use TimestampsTrait; + /** + * Flag for the enabled_components_lowest function. + * + * @var bool + */ + protected $enabledComponentsLowest = false; + /** * Returns the lowest component status. * @@ -27,7 +34,7 @@ class ComponentGroupPresenter extends BasePresenter implements Arrayable */ public function lowest_status() { - if ($component = $this->wrappedObject->enabled_components_lowest()->first()) { + if ($component = $this->enabled_components_lowest()) { return AutoPresenter::decorate($component)->status; } } @@ -39,7 +46,7 @@ public function lowest_status() */ public function lowest_human_status() { - if ($component = $this->wrappedObject->enabled_components_lowest()->first()) { + if ($component = $this->enabled_components_lowest()) { return AutoPresenter::decorate($component)->human_status; } } @@ -51,11 +58,25 @@ public function lowest_human_status() */ public function lowest_status_color() { - if ($component = $this->wrappedObject->enabled_components_lowest()->first()) { + if ($component = $this->enabled_components_lowest()) { return AutoPresenter::decorate($component)->status_color; } } + /** + * Return the enabled components from the wrapped object, and cache it if need be. + * + * @return bool + */ + public function enabled_components_lowest() + { + if (is_bool($this->enabledComponentsLowest)) { + $this->enabledComponentsLowest = $this->wrappedObject->enabled_components_lowest()->first(); + } + + return $this->enabledComponentsLowest; + } + /** * Determine the class for collapsed/uncollapsed groups. * @@ -81,7 +102,7 @@ public function is_collapsed() return $this->wrappedObject->components->filter(function ($component) { return $component->status > 1; - })->count() === 0; + })->isEmpty(); } /** @@ -97,4 +118,27 @@ public function toArray() 'lowest_human_status' => $this->lowest_human_status(), ]); } + + /** + * Determine if any of the contained components have active subscriptions. + * + * @return bool + */ + public function has_subscriber($subscriptions) + { + $enabled_components = $this->wrappedObject->enabled_components()->orderBy('order')->pluck('id')->toArray(); + $intersected = array_intersect($enabled_components, $subscriptions); + + return count($intersected) != 0; + } + + /** + * Determine the class for collapsed/uncollapsed groups on the subscription form. + * + * @return string + */ + public function collapse_class_with_subscriptions($subscriptions) + { + return $this->has_subscriber($subscriptions) ? 'ion-ios-minus-outline' : 'ion-ios-plus-outline'; + } } diff --git a/app/Presenters/ComponentPresenter.php b/app/Presenters/ComponentPresenter.php index af56214c5a4..07a2458ea5c 100644 --- a/app/Presenters/ComponentPresenter.php +++ b/app/Presenters/ComponentPresenter.php @@ -11,10 +11,9 @@ namespace CachetHQ\Cachet\Presenters; -use CachetHQ\Cachet\Dates\DateFactory; use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait; +use CachetHQ\Cachet\Services\Dates\DateFactory; use Illuminate\Contracts\Support\Arrayable; -use Illuminate\Support\Facades\Config; use McCool\LaravelAutoPresenter\BasePresenter; class ComponentPresenter extends BasePresenter implements Arrayable @@ -29,6 +28,7 @@ class ComponentPresenter extends BasePresenter implements Arrayable public function status_color() { switch ($this->wrappedObject->status) { + case 0: return 'greys'; case 1: return 'greens'; case 2: return 'blues'; case 3: return 'yellows'; @@ -63,7 +63,7 @@ public function tags() */ public function updated_at_formatted() { - return ucfirst(app(DateFactory::class)->make($this->wrappedObject->updated_at)->format(Config::get('setting.incident_date_format', 'l jS F Y H:i:s'))); + return ucfirst(app(DateFactory::class)->make($this->wrappedObject->updated_at)->format($this->incidentDateFormat())); } /** diff --git a/app/Presenters/IncidentPresenter.php b/app/Presenters/IncidentPresenter.php index 655be27ccd7..0a8e8a65df9 100644 --- a/app/Presenters/IncidentPresenter.php +++ b/app/Presenters/IncidentPresenter.php @@ -11,55 +11,95 @@ namespace CachetHQ\Cachet\Presenters; -use CachetHQ\Cachet\Dates\DateFactory; +use CachetHQ\Cachet\Models\Incident; use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait; +use CachetHQ\Cachet\Services\Dates\DateFactory; use GrahamCampbell\Markdown\Facades\Markdown; use Illuminate\Contracts\Support\Arrayable; -use Illuminate\Support\Facades\Config; use McCool\LaravelAutoPresenter\BasePresenter; class IncidentPresenter extends BasePresenter implements Arrayable { use TimestampsTrait; + /** + * The date factory instance. + * + * @var \CachetHQ\Cachet\Services\Dates\DateFactory + */ + protected $dates; + + /** + * Flag for the latest function. + * + * @var bool + */ + protected $latest = false; + + /** + * Incident icon lookup. + * + * @var array + */ + protected $icons = [ + 0 => 'icon ion-android-calendar', // Scheduled + 1 => 'icon ion-flag oranges', // Investigating + 2 => 'icon ion-alert yellows', // Identified + 3 => 'icon ion-eye blues', // Watching + 4 => 'icon ion-checkmark greens', // Fixed + ]; + + /** + * Create a new presenter. + * + * @param \CachetHQ\Cachet\Services\Dates\DateFactory $dates + * @param \CachetHQ\Cachet\Models\Incident $resource + * + * @return void + */ + public function __construct(DateFactory $dates, Incident $resource) + { + $this->dates = $dates; + } + /** * Renders the message from Markdown into HTML. * * @return string */ - public function formattedMessage() + public function formatted_message() { return Markdown::convertToHtml($this->wrappedObject->message); } /** - * Present diff for humans date time. + * Return the raw text of the message, even without Markdown. * * @return string */ - public function created_at_diff() + public function raw_message() { - return app(DateFactory::class)->make($this->wrappedObject->created_at)->diffForHumans(); + return strip_tags($this->formatted_message()); } /** - * Present formatted date time. + * Present formatted occurred_at date time. * * @return string */ - public function created_at_formatted() + public function occurred_at() { - return ucfirst(app(DateFactory::class)->make($this->wrappedObject->created_at)->format(Config::get('setting.incident_date_format', 'l jS F Y H:i:s'))); + return $this->dates->make($this->wrappedObject->occurred_at)->toDateTimeString(); } /** - * Formats the created_at time ready to be used by bootstrap-datetimepicker. + * Present diff for humans date time. * * @return string */ - public function created_at_datetimepicker() + public function occurred_at_diff() { - return app(DateFactory::class)->make($this->wrappedObject->created_at)->format('d/m/Y H:i'); + return $this->dates->make($this->wrappedObject->occurred_at)->diffForHumans(); } /** @@ -67,39 +107,39 @@ public function created_at_datetimepicker() * * @return string */ - public function created_at_iso() + public function occurred_at_formatted() { - return app(DateFactory::class)->make($this->wrappedObject->created_at)->toISO8601String(); + return ucfirst($this->dates->make($this->wrappedObject->occurred_at)->format($this->incidentDateFormat())); } /** - * Present formatted date time. + * Formats the occurred_at time ready to be used by bootstrap-datetimepicker. * * @return string */ - public function scheduled_at() + public function occurred_at_datetimepicker() { - return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->toDateTimeString(); + return $this->dates->make($this->wrappedObject->occurred_at)->format('Y-m-d H:i'); } /** - * Present diff for humans date time. + * Present formatted date time. * * @return string */ - public function scheduled_at_diff() + public function occurred_at_iso() { - return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->diffForHumans(); + return $this->dates->make($this->wrappedObject->occurred_at)->toISO8601String(); } /** - * Present formatted date time. + * Present diff for humans date time. * * @return string */ - public function scheduled_at_formatted() + public function created_at_diff() { - return ucfirst(app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->format(Config::get('setting.incident_date_format', 'l jS F Y H:i:s'))); + return $this->dates->make($this->wrappedObject->created_at)->diffForHumans(); } /** @@ -107,19 +147,19 @@ public function scheduled_at_formatted() * * @return string */ - public function scheduled_at_iso() + public function created_at_formatted() { - return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->toISO8601String(); + return ucfirst($this->dates->make($this->wrappedObject->created_at)->format($this->incidentDateFormat())); } /** - * Formats the scheduled_at time ready to be used by bootstrap-datetimepicker. + * Present formatted date time. * * @return string */ - public function scheduled_at_datetimepicker() + public function created_at_iso() { - return app(DateFactory::class)->make($this->wrappedObject->scheduled_at)->format('d/m/Y H:i'); + return $this->dates->make($this->wrappedObject->created_at)->toISO8601String(); } /** @@ -129,11 +169,7 @@ public function scheduled_at_datetimepicker() */ public function timestamp_formatted() { - if ($this->wrappedObject->is_scheduled) { - return $this->scheduled_at_formatted; - } - - return $this->created_at_formatted; + return $this->occurred_at_formatted; } /** @@ -143,11 +179,7 @@ public function timestamp_formatted() */ public function timestamp_iso() { - if ($this->wrappedObject->is_scheduled) { - return $this->scheduled_at_iso; - } - - return $this->created_at_iso; + return $this->occurred_at_iso; } /** @@ -157,19 +189,8 @@ public function timestamp_iso() */ public function icon() { - switch ($this->wrappedObject->status) { - case 0: // Scheduled - return 'icon ion-android-calendar'; - case 1: // Investigating - return 'icon ion-flag oranges'; - case 2: // Identified - return 'icon ion-alert yellows'; - case 3: // Watching - return 'icon ion-eye blues'; - case 4: // Fixed - return 'icon ion-checkmark greens'; - default: // Something actually broke, this shouldn't happen. - return ''; + if (isset($this->icons[$this->wrappedObject->status])) { + return $this->icons[$this->wrappedObject->status]; } } @@ -183,6 +204,98 @@ public function human_status() return trans('cachet.incidents.status.'.$this->wrappedObject->status); } + /** + * Returns the latest update. + * + * @return int|null + */ + public function latest_status() + { + if ($update = $this->latest()) { + return $update->status; + } + + return $this->wrappedObject->status; + } + + /** + * Returns the latest update. + * + * @return string|null + */ + public function latest_human_status() + { + if ($update = $this->latest()) { + return trans('cachet.incidents.status.'.$update->status); + } + + return $this->human_status(); + } + + /** + * Present the latest icon. + * + * @return string + */ + public function latest_icon() + { + if ($update = $this->latest()) { + if (isset($this->icons[$update->status])) { + return $this->icons[$update->status]; + } + } + + return $this->icon(); + } + + /** + * Fetch the latest incident update. + * + * @return \CachetHQ\Cachet\Models\IncidentUpdate|void + */ + public function latest() + { + if (is_bool($this->latest)) { + $this->latest = $this->wrappedObject->updates()->first(); + } + + return $this->latest; + } + + /** + * Get the incident permalink. + * + * @return string + */ + public function permalink() + { + return cachet_route('incident', [$this->wrappedObject->id]); + } + + /** + * The duration since the last update (in seconds). + * + * @return int + */ + public function duration() + { + if ($update = $this->latest()) { + return $this->wrappedObject->created_at->diffInSeconds($update->occurred_at); + } + + return 0; + } + + /** + * Return the meta in a key value pair. + * + * @return array + */ + public function meta() + { + return $this->wrappedObject->meta->pluck('value', 'key')->all(); + } + /** * Convert the presenter instance to an array. * @@ -191,10 +304,17 @@ public function human_status() public function toArray() { return array_merge($this->wrappedObject->toArray(), [ - 'human_status' => $this->human_status(), - 'scheduled_at' => $this->scheduled_at(), - 'created_at' => $this->created_at(), - 'updated_at' => $this->updated_at(), + 'human_status' => $this->human_status(), + 'latest_update_id' => $this->latest() ? $this->latest()->id : null, + 'latest_status' => $this->latest_status(), + 'latest_human_status' => $this->latest_human_status(), + 'latest_icon' => $this->latest_icon(), + 'permalink' => $this->permalink(), + 'duration' => $this->duration(), + 'meta' => $this->meta(), + 'occurred_at' => $this->occurred_at(), + 'created_at' => $this->created_at(), + 'updated_at' => $this->updated_at(), ]); } } diff --git a/app/Presenters/IncidentUpdatePresenter.php b/app/Presenters/IncidentUpdatePresenter.php new file mode 100644 index 00000000000..abbcbbc8d17 --- /dev/null +++ b/app/Presenters/IncidentUpdatePresenter.php @@ -0,0 +1,177 @@ + + */ +class IncidentUpdatePresenter extends BasePresenter implements Arrayable +{ + use TimestampsTrait; + + /** + * Renders the message from Markdown into HTML. + * + * @return string + */ + public function formatted_message() + { + return Markdown::convertToHtml($this->wrappedObject->message); + } + + /** + * Return the raw text of the message, even without Markdown. + * + * @return string + */ + public function raw_message() + { + return strip_tags($this->formatted_message()); + } + + /** + * Present diff for humans date time. + * + * @return string + */ + public function created_at_diff() + { + return app(DateFactory::class)->make($this->wrappedObject->created_at)->diffForHumans(); + } + + /** + * Present formatted date time. + * + * @return string + */ + public function created_at_formatted() + { + return ucfirst(app(DateFactory::class)->make($this->wrappedObject->created_at)->format($this->incidentDateFormat())); + } + + /** + * Formats the created_at time ready to be used by bootstrap-datetimepicker. + * + * @return string + */ + public function created_at_datetimepicker() + { + return app(DateFactory::class)->make($this->wrappedObject->created_at)->format('d/m/Y H:i'); + } + + /** + * Present formatted date time. + * + * @return string + */ + public function created_at_iso() + { + return app(DateFactory::class)->make($this->wrappedObject->created_at)->toISO8601String(); + } + + /** + * Returns a formatted timestamp for use within the timeline. + * + * @return string + */ + public function timestamp_formatted() + { + if ($this->wrappedObject->is_scheduled) { + return $this->scheduled_at_formatted; + } + + return $this->created_at_formatted; + } + + /** + * Return the iso timestamp for use within the timeline. + * + * @return string + */ + public function timestamp_iso() + { + if ($this->wrappedObject->is_scheduled) { + return $this->scheduled_at_iso; + } + + return $this->created_at_iso; + } + + /** + * Present the status with an icon. + * + * @return string + */ + public function icon() + { + switch ($this->wrappedObject->status) { + case 1: // Investigating + + return 'icon ion-flag oranges'; + case 2: // Identified + + return 'icon ion-alert yellows'; + case 3: // Watching + + return 'icon ion-eye blues'; + case 4: // Fixed + + return 'icon ion-checkmark greens'; + default: // Something actually broke, this shouldn't happen. + + return ''; + } + } + + /** + * Returns a human readable version of the status. + * + * @return string + */ + public function human_status() + { + return trans('cachet.incidents.status.'.$this->wrappedObject->status); + } + + /** + * Generate a permalink to the incident update. + * + * @return string + */ + public function permalink() + { + return cachet_route('incident', [$this->wrappedObject->incident]).'#update-'.$this->wrappedObject->id; + } + + /** + * Convert the presenter instance to an array. + * + * @return string[] + */ + public function toArray() + { + return array_merge($this->wrappedObject->toArray(), [ + 'human_status' => $this->human_status(), + 'permalink' => $this->permalink(), + 'created_at' => $this->created_at(), + 'updated_at' => $this->updated_at(), + ]); + } +} diff --git a/app/Presenters/MetricPointPresenter.php b/app/Presenters/MetricPointPresenter.php index 388ef816d39..5cbfdd60817 100644 --- a/app/Presenters/MetricPointPresenter.php +++ b/app/Presenters/MetricPointPresenter.php @@ -19,16 +19,6 @@ class MetricPointPresenter extends BasePresenter implements Arrayable { use TimestampsTrait; - /** - * Show the actual calculated value; as per (value * counter). - * - * @return int - */ - public function calculated_value() - { - return $this->wrappedObject->value * $this->wrappedObject->counter; - } - /** * Convert the presenter instance to an array. * @@ -37,9 +27,8 @@ public function calculated_value() public function toArray() { return array_merge($this->wrappedObject->toArray(), [ - 'created_at' => $this->created_at(), - 'updated_at' => $this->updated_at(), - 'calculated_value' => $this->calculated_value(), + 'created_at' => $this->created_at(), + 'updated_at' => $this->updated_at(), ]); } } diff --git a/app/Presenters/MetricPresenter.php b/app/Presenters/MetricPresenter.php index 3a76abdd9ca..4a4ef6607e9 100644 --- a/app/Presenters/MetricPresenter.php +++ b/app/Presenters/MetricPresenter.php @@ -13,9 +13,10 @@ use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait; use Illuminate\Contracts\Support\Arrayable; +use Illuminate\Contracts\Support\Jsonable; use McCool\LaravelAutoPresenter\BasePresenter; -class MetricPresenter extends BasePresenter implements Arrayable +class MetricPresenter extends BasePresenter implements Arrayable, Jsonable { use TimestampsTrait; @@ -72,4 +73,18 @@ public function toArray() 'default_view_name' => $this->default_view_name(), ]); } + + /** + * Convert the object to its JSON representation. + * + * @param int $options + * + * @return string + */ + public function toJson($options = 0) + { + $json = json_encode($this->toArray(), $options); + + return $json; + } } diff --git a/app/Presenters/SchedulePresenter.php b/app/Presenters/SchedulePresenter.php new file mode 100644 index 00000000000..ddf0c04ffd1 --- /dev/null +++ b/app/Presenters/SchedulePresenter.php @@ -0,0 +1,261 @@ + + */ +class SchedulePresenter extends BasePresenter implements Arrayable +{ + use TimestampsTrait; + + /** + * The date factory instance. + * + * @var \CachetHQ\Cachet\Services\Dates\DateFactory + */ + protected $dates; + + /** + * Create a new presenter. + * + * @param \CachetHQ\Cachet\Services\Dates\DateFactory $dates + * @param \CachetHQ\Cachet\Models\Schedule $resource + * + * @return void + */ + public function __construct(DateFactory $dates, Schedule $resource) + { + $this->dates = $dates; + } + + /** + * Renders the message from Markdown into HTML. + * + * @return string + */ + public function formatted_message() + { + return Markdown::convertToHtml($this->wrappedObject->message); + } + + /** + * Present diff for humans date time. + * + * @return string + */ + public function created_at_diff() + { + return $this->dates->make($this->wrappedObject->created_at)->diffForHumans(); + } + + /** + * Present formatted date time. + * + * @return string + */ + public function created_at_formatted() + { + return ucfirst($this->dates->make($this->wrappedObject->created_at)->format($this->incidentDateFormat())); + } + + /** + * Formats the created_at time ready to be used by bootstrap-datetimepicker. + * + * @return string + */ + public function created_at_datetimepicker() + { + return $this->dates->make($this->wrappedObject->created_at)->format('Y-m-d H:i'); + } + + /** + * Present formatted date time. + * + * @return string + */ + public function created_at_iso() + { + return $this->dates->make($this->wrappedObject->created_at)->toISO8601String(); + } + + /** + * Present formatted date time. + * + * @return string + */ + public function scheduled_at() + { + return $this->dates->make($this->wrappedObject->scheduled_at)->toDateTimeString(); + } + + /** + * Present diff for humans date time. + * + * @return string + */ + public function scheduled_at_diff() + { + return $this->dates->make($this->wrappedObject->scheduled_at)->diffForHumans(); + } + + /** + * Present formatted date time. + * + * @return string + */ + public function scheduled_at_formatted() + { + return ucfirst($this->dates->make($this->wrappedObject->scheduled_at)->format($this->incidentDateFormat())); + } + + /** + * Present formatted date time. + * + * @return string + */ + public function scheduled_at_iso() + { + return $this->dates->make($this->wrappedObject->scheduled_at)->toISO8601String(); + } + + /** + * Formats the scheduled_at time ready to be used by bootstrap-datetimepicker. + * + * @return string + */ + public function scheduled_at_datetimepicker() + { + return $this->dates->make($this->wrappedObject->scheduled_at)->format('Y-m-d H:i'); + } + + /** + * Returns a formatted timestamp for use within the timeline. + * + * @return string + */ + public function timestamp_formatted() + { + if ($this->wrappedObject->is_scheduled) { + return $this->scheduled_at_formatted; + } + + return $this->created_at_formatted; + } + + /** + * Present formatted date time. + * + * @return string + */ + public function completed_at() + { + return $this->dates->make($this->wrappedObject->completed_at)->toDateTimeString(); + } + + /** + * Present diff for humans date time. + * + * @return string + */ + public function completed_at_diff() + { + return $this->dates->make($this->wrappedObject->completed_at)->diffForHumans(); + } + + /** + * Present formatted date time. + * + * @return string + */ + public function completed_at_formatted() + { + return ucfirst($this->dates->make($this->wrappedObject->completed_at)->format($this->incidentDateFormat())); + } + + /** + * Present formatted date time. + * + * @return string + */ + public function completed_at_iso() + { + return $this->dates->make($this->wrappedObject->completed_at)->toISO8601String(); + } + + /** + * Formats the completed_at time ready to be used by bootstrap-datetimepicker. + * + * @return string|void + */ + public function completed_at_datetimepicker() + { + if ($this->wrappedObject->completed_at) { + return $this->dates->make($this->wrappedObject->completed_at)->format('Y-m-d H:i'); + } + } + + /** + * Return the iso timestamp for use within the timeline. + * + * @return string + */ + public function timestamp_iso() + { + if ($this->wrappedObject->is_scheduled) { + return $this->scheduled_at_iso; + } + + return $this->completed_at_iso; + } + + /** + * Returns a human readable version of the status. + * + * @return string + */ + public function human_status() + { + // return trans('cachet.incidents.status.'.$this->wrappedObject->status); + // TODO: Refactor into translations. + switch ($this->wrappedObject->status) { + case 0: return 'Upcoming'; + case 1: return 'In Progress'; + case 2: return 'Complete'; + } + } + + /** + * Convert the presenter instance to an array. + * + * @return string[] + */ + public function toArray() + { + return array_merge($this->wrappedObject->toArray(), [ + 'human_status' => $this->human_status(), + 'scheduled_at' => $this->scheduled_at(), + 'completed_at' => $this->completed_at(), + 'created_at' => $this->created_at(), + 'updated_at' => $this->updated_at(), + ]); + } +} diff --git a/app/Presenters/SubscriberPresenter.php b/app/Presenters/SubscriberPresenter.php index 2da85041d98..71c2112614e 100644 --- a/app/Presenters/SubscriberPresenter.php +++ b/app/Presenters/SubscriberPresenter.php @@ -11,10 +11,9 @@ namespace CachetHQ\Cachet\Presenters; -use CachetHQ\Cachet\Dates\DateFactory; use CachetHQ\Cachet\Presenters\Traits\TimestampsTrait; +use CachetHQ\Cachet\Services\Dates\DateFactory; use Illuminate\Contracts\Support\Arrayable; -use Illuminate\Support\Facades\Config; use McCool\LaravelAutoPresenter\BasePresenter; class SubscriberPresenter extends BasePresenter implements Arrayable @@ -28,7 +27,7 @@ class SubscriberPresenter extends BasePresenter implements Arrayable */ public function verified_at() { - return ucfirst(app(DateFactory::class)->make($this->wrappedObject->verified_at)->format(Config::get('setting.incident_date_format', 'l jS F Y H:i:s'))); + return ucfirst(app(DateFactory::class)->make($this->wrappedObject->verified_at)->format($this->incidentDateFormat())); } /** diff --git a/app/Presenters/Traits/TimestampsTrait.php b/app/Presenters/Traits/TimestampsTrait.php index eba58b2abdb..8642ac7ac62 100644 --- a/app/Presenters/Traits/TimestampsTrait.php +++ b/app/Presenters/Traits/TimestampsTrait.php @@ -11,8 +11,16 @@ namespace CachetHQ\Cachet\Presenters\Traits; -use CachetHQ\Cachet\Dates\DateFactory; +use CachetHQ\Cachet\Services\Dates\DateFactory; +use Illuminate\Support\Facades\Config; +/** + * This is the timestamps trait. + * + * @author Joseph Cohen + * @author Graham Campbell + * @author James Brooks + */ trait TimestampsTrait { /** @@ -44,4 +52,14 @@ public function deleted_at() { return app(DateFactory::class)->make($this->wrappedObject->deleted_at)->toDateTimeString(); } + + /** + * Get the incident date format setting, or fallback to a sane default. + * + * @return string + */ + protected function incidentDateFormat() + { + return Config::get('setting.incident_date_format', 'l jS F Y H:i:s'); + } } diff --git a/app/Foundation/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php similarity index 57% rename from app/Foundation/Providers/AppServiceProvider.php rename to app/Providers/AppServiceProvider.php index 8b7c9757870..007a271ca4f 100644 --- a/app/Foundation/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -9,14 +9,14 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Foundation\Providers; +namespace CachetHQ\Cachet\Providers; use AltThree\Bus\Dispatcher; +use AltThree\Validator\ValidatingMiddleware; use CachetHQ\Cachet\Bus\Middleware\UseDatabaseTransactions; -use CachetHQ\Cachet\Dates\DateFactory; -use CachetHQ\Cachet\Integrations\Credits; -use CachetHQ\Cachet\Integrations\Feed; -use CachetHQ\Cachet\Integrations\Releases; +use CachetHQ\Cachet\Services\Dates\DateFactory; +use Illuminate\Database\Eloquent\Relations\Relation; +use Illuminate\Support\Facades\Schema; use Illuminate\Support\ServiceProvider; use Illuminate\Support\Str; @@ -24,7 +24,7 @@ * This is the app service provider. * * @author James Brooks - * @author Joe Cohen + * @author Joseph Cohen * @author Graham Campbell */ class AppServiceProvider extends ServiceProvider @@ -33,18 +33,31 @@ class AppServiceProvider extends ServiceProvider * Boot the service provider. * * @param \AltThree\Bus\Dispatcher $dispatcher + * + * @return void */ public function boot(Dispatcher $dispatcher) { + Schema::defaultStringLength(191); + $dispatcher->mapUsing(function ($command) { return Dispatcher::simpleMapping($command, 'CachetHQ\Cachet\Bus', 'CachetHQ\Cachet\Bus\Handlers'); }); - $dispatcher->pipeThrough([UseDatabaseTransactions::class]); + $dispatcher->pipeThrough([UseDatabaseTransactions::class, ValidatingMiddleware::class]); Str::macro('canonicalize', function ($url) { return preg_replace('/([^\/])$/', '$1/', $url); }); + + Relation::morphMap([ + 'components' => \CachetHQ\Cachet\Models\Component::class, + 'incidents' => \CachetHQ\Cachet\Models\Incident::class, + 'metrics' => \CachetHQ\Cachet\Models\Metric::class, + 'schedules' => \CachetHQ\Cachet\Models\Schedule::class, + 'subscriber' => \CachetHQ\Cachet\Models\Subscriber::class, + 'tags' => \CachetHQ\Cachet\Models\Tag::class, + ]); } /** @@ -55,9 +68,6 @@ public function boot(Dispatcher $dispatcher) public function register() { $this->registerDateFactory(); - $this->registerCredits(); - $this->registerFeed(); - $this->registerReleases(); } /** @@ -74,47 +84,4 @@ protected function registerDateFactory() return new DateFactory($appTimezone, $cacheTimezone); }); } - - /** - * Register the credits class. - * - * @return void - */ - protected function registerCredits() - { - $this->app->singleton(Credits::class, function ($app) { - $cache = $app['cache.store']; - - return new Credits($cache); - }); - } - - /** - * Register the feed class. - * - * @return void - */ - protected function registerFeed() - { - $this->app->singleton(Feed::class, function ($app) { - $cache = $app['cache.store']; - - return new Feed($cache); - }); - } - - /** - * Register the releases class. - * - * @return void - */ - protected function registerReleases() - { - $this->app->singleton(Releases::class, function ($app) { - $cache = $app['cache.store']; - $token = $app['config']->get('services.github.token'); - - return new Releases($cache, $token); - }); - } } diff --git a/app/Providers/ComposerServiceProvider.php b/app/Providers/ComposerServiceProvider.php new file mode 100644 index 00000000000..d3a23d62c4c --- /dev/null +++ b/app/Providers/ComposerServiceProvider.php @@ -0,0 +1,62 @@ +composer('*', AppComposer::class); + $factory->composer('*', CurrentUserComposer::class); + $factory->composer(['index', 'single-incident', 'subscribe.*', 'signup', 'dashboard.settings.theme', 'notifications::email', 'single-schedule', 'errors.*'], ThemeComposer::class); + $factory->composer('dashboard.*', DashboardComposer::class); + $factory->composer(['setup.*', 'dashboard.settings.localization'], TimezoneLocaleComposer::class); + + $factory->composer('partials.modules.components', ComponentsComposer::class); + $factory->composer('partials.modules.metrics', MetricsComposer::class); + $factory->composer('partials.modules.stickied', StickiedComposer::class); + $factory->composer('partials.modules.scheduled', ScheduledComposer::class); + $factory->composer('partials.modules.status', StatusComposer::class); + $factory->composer('partials.modules.timeline', TimelineComposer::class); + $factory->composer(['dashboard.settings.mail', 'setup.*'], SettingsComposer::class); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + $this->app->singleton(DashboardComposer::class); + } +} diff --git a/app/Foundation/Providers/ConfigServiceProvider.php b/app/Providers/ConfigServiceProvider.php similarity index 76% rename from app/Foundation/Providers/ConfigServiceProvider.php rename to app/Providers/ConfigServiceProvider.php index f088cb4465d..7390f720d77 100644 --- a/app/Foundation/Providers/ConfigServiceProvider.php +++ b/app/Providers/ConfigServiceProvider.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Foundation\Providers; +namespace CachetHQ\Cachet\Providers; use CachetHQ\Cachet\Models\Setting as SettingModel; use CachetHQ\Cachet\Settings\Cache; @@ -23,7 +23,7 @@ * * @author James Brooks * @author Graham Campbell - * @author Joe Cohen + * @author Joseph Cohen */ class ConfigServiceProvider extends ServiceProvider { @@ -35,10 +35,9 @@ class ConfigServiceProvider extends ServiceProvider public function boot() { $env = $this->app->environment(); - $cli = $this->app->runningInConsole(); $repo = $this->app->make(Repository::class); $cache = $this->app->make(Cache::class); - $loaded = $cli ? false : $cache->load($env); + $loaded = $cache->load($env); $this->app->terminating(function () use ($repo, $cache) { if ($repo->stale()) { @@ -47,7 +46,7 @@ public function boot() }); try { - if ($cli === false && $loaded === false) { + if ($loaded === false) { $loaded = $repo->all(); $cache->store($env, $loaded); } @@ -59,20 +58,24 @@ public function boot() // } + // Set the app url. if ($appDomain = $this->app->config->get('setting.app_domain')) { $this->app->config->set('app.url', $appDomain); } + // Set the locale. if ($appLocale = $this->app->config->get('setting.app_locale')) { $this->app->config->set('app.locale', $appLocale); $this->app->translator->setLocale($appLocale); Date::setLocale($appLocale); } + // Set the timezone. if ($appTimezone = $this->app->config->get('setting.app_timezone')) { $this->app->config->set('cachet.timezone', $appTimezone); } + // Set allowed domains for CORS. $allowedOrigins = $this->app->config->get('cors.defaults.allowedOrigins'); if ($allowedDomains = $this->app->config->get('setting.allowed_domains')) { @@ -85,6 +88,23 @@ public function boot() } $this->app->config->set('cors.paths.api/v1/*.allowedOrigins', $allowedOrigins); + + // Set the mail from address. + if (!$this->app->config->get('mail.from.address')) { + $url = parse_url($appDomain); + + if (isset($url['host'])) { + $this->app->config->set('mail.from.address', "notify@{$url['host']}"); + } + } + + // Set the mail from name. + if (!$this->app->config->get('mail.from.name')) { + $this->app->config->set( + 'mail.from.name', + $this->app->config->get('setting.app_name', $this->app->config->get('app.name')) + ); + } } /** diff --git a/app/Foundation/Providers/ConsoleServiceProvider.php b/app/Providers/ConsoleServiceProvider.php similarity index 94% rename from app/Foundation/Providers/ConsoleServiceProvider.php rename to app/Providers/ConsoleServiceProvider.php index 54d2b92b983..6976453b5c8 100644 --- a/app/Foundation/Providers/ConsoleServiceProvider.php +++ b/app/Providers/ConsoleServiceProvider.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Foundation\Providers; +namespace CachetHQ\Cachet\Providers; use CachetHQ\Cachet\Subscribers\CommandSubscriber; use Illuminate\Support\ServiceProvider; diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php new file mode 100644 index 00000000000..792e2b8bbf7 --- /dev/null +++ b/app/Providers/EventServiceProvider.php @@ -0,0 +1,163 @@ + [ + 'CachetHQ\Cachet\Bus\Handlers\Events\ActionStorageHandler', + ], + 'CachetHQ\Cachet\Bus\Events\Beacon\BeaconFailedToSendEvent' => [ + 'CachetHQ\Cachet\Bus\Handlers\Events\Beacon\LogBeaconFailedHandler', + ], + 'CachetHQ\Cachet\Bus\Events\Beacon\BeaconWasSentEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\ComponentGroup\ComponentGroupWasCreatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\ComponentGroup\ComponentGroupWasRemovedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\ComponentGroup\ComponentGroupWasUpdatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Component\ComponentStatusWasChangedEvent' => [ + 'CachetHQ\Cachet\Bus\Handlers\Events\Component\SendComponentUpdateEmailNotificationHandler', + ], + 'CachetHQ\Cachet\Bus\Events\Component\ComponentWasCreatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Component\ComponentWasRemovedEvent' => [ + 'CachetHQ\Cachet\Bus\Handlers\Events\Component\CleanupComponentSubscriptionsHandler', + ], + 'CachetHQ\Cachet\Bus\Events\Component\ComponentWasUpdatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\IncidentUpdate\IncidentUpdateWasRemovedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\IncidentUpdate\IncidentUpdateWasReportedEvent' => [ + 'CachetHQ\Cachet\Bus\Handlers\Events\IncidentUpdate\SendIncidentUpdateEmailNotificationHandler', + ], + 'CachetHQ\Cachet\Bus\Events\IncidentUpdate\IncidentUpdateWasUpdatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Incident\IncidentWasCreatedEvent' => [ + 'CachetHQ\Cachet\Bus\Handlers\Events\Incident\SendIncidentEmailNotificationHandler', + ], + 'CachetHQ\Cachet\Bus\Events\Incident\IncidentWasRemovedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Incident\IncidentWasUpdatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Invite\InviteWasClaimedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Metric\MetricPointWasCreatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Metric\MetricPointWasRemovedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Metric\MetricPointWasUpdatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Metric\MetricWasCreatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Metric\MetricWasRemovedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Metric\MetricWasUpdatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Schedule\ScheduleWasCreatedEvent' => [ + 'CachetHQ\Cachet\Bus\Handlers\Events\Schedule\SendScheduleEmailNotificationHandler', + ], + 'CachetHQ\Cachet\Bus\Events\Schedule\ScheduleWasRemovedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Schedule\ScheduleWasUpdatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasSubscribedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasUnsubscribedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasUpdatedSubscriptionsEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\Subscriber\SubscriberHasVerifiedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\System\SystemCheckedForUpdatesEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\System\SystemWasInstalledEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\System\SystemWasResetEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\System\SystemWasUpdatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserAcceptedInviteEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserDisabledTwoAuthEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserEnabledTwoAuthEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserFailedTwoAuthEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserLoggedInEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserLoggedOutEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserPassedTwoAuthEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserRegeneratedApiTokenEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserWasCreatedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserWasInvitedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserWasRemovedEvent' => [ + // + ], + 'CachetHQ\Cachet\Bus\Events\User\UserWasWelcomedEvent' => [ + // + ], + ]; +} diff --git a/app/Providers/IntegrationServiceProvider.php b/app/Providers/IntegrationServiceProvider.php new file mode 100644 index 00000000000..57d27523cda --- /dev/null +++ b/app/Providers/IntegrationServiceProvider.php @@ -0,0 +1,120 @@ + + */ +class IntegrationServiceProvider extends ServiceProvider +{ + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + $this->registerBeacon(); + $this->registerCredits(); + $this->registerFeed(); + $this->registerSystem(); + + $this->registerReleases(); + } + + /** + * Register the beacon class. + * + * @return void + */ + protected function registerBeacon() + { + $this->app->singleton(BeaconContract::class, function ($app) { + $config = $app['config']; + + return new Beacon($config); + }); + } + + /** + * Register the credits class. + * + * @return void + */ + protected function registerCredits() + { + $this->app->singleton(CreditsContract::class, function ($app) { + $cache = $app['cache.store']; + + return new Credits($cache); + }); + } + + /** + * Register the feed class. + * + * @return void + */ + protected function registerFeed() + { + $this->app->singleton(FeedContract::class, function ($app) { + $cache = $app['cache.store']; + + return new Feed($cache); + }); + } + + /** + * Register the system class. + * + * @return void + */ + protected function registerSystem() + { + $this->app->singleton(SystemContract::class, function (Container $app) { + $config = $app['config']; + $auth = $app['auth.driver']; + + return new System($config, $auth); + }); + } + + /** + * Register the releases class. + * + * @return void + */ + protected function registerReleases() + { + $this->app->singleton(ReleasesContract::class, function ($app) { + $cache = $app['cache.store']; + $token = $app['config']->get('services.github.token'); + + return new Releases($cache, $token); + }); + } +} diff --git a/app/Foundation/Providers/RepositoryServiceProvider.php b/app/Providers/RepositoryServiceProvider.php similarity index 62% rename from app/Foundation/Providers/RepositoryServiceProvider.php rename to app/Providers/RepositoryServiceProvider.php index 56afc6a1656..550aa17f1b3 100644 --- a/app/Foundation/Providers/RepositoryServiceProvider.php +++ b/app/Providers/RepositoryServiceProvider.php @@ -9,13 +9,13 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Foundation\Providers; +namespace CachetHQ\Cachet\Providers; -use CachetHQ\Cachet\Dates\DateFactory; use CachetHQ\Cachet\Repositories\Metric\MetricRepository; -use CachetHQ\Cachet\Repositories\Metric\MySqlRepository as MetricMySqlRepository; -use CachetHQ\Cachet\Repositories\Metric\PgSqlRepository as MetricPgSqlRepository; -use CachetHQ\Cachet\Repositories\Metric\SqliteRepository as MetricSqliteRepository; +use CachetHQ\Cachet\Repositories\Metric\MySqlRepository; +use CachetHQ\Cachet\Repositories\Metric\PgSqlRepository; +use CachetHQ\Cachet\Repositories\Metric\SqliteRepository; +use CachetHQ\Cachet\Services\Dates\DateFactory; use Illuminate\Contracts\Config\Repository as ConfigRepository; use Illuminate\Contracts\Container\Container; use Illuminate\Support\ServiceProvider; @@ -46,14 +46,14 @@ protected function registerMetricRepository() { $this->app->singleton(MetricRepository::class, function (Container $app) { $config = $app->make(ConfigRepository::class); - $driver = $config->get('database.default'); - if ($driver == 'mysql') { - $repository = new MetricMySqlRepository($config); - } elseif ($driver == 'pgsql') { - $repository = new MetricPgSqlRepository($config); - } elseif ($driver == 'sqlite') { - $repository = new MetricSqliteRepository($config); + switch ($config->get('database.default')) { + case 'mysql': $repository = new MySqlRepository($config); + break; + case 'pgsql': $repository = new PgSqlRepository($config); + break; + case 'sqlite': $repository = new SqliteRepository($config); + break; } $dates = $app->make(DateFactory::class); diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php new file mode 100644 index 00000000000..f23d7a023da --- /dev/null +++ b/app/Providers/RouteServiceProvider.php @@ -0,0 +1,207 @@ + + * @author Joseph Cohen + * @author Graham Campbell + */ +class RouteServiceProvider extends ServiceProvider +{ + /** + * This namespace is applied to your controller routes. + * + * In addition, it is set as the URL generator's root namespace. + * + * @var string + */ + protected $namespace = 'CachetHQ\Cachet\Http\Controllers'; + + /** + * These are the route files that should always be available anonymously. + * + * When applying the always_authenticate feature, these routes will be skipped. + * + * @var string[] + */ + protected $whitelistedAuthRoutes = [ + AuthRoutes::class, + SetupRoutes::class, + SignupRoutes::class, + ApiSystemRoutes::class, + ApiSetupRoutes::class, + ]; + + /** + * Define the route model bindings, pattern filters, etc. + * + * @return void + */ + public function boot() + { + parent::boot(); + + $this->app->call([$this, 'bind']); + } + + /** + * Define the bindings for the application. + * + * @param \Illuminate\Routing\Router $router + * + * @return void + */ + public function bind(Router $router) + { + $router->model('component', 'CachetHQ\Cachet\Models\Component'); + $router->model('component_group', 'CachetHQ\Cachet\Models\ComponentGroup'); + $router->model('incident', 'CachetHQ\Cachet\Models\Incident'); + $router->model('incident_template', 'CachetHQ\Cachet\Models\IncidentTemplate'); + $router->model('incident_update', 'CachetHQ\Cachet\Models\IncidentUpdate'); + $router->model('metric', 'CachetHQ\Cachet\Models\Metric'); + $router->model('metric_point', 'CachetHQ\Cachet\Models\MetricPoint'); + $router->model('schedule', 'CachetHQ\Cachet\Models\Schedule'); + $router->model('setting', 'CachetHQ\Cachet\Models\Setting'); + $router->model('subscriber', 'CachetHQ\Cachet\Models\Subscriber'); + $router->model('subscription', 'CachetHQ\Cachet\Models\Subscription'); + $router->model('tag', 'CachetHQ\Cachet\Models\Tag'); + $router->model('user', 'CachetHQ\Cachet\Models\User'); + } + + /** + * Define the routes for the application. + * + * @param \Illuminate\Routing\Router $router + * + * @return void + */ + public function map(Router $router) + { + $router->group(['namespace' => $this->namespace, 'as' => 'core::'], function (Router $router) { + $path = app_path('Http/Routes'); + + $applyAlwaysAuthenticate = $this->app['config']->get('setting.always_authenticate', false); + $AllFileIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path)); + $PhpFileIterator = new \RegexIterator($AllFileIterator, '/^.+\.php$/i', \RecursiveRegexIterator::GET_MATCH); + + foreach ($PhpFileIterator as $file => $object) { + $class = substr($file, strlen($path)); + $class = str_replace('/', '\\', $class); + $class = substr($class, 0, -4); + + $routes = $this->app->make("CachetHQ\\Cachet\\Http\\Routes${class}"); + + if ($routes::$browser) { + $this->mapForBrowser($router, $routes, $applyAlwaysAuthenticate); + } else { + $this->mapOtherwise($router, $routes, $applyAlwaysAuthenticate); + } + } + }); + } + + /** + * Wrap the routes in the browser specific middleware. + * + * @param \Illuminate\Routing\Router $router + * @param object $routes + * @param bool $applyAlwaysAuthenticate + * + * @return void + */ + protected function mapForBrowser(Router $router, $routes, $applyAlwaysAuthenticate) + { + $middleware = [ + EncryptCookies::class, + AddQueuedCookiesToResponse::class, + StartSession::class, + ShareErrorsFromSession::class, + VerifyCsrfToken::class, + SubstituteBindings::class, + ]; + + if ($applyAlwaysAuthenticate && !$this->isWhiteListedAuthRoute($routes)) { + $middleware[] = RemoteUserAuthenticate::class; + $middleware[] = Authenticate::class; + } + + $router->group(['middleware' => $middleware], function (Router $router) use ($routes) { + $routes->map($router); + }); + } + + /** + * Wrap the routes in the basic middleware. + * + * @param \Illuminate\Routing\Router $router + * @param object $routes + * @param bool $applyAlwaysAuthenticate + * + * @return void + */ + protected function mapOtherwise(Router $router, $routes, $applyAlwaysAuthenticate) + { + $middleware = [ + SubstituteBindings::class, + Acceptable::class, + Timezone::class, + ]; + + if ($applyAlwaysAuthenticate && !$this->isWhiteListedAuthRoute($routes)) { + $middleware[] = 'auth.api:true'; + } + + $router->group(['middleware' => $middleware], function (Router $router) use ($routes) { + $routes->map($router); + }); + } + + /** + * Validates if the route object is an instance of the whitelisted routes. + * A small workaround since we cant use multiple classes in a `instanceof` comparison. + * + * @param object $routes + * + * @return bool + */ + private function isWhiteListedAuthRoute($routes) + { + foreach ($this->whitelistedAuthRoutes as $whitelistedRoute) { + if (is_a($routes, $whitelistedRoute)) { + return true; + } + } + + return false; + } +} diff --git a/app/Repositories/Metric/AbstractMetricRepository.php b/app/Repositories/Metric/AbstractMetricRepository.php index c781d281a39..566827e6661 100644 --- a/app/Repositories/Metric/AbstractMetricRepository.php +++ b/app/Repositories/Metric/AbstractMetricRepository.php @@ -11,8 +11,10 @@ namespace CachetHQ\Cachet\Repositories\Metric; +use CachetHQ\Cachet\Integrations\Contracts\System; use CachetHQ\Cachet\Models\Metric; use Illuminate\Contracts\Config\Repository; +use Illuminate\Support\Collection; /** * This is the abstract metric repository class. @@ -52,12 +54,67 @@ public function __construct(Repository $config) * * @return string */ - protected function getTableName() + protected function getMetricsTable() { - $driver = $this->config->get('database.default'); - $connection = $this->config->get('database.connections.'.$driver); - $prefix = $connection['prefix']; + $prefix = app(System::class)->getTablePrefix(); return $prefix.'metrics'; } + + /** + * Get the metric points table name. + * + * @return string + */ + protected function getMetricPointsTable() + { + $prefix = app(System::class)->getTablePrefix(); + + return $prefix.'metric_points'; + } + + /** + * Return the query type. + * + * @param \CachetHQ\Cachet\Models\Metric $metric + * + * @return string + */ + protected function getQueryType(Metric $metric) + { + if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { + return "sum({$this->getMetricPointsTable()}.value * {$this->getMetricPointsTable()}.counter) AS value"; + } elseif ($metric->calc_type == Metric::CALC_AVG) { + return "avg({$this->getMetricPointsTable()}.value) AS value"; + } else { + return "sum({$this->getMetricPointsTable()}.value * {$this->getMetricPointsTable()}.counter) AS value"; + } + } + + /** + * Map the result set. + * + * @param \CachetHQ\Cachet\Models\Metric $metric + * @param array $results + * + * @return \Illuminate\Support\Collection + */ + protected function mapResults(Metric $metric, array $results) + { + $results = Collection::make($results); + + return $results->map(function ($point) use ($metric) { + if (!$point->value) { + $point->value = $metric->default_value; + } + + if ($point->value === 0 && $metric->default_value != $point->value) { + $point->value = $metric->default_value; + } + + $point->value = round($point->value, $metric->places); + + return $point; + }); + } } diff --git a/app/Repositories/Metric/MetricInterface.php b/app/Repositories/Metric/MetricInterface.php index b355192f4c3..ec0cb163452 100644 --- a/app/Repositories/Metric/MetricInterface.php +++ b/app/Repositories/Metric/MetricInterface.php @@ -13,36 +13,40 @@ use CachetHQ\Cachet\Models\Metric; +/** + * This is the metric interface. + * + * @author James Brooks + */ interface MetricInterface { /** - * Returns metrics for the last hour. + * Returns metrics since given minutes. * * @param \CachetHQ\Cachet\Models\Metric $metric - * @param int $hour - * @param int $minute + * @param int $minutes * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsLastHour(Metric $metric, $hour, $minute); + public function getPointsSinceMinutes(Metric $metric, $minutes); /** - * Returns metrics for a given hour. + * Returns metrics since given hour. * * @param \CachetHQ\Cachet\Models\Metric $metric * @param int $hour * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsByHour(Metric $metric, $hour); + public function getPointsSinceHour(Metric $metric, $hour); /** - * Returns metrics for the week. + * Returns metrics since given day. * * @param \CachetHQ\Cachet\Models\Metric $metric * @param int $day * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsForDayInWeek(Metric $metric, $day); + public function getPointsSinceDay(Metric $metric, $day); } diff --git a/app/Repositories/Metric/MetricRepository.php b/app/Repositories/Metric/MetricRepository.php index 315ffc6e228..c424336b19c 100644 --- a/app/Repositories/Metric/MetricRepository.php +++ b/app/Repositories/Metric/MetricRepository.php @@ -11,10 +11,15 @@ namespace CachetHQ\Cachet\Repositories\Metric; -use CachetHQ\Cachet\Dates\DateFactory; use CachetHQ\Cachet\Models\Metric; +use CachetHQ\Cachet\Services\Dates\DateFactory; use DateInterval; +/** + * This is the metric repository class. + * + * @author James Brooks + */ class MetricRepository { /** @@ -27,7 +32,7 @@ class MetricRepository /** * The date factory instance. * - * @var \CachetHQ\Cachet\Dates\DateFactory + * @var \CachetHQ\Cachet\Services\Dates\DateFactory */ protected $dates; @@ -35,7 +40,7 @@ class MetricRepository * Create a new metric repository class. * * @param \CachetHQ\Cachet\Repositories\Metric\MetricInterface $repository - * @param \CachetHQ\Cachet\Dates\DateFactory $dates + * @param \CachetHQ\Cachet\Services\Dates\DateFactory $dates * * @return void */ @@ -50,22 +55,41 @@ public function __construct(MetricInterface $repository, DateFactory $dates) * * @param \CachetHQ\Cachet\Models\Metric $metric * - * @return array + * @return \Illuminate\Support\Collection */ public function listPointsLastHour(Metric $metric) { $dateTime = $this->dates->make(); - - $points = []; - - $pointKey = $dateTime->format('H:i'); - - for ($i = 0; $i <= 60; $i++) { - $points[$pointKey] = $this->repository->getPointsLastHour($metric, 0, $i); - $pointKey = $dateTime->sub(new DateInterval('PT1M'))->format('H:i'); + $pointKey = $dateTime->format('Y-m-d H:i'); + $nrOfMinutes = 61; + $points = $this->repository->getPointsSinceMinutes($metric, $nrOfMinutes + $metric->threshold)->pluck('value', 'key')->take(-$nrOfMinutes); + + $timeframe = $nrOfMinutes; + + //Settings counter for minutes without data + $minutesWithNoData = 0; + + for ($i = 0; $i < $timeframe; $i++) { + if (!$points->has($pointKey)) { + if ($i >= $metric->threshold) { + $points->put($pointKey, $metric->default_value); + //We put default value as metric, so we can reset counter for minutes without data + $minutesWithNoData = 0; + } else { + //We didn't find any data, but threshold is not meet yet so we just adding to counter + $minutesWithNoData++; + } + } else { + //We found data within this threshold, zeroing counter + $minutesWithNoData = 0; + } + + $pointKey = $dateTime->sub(new DateInterval('PT1M'))->format('Y-m-d H:i'); } - return array_reverse($points); + return $points->sortBy(function ($point, $key) { + return $key; + }); } /** @@ -79,17 +103,20 @@ public function listPointsLastHour(Metric $metric) public function listPointsToday(Metric $metric, $hours = 12) { $dateTime = $this->dates->make(); + $pointKey = $dateTime->format('Y-m-d H:00'); + $points = $this->repository->getPointsSinceHour($metric, $hours)->pluck('value', 'key'); - $points = []; - - $pointKey = $dateTime->format('H:00'); + for ($i = 0; $i < $hours; $i++) { + if (!$points->has($pointKey)) { + $points->put($pointKey, $metric->default_value); + } - for ($i = 0; $i <= $hours; $i++) { - $points[$pointKey] = $this->repository->getPointsByHour($metric, $i); - $pointKey = $dateTime->sub(new DateInterval('PT1H'))->format('H:00'); + $pointKey = $dateTime->sub(new DateInterval('PT1H'))->format('Y-m-d H:00'); } - return array_reverse($points); + return $points->sortBy(function ($point, $key) { + return $key; + }); } /** @@ -102,17 +129,20 @@ public function listPointsToday(Metric $metric, $hours = 12) public function listPointsForWeek(Metric $metric) { $dateTime = $this->dates->make(); - - $points = []; - - $pointKey = $dateTime->format('D jS M'); + $pointKey = $dateTime->format('Y-m-d'); + $points = $this->repository->getPointsSinceDay($metric, 7)->pluck('value', 'key'); for ($i = 0; $i <= 7; $i++) { - $points[$pointKey] = $this->repository->getPointsForDayInWeek($metric, $i); - $pointKey = $dateTime->sub(new DateInterval('P1D'))->format('D jS M'); + if (!$points->has($pointKey)) { + $points->put($pointKey, $metric->default_value); + } + + $pointKey = $dateTime->sub(new DateInterval('P1D'))->format('Y-m-d'); } - return array_reverse($points); + return $points->sortBy(function ($point, $key) { + return $key; + }); } /** @@ -125,18 +155,20 @@ public function listPointsForWeek(Metric $metric) public function listPointsForMonth(Metric $metric) { $dateTime = $this->dates->make(); - + $pointKey = $dateTime->format('Y-m-d'); $daysInMonth = $dateTime->format('t'); - - $points = []; - - $pointKey = $dateTime->format('jS M'); + $points = $this->repository->getPointsSinceDay($metric, $daysInMonth)->pluck('value', 'key'); for ($i = 0; $i <= $daysInMonth; $i++) { - $points[$pointKey] = $this->repository->getPointsForDayInWeek($metric, $i); - $pointKey = $dateTime->sub(new DateInterval('P1D'))->format('jS M'); + if (!$points->has($pointKey)) { + $points->put($pointKey, $metric->default_value); + } + + $pointKey = $dateTime->sub(new DateInterval('P1D'))->format('Y-m-d'); } - return array_reverse($points); + return $points->sortBy(function ($point, $key) { + return $key; + }); } } diff --git a/app/Repositories/Metric/MySqlRepository.php b/app/Repositories/Metric/MySqlRepository.php index a9cca0861a8..3d5e37159dd 100644 --- a/app/Repositories/Metric/MySqlRepository.php +++ b/app/Repositories/Metric/MySqlRepository.php @@ -12,9 +12,7 @@ namespace CachetHQ\Cachet\Repositories\Metric; use CachetHQ\Cachet\Models\Metric; -use DateInterval; use Illuminate\Support\Facades\DB; -use Jenssegers\Date\Date; /** * This is the mysql repository class. @@ -24,112 +22,76 @@ class MySqlRepository extends AbstractMetricRepository implements MetricInterface { /** - * Returns metrics for the last hour. + * Returns metrics since given minutes. * * @param \CachetHQ\Cachet\Models\Metric $metric - * @param int $hour - * @param int $minute + * @param int $minutes * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsLastHour(Metric $metric, $hour, $minute) + public function getPointsSinceMinutes(Metric $metric, $minutes) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M')); - $timeInterval = $dateTime->format('YmdHi'); - - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`'; - } - - $value = 0; - - $points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND DATE_FORMAT(mp.`created_at`, '%Y%m%d%H%i') = :timeInterval GROUP BY HOUR(mp.`created_at`), MINUTE(mp.`created_at`)", [ - 'metricId' => $metric->id, - 'timeInterval' => $timeInterval, - ]); - - if (isset($points[0]) && !($value = $points[0]->value)) { - $value = 0; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + $queryType = $this->getQueryType($metric); + + $points = DB::select("SELECT DATE_FORMAT({$this->getMetricPointsTable()}.`created_at`, '%Y-%m-%d %H:%i') AS `key`, {$queryType} ". + "FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON {$this->getMetricsTable()}.id = {$this->getMetricPointsTable()}.metric_id ". + "WHERE {$this->getMetricsTable()}.id = :metricId ". + "AND {$this->getMetricPointsTable()}.`created_at` >= DATE_SUB(NOW(), INTERVAL :minutes MINUTE) ". + "AND {$this->getMetricPointsTable()}.`created_at` <= NOW() ". + "GROUP BY HOUR({$this->getMetricPointsTable()}.`created_at`), MINUTE({$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, + 'minutes' => $minutes, + ]); + + return $this->mapResults($metric, $points); } /** - * Returns metrics for a given hour. + * Returns metrics since given hour. * * @param \CachetHQ\Cachet\Models\Metric $metric * @param int $hour * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsByHour(Metric $metric, $hour) + public function getPointsSinceHour(Metric $metric, $hour) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H')); - $hourInterval = $dateTime->format('YmdH'); - - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`'; - } - - $value = 0; - - $points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND DATE_FORMAT(mp.`created_at`, '%Y%m%d%H') = :hourInterval GROUP BY HOUR(mp.`created_at`)", [ - 'metricId' => $metric->id, - 'hourInterval' => $hourInterval, - ]); - - if (isset($points[0]) && !($value = $points[0]->value)) { - $value = 0; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT DATE_FORMAT({$this->getMetricPointsTable()}.`created_at`, '%Y-%m-%d %H:00') AS `key`, {$queryType} ". + "FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON {$this->getMetricsTable()}.id = {$this->getMetricPointsTable()}.metric_id ". + "WHERE {$this->getMetricsTable()}.id = :metricId ". + "AND {$this->getMetricPointsTable()}.`created_at` >= DATE_SUB(NOW(), INTERVAL :hour HOUR) ". + "AND {$this->getMetricPointsTable()}.`created_at` <= NOW() ". + "GROUP BY HOUR({$this->getMetricPointsTable()}.`created_at`) ". + "ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, + 'hour' => $hour, + ]); + + return $this->mapResults($metric, $points); } /** - * Returns metrics for the week. + * Returns metrics since given day. * * @param \CachetHQ\Cachet\Models\Metric $metric + * @param int $day * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsForDayInWeek(Metric $metric, $day) + public function getPointsSinceDay(Metric $metric, $day) { - $dateTime = (new Date())->sub(new DateInterval('P'.$day.'D')); - - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'SUM(mp.`value` * mp.`counter`) AS `value`'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'AVG(mp.`value` * mp.`counter`) AS `value`'; - } - - $value = 0; - - $points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND mp.`created_at` BETWEEN DATE_SUB(mp.`created_at`, INTERVAL 1 WEEK) AND DATE_ADD(NOW(), INTERVAL 1 DAY) AND DATE_FORMAT(mp.`created_at`, '%Y%m%d') = :timeInterval GROUP BY DATE_FORMAT(mp.`created_at`, '%Y%m%d')", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('Ymd'), - ]); - - if (isset($points[0]) && !($value = $points[0]->value)) { - $value = 0; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT DATE_FORMAT({$this->getMetricPointsTable()}.`created_at`, '%Y-%m-%d') AS `key`, {$queryType} ". + "FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON {$this->getMetricsTable()}.id = {$this->getMetricPointsTable()}.metric_id ". + "WHERE {$this->getMetricsTable()}.id = :metricId ". + "AND {$this->getMetricPointsTable()}.`created_at` >= DATE_SUB(NOW(), INTERVAL :day DAY) ". + "AND {$this->getMetricPointsTable()}.`created_at` <= NOW() ". + "GROUP BY DATE({$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, + 'day' => $day, + ]); + + return $this->mapResults($metric, $points); } } diff --git a/app/Repositories/Metric/PgSqlRepository.php b/app/Repositories/Metric/PgSqlRepository.php index 739c543b0a0..c8d135c6317 100644 --- a/app/Repositories/Metric/PgSqlRepository.php +++ b/app/Repositories/Metric/PgSqlRepository.php @@ -12,9 +12,7 @@ namespace CachetHQ\Cachet\Repositories\Metric; use CachetHQ\Cachet\Models\Metric; -use DateInterval; use Illuminate\Support\Facades\DB; -use Jenssegers\Date\Date; /** * This is the pgsql repository class. @@ -24,113 +22,74 @@ class PgSqlRepository extends AbstractMetricRepository implements MetricInterface { /** - * Returns metrics for the last hour. + * Returns metrics since given minutes. * * @param \CachetHQ\Cachet\Models\Metric $metric - * @param int $hour - * @param int $minute + * @param int $minutes * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsLastHour(Metric $metric, $hour, $minute) + public function getPointsSinceMinutes(Metric $metric, $minutes) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M')); - - // Default metrics calculations. - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(metric_points.value * metric_points.counter)'; - } else { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } - - $value = 0; - $query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND to_char(metric_points.created_at, 'YYYYMMDDHH24MI') = :timeInterval GROUP BY to_char(metric_points.created_at, 'HHMI')", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('YmdHi'), - ]); - - if (isset($query[0])) { - $value = $query[0]->value; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT to_char({$this->getMetricPointsTable()}.created_at, 'YYYY-MM-DD HH24:MI') AS key, {$queryType} ". + "FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON {$this->getMetricsTable()}.id = {$this->getMetricPointsTable()}.metric_id ". + "WHERE {$this->getMetricsTable()}.id = :metricId ". + "AND {$this->getMetricPointsTable()}.created_at >= (NOW() - INTERVAL '{$minutes}' MINUTE) ". + "AND {$this->getMetricPointsTable()}.created_at <= NOW() ". + "GROUP BY to_char({$this->getMetricPointsTable()}.created_at, 'YYYY-MM-DD HH24:MI') ". + "ORDER BY to_char({$this->getMetricPointsTable()}.created_at, 'YYYY-MM-DD HH24:MI')", [ + 'metricId' => $metric->id, + ]); + + return $this->mapResults($metric, $points); } /** - * Returns metrics for a given hour. + * Returns metrics since given hour. * * @param \CachetHQ\Cachet\Models\Metric $metric * @param int $hour * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsByHour(Metric $metric, $hour) + public function getPointsSinceHour(Metric $metric, $hour) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H')); - - // Default metrics calculations. - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(metric_points.value * metric_points.counter)'; - } else { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } - - $value = 0; - $query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE metric_points.metric_id = :metricId AND to_char(metric_points.created_at, 'YYYYMMDDHH24') = :timeInterval GROUP BY to_char(metric_points.created_at, 'H')", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('YmdH'), - ]); - - if (isset($query[0])) { - $value = $query[0]->value; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT to_char({$this->getMetricPointsTable()}.created_at, 'YYYY-MM-DD HH24:00') AS key, {$queryType} ". + "FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON {$this->getMetricsTable()}.id = {$this->getMetricPointsTable()}.metric_id ". + "WHERE {$this->getMetricsTable()}.id = :metricId ". + "AND {$this->getMetricPointsTable()}.created_at >= (NOW() - INTERVAL '{$hour}' HOUR) ". + "AND {$this->getMetricPointsTable()}.created_at <= NOW() ". + "GROUP BY to_char({$this->getMetricPointsTable()}.created_at, 'YYYY-MM-DD HH24:00') ". + "ORDER BY to_char({$this->getMetricPointsTable()}.created_at, 'YYYY-MM-DD HH24:00')", [ + 'metricId' => $metric->id, + ]); + + return $this->mapResults($metric, $points); } /** - * Returns metrics for the week. + * Returns metrics since given day. * * @param \CachetHQ\Cachet\Models\Metric $metric + * @param int $day * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsForDayInWeek(Metric $metric, $day) + public function getPointsSinceDay(Metric $metric, $day) { - $dateTime = (new Date())->sub(new DateInterval('P'.$day.'D')); - - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(mp.value * mp.counter) AS value'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(mp.value * mp.counter) AS value'; - } - - $value = 0; - $points = DB::select("SELECT {$queryType} FROM {$this->getTableName()} m INNER JOIN metric_points mp ON m.id = mp.metric_id WHERE m.id = :metricId AND mp.created_at BETWEEN (mp.created_at - interval '1 week') AND (now() + interval '1 day') AND to_char(mp.created_at, 'YYYYMMDD') = :timeInterval GROUP BY to_char(mp.created_at, 'YYYYMMDD')", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('Ymd'), - ]); - - if (isset($points[0]) && !($value = $points[0]->value)) { - $value = 0; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT to_char({$this->getMetricPointsTable()}.created_at, 'YYYY-MM-DD HH24:00') AS key, {$queryType} ". + "FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON {$this->getMetricsTable()}.id = {$this->getMetricPointsTable()}.metric_id ". + "WHERE {$this->getMetricsTable()}.id = :metricId ". + "AND {$this->getMetricPointsTable()}.created_at >= (DATE(NOW()) - INTERVAL '{$day}' DAY) ". + "AND {$this->getMetricPointsTable()}.created_at <= DATE(NOW()) ". + "GROUP BY to_char({$this->getMetricPointsTable()}.created_at, 'YYYY-MM-DD HH24:00')". + "ORDER BY to_char({$this->getMetricPointsTable()}.created_at, 'YYYY-MM-DD HH24:00')", [ + 'metricId' => $metric->id, + ]); + + return $this->mapResults($metric, $points); } } diff --git a/app/Repositories/Metric/SqliteRepository.php b/app/Repositories/Metric/SqliteRepository.php index 403d776110a..d979e084ac6 100644 --- a/app/Repositories/Metric/SqliteRepository.php +++ b/app/Repositories/Metric/SqliteRepository.php @@ -12,123 +12,84 @@ namespace CachetHQ\Cachet\Repositories\Metric; use CachetHQ\Cachet\Models\Metric; -use DateInterval; use Illuminate\Support\Facades\DB; -use Jenssegers\Date\Date; +/** + * This is the sqlite repository class. + * + * @author James Brooks + */ class SqliteRepository extends AbstractMetricRepository implements MetricInterface { /** - * Returns metrics for the last hour. + * Returns metrics since given minutes. * * @param \CachetHQ\Cachet\Models\Metric $metric - * @param int $hour - * @param int $minute + * @param int $minutes * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsLastHour(Metric $metric, $hour, $minute) + public function getPointsSinceMinutes(Metric $metric, $minutes) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H'))->sub(new DateInterval('PT'.$minute.'M')); - - // Default metrics calculations. - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(metric_points.value * metric_points.counter)'; - } else { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } - - $value = 0; - $query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND strftime('%Y%m%d%H%M', metric_points.created_at) = :timeInterval GROUP BY strftime('%H%M', metric_points.created_at)", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('YmdHi'), - ]); - - if (isset($query[0])) { - $value = $query[0]->value; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT strftime('%Y-%m-%d %H:%M', {$this->getMetricPointsTable()}.`created_at`) AS `key`, {$queryType} ". + "FROM {$this->getMetricsTable()} ". + "INNER JOIN {$this->getMetricPointsTable()} ON {$this->getMetricsTable()}.id = {$this->getMetricPointsTable()}.metric_id ". + "WHERE {$this->getMetricsTable()}.id = :metricId ". + "AND {$this->getMetricPointsTable()}.`created_at` >= datetime('now', 'localtime', '-{$minutes} minutes') ". + "AND {$this->getMetricPointsTable()}.`created_at` <= datetime('now', 'localtime') ". + "GROUP BY strftime('%H', {$this->getMetricPointsTable()}.`created_at`), strftime('%M', {$this->getMetricPointsTable()}.`created_at`) ". + "ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, + ]); + + return $this->mapResults($metric, $points); } /** - * Returns metrics for a given hour. + * Returns metrics since given hour. * * @param \CachetHQ\Cachet\Models\Metric $metric * @param int $hour * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsByHour(Metric $metric, $hour) + public function getPointsSinceHour(Metric $metric, $hour) { - $dateTime = (new Date())->sub(new DateInterval('PT'.$hour.'H')); - - // Default metrics calculations. - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(metric_points.value * metric_points.counter)'; - } else { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } - - $value = 0; - $query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND strftime('%Y%m%d%H', metric_points.created_at) = :timeInterval GROUP BY strftime('%H', metric_points.created_at)", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('YmdH'), - ]); - - if (isset($query[0])) { - $value = $query[0]->value; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT strftime('%Y-%m-%d %H:00', {$this->getMetricPointsTable()}.`created_at`) AS `key`, {$queryType} ". + "FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON {$this->getMetricsTable()}.id = {$this->getMetricPointsTable()}.metric_id ". + "WHERE {$this->getMetricsTable()}.id = :metricId ". + "AND {$this->getMetricPointsTable()}.`created_at` >= datetime('now', 'localtime', '-{$hour} hours') ". + "AND {$this->getMetricPointsTable()}.`created_at` <= datetime('now', 'localtime') ". + "GROUP BY strftime('%H', {$this->getMetricPointsTable()}.`created_at`) ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, + ]); + + return $this->mapResults($metric, $points); } /** - * Returns metrics for the week. + * Returns metrics since given day. * * @param \CachetHQ\Cachet\Models\Metric $metric + * @param int $day * - * @return int + * @return \Illuminate\Support\Collection */ - public function getPointsForDayInWeek(Metric $metric, $day) + public function getPointsSinceDay(Metric $metric, $day) { - $dateTime = (new Date())->sub(new DateInterval('P'.$day.'D')); - - // Default metrics calculations. - if (!isset($metric->calc_type) || $metric->calc_type == Metric::CALC_SUM) { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } elseif ($metric->calc_type == Metric::CALC_AVG) { - $queryType = 'avg(metric_points.value * metric_points.counter)'; - } else { - $queryType = 'sum(metric_points.value * metric_points.counter)'; - } - - $value = 0; - $query = DB::select("select {$queryType} as value FROM {$this->getTableName()} m JOIN metric_points ON metric_points.metric_id = m.id WHERE m.id = :metricId AND metric_points.created_at > date('now', '-7 day') AND strftime('%Y%m%d', metric_points.created_at) = :timeInterval GROUP BY strftime('%Y%m%d', metric_points.created_at)", [ - 'metricId' => $metric->id, - 'timeInterval' => $dateTime->format('Ymd'), - ]); - - if (isset($query[0])) { - $value = $query[0]->value; - } - - if ($value === 0 && $metric->default_value != $value) { - return $metric->default_value; - } - - return round($value, $metric->places); + $queryType = $this->getQueryType($metric); + $points = DB::select("SELECT strftime('%Y-%m-%d', {$this->getMetricPointsTable()}.`created_at`) AS `key`, {$queryType} ". + "FROM {$this->getMetricsTable()} INNER JOIN {$this->getMetricPointsTable()} ON {$this->getMetricsTable()}.id = {$this->getMetricPointsTable()}.metric_id ". + "WHERE {$this->getMetricsTable()}.id = :metricId ". + "AND {$this->getMetricPointsTable()}.`created_at` >= datetime('now', 'localtime', '-{$day} days') ". + "AND {$this->getMetricPointsTable()}.`created_at` <= datetime('now', 'localtime') ". + "GROUP BY DATE({$this->getMetricPointsTable()}.`created_at`) ". + "ORDER BY {$this->getMetricPointsTable()}.`created_at`", [ + 'metricId' => $metric->id, + ]); + + return $this->mapResults($metric, $points); } } diff --git a/app/Dates/DateFactory.php b/app/Services/Dates/DateFactory.php similarity index 80% rename from app/Dates/DateFactory.php rename to app/Services/Dates/DateFactory.php index d2e0ca45341..4ccbcb493d4 100644 --- a/app/Dates/DateFactory.php +++ b/app/Services/Dates/DateFactory.php @@ -9,10 +9,17 @@ * file that was distributed with this source code. */ -namespace CachetHQ\Cachet\Dates; +namespace CachetHQ\Cachet\Services\Dates; +use DateTimeZone; use Jenssegers\Date\Date; +/** + * This is the date factory class. + * + * @author Graham Campbell + * @author James Brooks + */ class DateFactory { /** @@ -88,4 +95,17 @@ public function make($time = null) { return (new Date($time))->setTimezone($this->cachetTimezone); } + + /** + * Return the abbreviated timezone. + * + * @return string + */ + public function getTimezone() + { + $dateTime = new Date(); + $dateTime->setTimeZone(new DateTimeZone($this->cachetTimezone)); + + return $dateTime->format('T'); + } } diff --git a/app/Settings/ReadException.php b/app/Settings/ReadException.php new file mode 100644 index 00000000000..86de0ae3f9e --- /dev/null +++ b/app/Settings/ReadException.php @@ -0,0 +1,34 @@ + + */ +class ReadException extends SettingsException +{ + /** + * Create a new read exception instance. + * + * @param \Exception $e + * + * @return void + */ + public function __construct(Exception $e) + { + parent::__construct('Unable to read Cachet settings', $e); + } +} diff --git a/app/Settings/Repository.php b/app/Settings/Repository.php index edd5103e3d1..e6d54038ee3 100644 --- a/app/Settings/Repository.php +++ b/app/Settings/Repository.php @@ -12,6 +12,7 @@ namespace CachetHQ\Cachet\Settings; use CachetHQ\Cachet\Models\Setting; +use Exception; /** * This is the settings repository class. @@ -21,6 +22,15 @@ */ class Repository { + /** + * Array of numerical settings that are not bools. + * + * @var string[] + */ + protected $notBooleans = [ + 'app_incident_days', + ]; + /** * The eloquent model instance. * @@ -50,11 +60,19 @@ public function __construct(Setting $model) /** * Returns a setting from the database. * + * @throws \CachetHQ\Cachet\Settings\ReadException + * * @return array */ public function all() { - return $this->model->all(['name', 'value'])->pluck('value', 'name')->toArray(); + try { + return $this->model->all(['name', 'value'])->pluck('value', 'name')->map(function ($value, $name) { + return $this->castSetting($name, $value); + })->toArray(); + } catch (Exception $e) { + throw new ReadException($e); + } } /** @@ -63,16 +81,45 @@ public function all() * @param string $name * @param string|null $value * + * @throws \CachetHQ\Cachet\Settings\WriteException + * * @return void */ public function set($name, $value) { $this->stale = true; - if ($value === null) { - $this->model->where('name', $name)->delete(); - } else { - $this->model->updateOrCreate(compact('name'), compact('value')); + try { + if ($value === null) { + $this->model->where('name', '=', $name)->delete(); + } else { + $this->model->updateOrCreate(compact('name'), compact('value')); + } + } catch (Exception $e) { + throw new WriteException($e); + } + } + + /** + * Get a setting, or the default value. + * + * @param string $name + * @param mixed $default + * + * @throws \CachetHQ\Cachet\Settings\ReadException + * + * @return mixed + */ + public function get($name, $default = null) + { + try { + if ($setting = $this->model->where('name', '=', $name)->first()) { + return $this->castSetting($name, $setting->value); + } + + return $default; + } catch (Exception $e) { + throw new ReadException($e); } } @@ -81,25 +128,37 @@ public function set($name, $value) * * @param string $name * + * @throws \CachetHQ\Cachet\Settings\WriteException + * * @return void */ public function delete($name) { $this->stale = true; - $this->model->where('name', $name)->delete(); + try { + $this->model->where('name', '=', $name)->delete(); + } catch (Exception $e) { + throw new WriteException($e); + } } /** * Clear all settings. * + * @throws \CachetHQ\Cachet\Settings\WriteException + * * @return void */ public function clear() { $this->stale = true; - $this->model->query()->delete(); + try { + $this->model->query()->delete(); + } catch (Exception $e) { + throw new WriteException($e); + } } /** @@ -111,4 +170,25 @@ public function stale() { return $this->stale; } + + /** + * Cast setting as the applicable type. + * + * @param string $key + * @param string $value + * + * @return mixed + */ + protected function castSetting($key, $value) + { + if (is_null($value)) { + return $value; + } + + if (!in_array($key, $this->notBooleans) && in_array($value, ['0', '1'])) { + return (bool) $value; + } + + return $value; + } } diff --git a/app/Settings/SettingsException.php b/app/Settings/SettingsException.php new file mode 100644 index 00000000000..1716ea366d9 --- /dev/null +++ b/app/Settings/SettingsException.php @@ -0,0 +1,35 @@ + + */ +class SettingsException extends Exception +{ + /** + * Create a new write exception instance. + * + * @param string $m + * @param \Exception $e + * + * @return void + */ + public function __construct(string $m, Exception $e) + { + parent::__construct($m, 0, $e); + } +} diff --git a/app/Settings/WriteException.php b/app/Settings/WriteException.php new file mode 100644 index 00000000000..baa41ff7ac1 --- /dev/null +++ b/app/Settings/WriteException.php @@ -0,0 +1,34 @@ + + */ +class WriteException extends SettingsException +{ + /** + * Create a new write exception instance. + * + * @param \Exception $e + * + * @return void + */ + public function __construct(Exception $e) + { + parent::__construct('Unable to write Cachet settings', $e); + } +} diff --git a/app/Subscribers/CommandSubscriber.php b/app/Subscribers/CommandSubscriber.php index accddefe9e5..a879361999a 100644 --- a/app/Subscribers/CommandSubscriber.php +++ b/app/Subscribers/CommandSubscriber.php @@ -11,11 +11,11 @@ namespace CachetHQ\Cachet\Subscribers; +use CachetHQ\Cachet\Bus\Events\System\SystemWasInstalledEvent; +use CachetHQ\Cachet\Bus\Events\System\SystemWasResetEvent; +use CachetHQ\Cachet\Bus\Events\System\SystemWasUpdatedEvent; use CachetHQ\Cachet\Settings\Cache; -use Carbon\Carbon; -use Exception; use Illuminate\Console\Command; -use Illuminate\Contracts\Config\Repository; use Illuminate\Contracts\Events\Dispatcher; /** @@ -33,25 +33,16 @@ class CommandSubscriber */ protected $cache; - /** - * The config repository instance. - * - * @var \Illuminate\Contracts\Config\Repository - */ - protected $config; - /** * Create a new command subscriber instance. * - * @param \CachetHQ\Cachet\Settings\Cache $cache - * @param \Illuminate\Contracts\Config\Repository $config + * @param \CachetHQ\Cachet\Settings\Cache $cache * * @return void */ - public function __construct(Cache $cache, Repository $config) + public function __construct(Cache $cache) { $this->cache = $cache; - $this->config = $config; } /** @@ -63,41 +54,193 @@ public function __construct(Cache $cache, Repository $config) */ public function subscribe(Dispatcher $events) { - $events->listen('command.installing', __CLASS__.'@fire', 5); - $events->listen('command.updating', __CLASS__.'@fire', 5); - $events->listen('command.resetting', __CLASS__.'@fire', 5); + $events->listen('command.installing', __CLASS__.'@fireInstallingCommand', 5); + $events->listen('command.updating', __CLASS__.'@fireUpdatingCommand', 5); + $events->listen('command.resetting', __CLASS__.'@fireResettingCommand', 5); + $events->listen('command.generatekey', __CLASS__.'@onGenerateKey'); + $events->listen('command.cacheconfig', __CLASS__.'@onCacheConfig'); + $events->listen('command.cacheroutes', __CLASS__.'@onCacheRoutes'); + $events->listen('command.publishvendors', __CLASS__.'@onPublishVendors'); + $events->listen('command.resetmigrations', __CLASS__.'@onResetMigrations'); + $events->listen('command.runmigrations', __CLASS__.'@onRunMigrations'); + $events->listen('command.runseeding', __CLASS__.'@onRunSeeding'); + $events->listen('command.linkstorage', __CLASS__.'@onLinkStorage'); + $events->listen('command.updatecache', __CLASS__.'@onUpdateCache'); + } + + /** + * Fire the installing command. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function fireInstallingCommand(Command $command) + { + $this->handleMainCommand($command); + + event(new SystemWasInstalledEvent()); + + $command->info('System was installed!'); + } + + /** + * Fire the updating command. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function fireUpdatingCommand(Command $command) + { + $this->handleMainCommand($command); + + event(new SystemWasUpdatedEvent()); + + $command->info('System was updated!'); + } + + /** + * Fire the resetting command. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function fireResettingCommand(Command $command) + { + $this->handleMainCommand($command); + + event(new SystemWasResetEvent()); + + $command->info('System was reset!'); } /** - * Clear the settings cache, and backup the databases. + * Handle the main bulk of the command, clear the settings. * * @param \Illuminate\Console\Command $command * * @return void */ - public function fire(Command $command) + protected function handleMainCommand(Command $command) { $command->line('Clearing settings cache...'); $this->cache->clear(); $command->line('Settings cache cleared!'); + } + + /** + * Handle a command.generatekey event. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function onGenerateKey(Command $command) + { + $command->call('key:generate'); + } + + /** + * Handle a command.cacheconfig event. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function onCacheConfig(Command $command) + { + $command->call('config:cache'); + } + + /** + * Handle a command.cacheroutes event. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function onCacheRoutes(Command $command) + { + $command->call('route:cache'); + } + + /** + * Handle a command.publishvendors event. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function onPublishVendors(Command $command) + { + $command->call('vendor:publish', ['--all' => true]); + } + + /** + * Handle a command.resetmigrations event. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function onResetMigrations(Command $command) + { + $command->call('migrate:reset', ['--force' => true]); + } + + /** + * Handle a command.runmigrations event. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function onRunMigrations(Command $command) + { + $command->call('migrate', ['--force' => true]); + } - $command->line('Backing up database...'); - - try { - $command->call('db:backup', [ - '--compression' => 'gzip', - '--database' => $this->config->get('database.default'), - '--destination' => 'local', - '--destinationPath' => Carbon::now()->format('Y-m-d H.i.s'), - '--no-interaction' => true, - ]); - } catch (Exception $e) { - $command->error($e->getMessage()); - $command->line('Backup skipped!'); + /** + * Handle a command.runseeding event. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function onRunSeeding(Command $command) + { + $command->call('db:seed', ['--force' => true]); + } + + /** + * Handle a command.linkstorage event. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function onLinkStorage(Command $command) + { + if ($command->getApplication()->has('storage:link')) { + $command->call('storage:link'); } + } - $command->line('Backup completed!'); + /** + * Handle a command.updatecache event. + * + * @param \Illuminate\Console\Command $command + * + * @return void + */ + public function onUpdateCache(Command $command) + { + $command->line('Clearing cache...'); + $command->call('cache:clear'); + $command->info('Cache cleared!'); } } diff --git a/app/helpers.php b/app/helpers.php index 6338fb4f2b6..d1f032545d4 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -9,12 +9,34 @@ * file that was distributed with this source code. */ +use CachetHQ\Cachet\Settings\Repository; +use Illuminate\Contracts\Bus\Dispatcher; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Request; use Jenssegers\Date\Date; -if (!function_exists('set_active')) { +if (!function_exists('setting')) { + /** + * Get a setting, or the default value. + * + * @param string $name + * @param mixed $default + * + * @return mixed + */ + function setting($name, $default = null) + { + static $settings = []; + + if (isset($settings[$name])) { + return $settings[$name]; + } + + return $settings[$name] = app(Repository::class)->get($name, $default); + } +} +if (!function_exists('set_active')) { /** * Set active class if request is in path. * @@ -52,22 +74,6 @@ function formatted_date($date) } } -if (!function_exists('subscribers_enabled')) { - /** - * Is the subscriber functionality enabled and configured. - * - * @return bool - */ - function subscribers_enabled() - { - $isEnabled = Config::get('setting.enable_subscribers', false); - $mailAddress = Config::get('mail.from.address', false); - $mailFrom = Config::get('mail.from.name', false); - - return $isEnabled && $mailAddress && $mailFrom; - } -} - if (!function_exists('color_darken')) { /** * Darken a color. @@ -108,11 +114,83 @@ function color_darken($hex, $percent) */ function color_contrast($hexcolor) { - $r = hexdec(substr($hexcolor, 0, 2)); - $g = hexdec(substr($hexcolor, 2, 2)); - $b = hexdec(substr($hexcolor, 4, 2)); + $r = ctype_xdigit(substr($hexcolor, 0, 2)); + $g = ctype_xdigit(substr($hexcolor, 2, 2)); + $b = ctype_xdigit(substr($hexcolor, 4, 2)); $yiq = (($r * 100) + ($g * 400) + ($b * 114)) / 1000; return ($yiq >= 128) ? 'black' : 'white'; } } + +if (!function_exists('cachet_route_generator')) { + /** + * Generate the route string. + * + * @param string $name + * @param string $method + * @param string $domain + * + * @return string + */ + function cachet_route_generator($name, $method = 'get', $domain = 'core') + { + return "{$domain}::{$method}:{$name}"; + } +} + +if (!function_exists('cachet_route')) { + /** + * Generate a URL to a named route, which resides in a given domain. + * + * @param string $name + * @param array $parameters + * @param string $method + * @param string $domain + * + * @return string + */ + function cachet_route($name, $parameters = [], $method = 'get', $domain = 'core') + { + return app('url')->route( + cachet_route_generator($name, $method, $domain), + $parameters, + true + ); + } +} + +if (!function_exists('cachet_redirect')) { + /** + * Create a new redirect response to a named route, which resides in a given domain. + * + * @param string $name + * @param array $parameters + * @param int $status + * @param array $headers + * @param string $method + * @param string $domain + * + * @return \Illuminate\Http\RedirectResponse + */ + function cachet_redirect($name, $parameters = [], $status = 302, $headers = [], $method = 'get', $domain = 'core') + { + $url = cachet_route($name, $parameters, $method, $domain); + + return app('redirect')->to($url, $status, $headers); + } +} + +if (!function_exists('execute')) { + /** + * Send the given command to the dispatcher for execution. + * + * @param object $command + * + * @return void + */ + function execute($command) + { + return app(Dispatcher::class)->dispatchNow($command); + } +} diff --git a/artisan b/artisan index eb5e2bb62d4..d294ad8bf35 100644 --- a/artisan +++ b/artisan @@ -28,11 +28,11 @@ $app = require_once __DIR__.'/bootstrap/app.php'; | */ -$kernel = $app->make('Illuminate\Contracts\Console\Kernel'); +$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class); $status = $kernel->handle( - $input = new Symfony\Component\Console\Input\ArgvInput, - new Symfony\Component\Console\Output\ConsoleOutput + $input = new Symfony\Component\Console\Input\ArgvInput(), + new Symfony\Component\Console\Output\ConsoleOutput() ); /* @@ -40,7 +40,7 @@ $status = $kernel->handle( | Shutdown The Application |-------------------------------------------------------------------------- | -| Once Artisan has finished running. We will fire off the shutdown events +| Once Artisan has finished running, we will fire off the shutdown events | so that any final work may be done by the application before we shut | down the process. This is the last thing to happen to the request. | diff --git a/bootstrap/app.php b/bootstrap/app.php index 524cdccff79..2b2ff8cb519 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -22,11 +22,11 @@ | */ -$app->singleton('Illuminate\Contracts\Http\Kernel', 'CachetHQ\Cachet\Http\Kernel'); +$app->singleton(Illuminate\Contracts\Http\Kernel::class, CachetHQ\Cachet\Http\Kernel::class); -$app->singleton('Illuminate\Contracts\Console\Kernel', 'CachetHQ\Cachet\Console\Kernel'); +$app->singleton(Illuminate\Contracts\Console\Kernel::class, CachetHQ\Cachet\Console\Kernel::class); -$app->singleton('Illuminate\Contracts\Debug\ExceptionHandler', 'GrahamCampbell\Exceptions\ExceptionHandler'); +$app->singleton(Illuminate\Contracts\Debug\ExceptionHandler::class, GrahamCampbell\Exceptions\ExceptionHandler::class); /* |-------------------------------------------------------------------------- diff --git a/composer.json b/composer.json index 1606c339a5d..ea6814120e2 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,13 @@ { "name": "cachethq/cachet", "description": "An open source status page system, for everyone.", - "keywords": ["laravel", "cachet", "alt-three", "status", "page"], + "keywords": [ + "laravel", + "cachet", + "alt-three", + "status", + "page" + ], "type": "project", "license": "BSD-3-Clause", "authors": [ @@ -18,40 +24,52 @@ "email": "joe@alt-three.com" } ], + "replace": { + "paragonie/random_compat": "*", + "symfony/polyfill-mbstring": "*" + }, "require": { - "php": ">=5.5.9", - "laravel/framework": "5.2.39", - "alt-three/badger": "^3.1", - "alt-three/bus": "^1.1", - "alt-three/emoji": "^3.1", - "alt-three/throttle": "^1.0", - "alt-three/validator": "^1.5", + "php": "^7.1.3", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-xml": "*", + "alt-three/bus": "^4.1", + "cachethq/badger": "^2.0", + "cachethq/emoji": "^3.0", + "cachethq/twitter": "^3.0", + "alt-three/validator": "^4.1", "aws/aws-sdk-php": "^3.7", - "backup-manager/laravel": "^1.1", - "barryvdh/laravel-cors": "^0.8", - "doctrine/dbal": "^2.5", - "fedeisas/laravel-mail-css-inliner": "^1.5", - "fideloper/proxy": "^3.1", - "graham-campbell/binput": "^3.4", - "graham-campbell/core": "^5.1", - "graham-campbell/exceptions": "^8.6", - "graham-campbell/markdown": "^6.1", - "guzzlehttp/guzzle": "^6.2.1", - "jenssegers/date": "^3.2", - "mccool/laravel-auto-presenter": "^4.3", - "pragmarx/google2fa": "^0.7.1", - "rcrowe/twigbridge": "^0.9.2", - "roumen/feed": "^2.10.4" + "barryvdh/laravel-cors": "^0.11.0", + "bugsnag/bugsnag-laravel": "^2.15", + "chillerlan/php-qrcode": "^2.0", + "doctrine/dbal": "2.9.*", + "fideloper/proxy": "^4.0", + "graham-campbell/binput": "^6.0", + "graham-campbell/exceptions": "^11.1", + "graham-campbell/markdown": "^11.2", + "guzzlehttp/guzzle": "^6.3.3", + "jenssegers/date": "^3.4", + "laravel/framework": "5.7.*", + "laravel/tinker": "^1.0", + "mccool/laravel-auto-presenter": "^7.1", + "nexmo/client": "^1.5", + "pragmarx/google2fa": "^5.0", + "predis/predis": "^1.1", + "twig/twig": "^2.13" }, "require-dev": { - "alt-three/testbench": "^1.4", - "filp/whoops": "^2.1", - "fzaninotto/faker": "^1.6", - "graham-campbell/testbench-core": "^1.1", - "mockery/mockery": "0.9.5", - "phpunit/phpunit": "4.8.21", - "symfony/css-selector": "^3.0", - "symfony/dom-crawler": "^3.0" + "ext-sqlite3": "*", + "alt-three/testbench": "5.0.x-dev", + "barryvdh/laravel-debugbar": "^3.2", + "filp/whoops": "^2.3", + "fzaninotto/faker": "^1.8", + "graham-campbell/analyzer": "^2.1", + "mockery/mockery": "^1.2", + "phpunit/phpunit": "^7.4", + "tightenco/mailthief": "^0.3.14" + }, + "suggest": { + "ext-apc": "APC Support cache driver." }, "autoload": { "classmap": [ @@ -71,34 +89,38 @@ }, "scripts": { "post-root-package-install": [ - "php -r \"copy('.env.example', '.env');\"", - "php artisan key:generate" + "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" ], "post-create-project-cmd": [ - "php artisan key:generate" + "@php artisan key:generate" ], - "post-install-cmd": [ - "Illuminate\\Foundation\\ComposerScripts::postInstall", - "php artisan optimize --force", - "php artisan config:cache", - "php artisan route:cache" + "post-autoload-dump": [ + "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", + "@php artisan package:discover" ], - "post-update-cmd": [ - "Illuminate\\Foundation\\ComposerScripts::postUpdate", - "php artisan optimize --force", - "php artisan config:cache", - "php artisan route:cache" + "test": [ + "@php artisan config:clear", + "vendor/bin/phpunit" + ], + "test-coverage": [ + "@php artisan config:clear", + "vendor/bin/phpunit --coverage-clover=coverage.xml" ] }, "config": { "platform": { - "php": "5.5.9" + "php": "7.1.3" }, - "preferred-install": "dist" + "preferred-install": "dist", + "sort-packages": true, + "optimize-autoloader": true, + "allow-plugins": { + "kylekatarnls/update-helper": true + } }, "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "2.4-dev" } }, "minimum-stability": "dev", diff --git a/composer.lock b/composer.lock index 2f6fc9cbd72..5694c9cc393 100644 --- a/composer.lock +++ b/composer.lock @@ -1,106 +1,40 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "hash": "b9a0ccfa48e2a43140cd4c642e23f515", - "content-hash": "1f7d74d6083194f25a95c7652ddb1a79", + "content-hash": "6ca7a749bbb1681ee57e72dd9387f9ec", "packages": [ - { - "name": "alt-three/badger", - "version": "v3.1.0", - "source": { - "type": "git", - "url": "https://github.com/AltThree/Badger.git", - "reference": "c5de4afcefcc0dd6576d2ae4bd5d5e83fb0cb8d9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/AltThree/Badger/zipball/c5de4afcefcc0dd6576d2ae4bd5d5e83fb0cb8d9", - "reference": "c5de4afcefcc0dd6576d2ae4bd5d5e83fb0cb8d9", - "shasum": "" - }, - "require": { - "illuminate/contracts": "5.1.*|5.2.*|5.3.*", - "illuminate/support": "5.1.*|5.2.*|5.3.*", - "php": ">=5.5.9" - }, - "require-dev": { - "graham-campbell/testbench": "^3.1", - "phpunit/phpunit": "^4.8|^5.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "psr-4": { - "AltThree\\Badger\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "James Brooks", - "email": "james@alt-three.com" - }, - { - "name": "Graham Campbell", - "email": "graham@alt-three.com" - }, - { - "name": "Joseph Cohen", - "email": "joe@alt-three.com" - } - ], - "description": "A Badge Generator For Laravel 5", - "keywords": [ - "Alt Three", - "badge", - "badger", - "shield", - "svg" - ], - "time": "2016-04-22 17:23:42" - }, { "name": "alt-three/bus", - "version": "v1.1.0", + "version": "v4.5.0", "source": { "type": "git", "url": "https://github.com/AltThree/Bus.git", - "reference": "5c8399e0ca67ba6b499aa1e8db6a278711446090" + "reference": "21d1623520c0ad48acb72420fd7f986cd23f349a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/AltThree/Bus/zipball/5c8399e0ca67ba6b499aa1e8db6a278711446090", - "reference": "5c8399e0ca67ba6b499aa1e8db6a278711446090", + "url": "https://api.github.com/repos/AltThree/Bus/zipball/21d1623520c0ad48acb72420fd7f986cd23f349a", + "reference": "21d1623520c0ad48acb72420fd7f986cd23f349a", "shasum": "" }, "require": { - "illuminate/container": "5.2.*|5.3.*", - "illuminate/contracts": "5.2.*|5.3.*", - "illuminate/pipeline": "5.2.*|5.3.*", - "illuminate/support": "5.2.*|5.3.*", - "php": ">=5.5.9" + "illuminate/bus": "^5.5 || ^6.0 || ^7.0 || ^8.0", + "illuminate/container": "^5.5 || ^6.0 || ^7.0 || ^8.0", + "illuminate/contracts": "^5.5 || ^6.0 || ^7.0 || ^8.0", + "illuminate/pipeline": "^5.5 || ^6.0 || ^7.0 || ^8.0", + "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0", + "php": "^7.1.3 || ^8.0" }, "require-dev": { - "graham-campbell/testbench-core": "^1.1", - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.8|^5.0" + "graham-campbell/analyzer": "^2.4 || ^3.0", + "graham-campbell/testbench": "^5.5", + "mockery/mockery": "^1.3.1", + "phpunit/phpunit": "^6.5 || ^7.5 || ^8.4 || ^9.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, "autoload": { "psr-4": { "AltThree\\Bus\\": "src/" @@ -112,23 +46,11 @@ ], "authors": [ { - "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" - }, - { - "name": "James Brooks", - "email": "james@alt-three.com" - }, - { - "name": "Graham Campbell", - "email": "graham@alt-three.com" - }, - { - "name": "Joseph Cohen", - "email": "joe@alt-three.com" + "name": "Alt Three", + "email": "support@alt-three.com" } ], - "description": "An improved command bus for Laravel 5.2+", + "description": "An improved command bus for Laravel", "keywords": [ "Alt Three", "bus", @@ -136,43 +58,41 @@ "command bus", "job" ], - "time": "2016-04-22 17:24:19" + "support": { + "issues": "https://github.com/AltThree/Bus/issues", + "source": "https://github.com/AltThree/Bus/tree/4.5" + }, + "abandoned": true, + "time": "2020-07-25T19:26:48+00:00" }, { - "name": "alt-three/emoji", - "version": "v3.1.0", + "name": "alt-three/validator", + "version": "v4.5.0", "source": { "type": "git", - "url": "https://github.com/AltThree/Emoji.git", - "reference": "631119fb03162af8f42f7eda4c1f92c87611e36f" + "url": "https://github.com/AltThree/Validator.git", + "reference": "65ffc90cda5589052f0dac124d588946dfffd803" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/AltThree/Emoji/zipball/631119fb03162af8f42f7eda4c1f92c87611e36f", - "reference": "631119fb03162af8f42f7eda4c1f92c87611e36f", + "url": "https://api.github.com/repos/AltThree/Validator/zipball/65ffc90cda5589052f0dac124d588946dfffd803", + "reference": "65ffc90cda5589052f0dac124d588946dfffd803", "shasum": "" }, "require": { - "guzzlehttp/guzzle": "^5.3|^6.0", - "illuminate/contracts": "5.1.*|5.2.*|5.3.*", - "illuminate/support": "5.1.*|5.2.*|5.3.*", - "league/commonmark": "^0.13", - "php": ">=5.5.9" + "illuminate/contracts": "^5.5 || ^6.0 || ^7.0 || ^8.0", + "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0", + "php": "^7.1.3 || ^8.0", + "psr/log": "^1.1" }, "require-dev": { - "graham-campbell/markdown": "^6.0", - "graham-campbell/testbench": "^3.1", - "phpunit/phpunit": "^4.8|^5.0" + "graham-campbell/analyzer": "^2.4 || ^3.0", + "phpunit/phpunit": "^6.5 || ^7.5 || ^8.4 || ^9.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, "autoload": { "psr-4": { - "AltThree\\Emoji\\": "src/" + "AltThree\\Validator\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -181,58 +101,55 @@ ], "authors": [ { - "name": "James Brooks", - "email": "james@alt-three.com" - }, - { - "name": "Graham Campbell", - "email": "graham@alt-three.com" - }, - { - "name": "Joseph Cohen", - "email": "joe@alt-three.com" + "name": "Alt Three", + "email": "support@alt-three.com" } ], - "description": "An Emoji Parser For Laravel 5", + "description": "A validation wrapper for Laravel", "keywords": [ "Alt Three", - "emoji", - "parser" + "validation", + "validator" ], - "time": "2016-04-22 17:24:35" + "support": { + "issues": "https://github.com/AltThree/Validator/issues", + "source": "https://github.com/AltThree/Validator/tree/4.5" + }, + "abandoned": true, + "time": "2020-07-25T18:31:34+00:00" }, { - "name": "alt-three/throttle", - "version": "v1.0.6", + "name": "asm89/stack-cors", + "version": "1.3.0", "source": { "type": "git", - "url": "https://github.com/AltThree/Throttle.git", - "reference": "f5d7fdca53b82f4607aa1f58738fe370106c5b62" + "url": "https://github.com/asm89/stack-cors.git", + "reference": "b9c31def6a83f84b4d4a40d35996d375755f0e08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/AltThree/Throttle/zipball/f5d7fdca53b82f4607aa1f58738fe370106c5b62", - "reference": "f5d7fdca53b82f4607aa1f58738fe370106c5b62", + "url": "https://api.github.com/repos/asm89/stack-cors/zipball/b9c31def6a83f84b4d4a40d35996d375755f0e08", + "reference": "b9c31def6a83f84b4d4a40d35996d375755f0e08", "shasum": "" }, "require": { - "illuminate/cache": "5.2.*|5.3.*", - "illuminate/http": "5.2.*|5.3.*", - "php": ">=5.5.9" + "php": ">=5.5.9", + "symfony/http-foundation": "~2.7|~3.0|~4.0|~5.0", + "symfony/http-kernel": "~2.7|~3.0|~4.0|~5.0" }, "require-dev": { - "graham-campbell/testbench": "^3.1", - "phpunit/phpunit": "^4.8|^5.0" + "phpunit/phpunit": "^5.0 || ^4.8.10", + "squizlabs/php_codesniffer": "^2.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.2-dev" } }, "autoload": { "psr-4": { - "AltThree\\Throttle\\": "src/" + "Asm89\\Stack\\": "src/Asm89/Stack/" } }, "notification-url": "https://packagist.org/downloads/", @@ -241,129 +158,127 @@ ], "authors": [ { - "name": "James Brooks", - "email": "james@alt-three.com" - }, - { - "name": "Graham Campbell", - "email": "graham@alt-three.com" - }, - { - "name": "Joseph Cohen", - "email": "joe@alt-three.com" + "name": "Alexander", + "email": "iam.asm89@gmail.com" } ], - "description": "A request rate limiter for Laravel 5.2+", + "description": "Cross-origin resource sharing library and stack middleware", + "homepage": "https://github.com/asm89/stack-cors", "keywords": [ - "Alt Three", - "http", - "rate limit", - "rate limiter", - "throttle" + "cors", + "stack" ], - "time": "2016-06-03 22:24:41" + "support": { + "issues": "https://github.com/asm89/stack-cors/issues", + "source": "https://github.com/asm89/stack-cors/tree/1.3.0" + }, + "time": "2019-12-24T22:41:47+00:00" }, { - "name": "alt-three/validator", - "version": "v1.5.0", + "name": "aws/aws-crt-php", + "version": "v1.2.3", "source": { "type": "git", - "url": "https://github.com/AltThree/Validator.git", - "reference": "fbfe733bac9614edc2c09f8dea7ee3ce465402bb" + "url": "https://github.com/awslabs/aws-crt-php.git", + "reference": "5545a4fa310aec39f54279fdacebcce33b3ff382" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/AltThree/Validator/zipball/fbfe733bac9614edc2c09f8dea7ee3ce465402bb", - "reference": "fbfe733bac9614edc2c09f8dea7ee3ce465402bb", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/5545a4fa310aec39f54279fdacebcce33b3ff382", + "reference": "5545a4fa310aec39f54279fdacebcce33b3ff382", "shasum": "" }, "require": { - "illuminate/contracts": "5.1.*|5.2.*|5.3.*", - "illuminate/support": "5.1.*|5.2.*|5.3.*", - "php": ">=5.5.9", - "psr/log": "^1.0" + "php": ">=5.5" }, "require-dev": { - "phpunit/phpunit": "^4.8|^5.0" + "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5", + "yoast/phpunit-polyfills": "^1.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.5-dev" - } + "suggest": { + "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality." }, + "type": "library", "autoload": { - "psr-4": { - "AltThree\\Validator\\": "src/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "Apache-2.0" ], "authors": [ { - "name": "James Brooks", - "email": "james@alt-three.com" - }, - { - "name": "Graham Campbell", - "email": "graham@alt-three.com" - }, - { - "name": "Joseph Cohen", - "email": "joe@alt-three.com" + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" } ], - "description": "A Validation Wrapper For Laravel 5", + "description": "AWS Common Runtime for PHP", + "homepage": "https://github.com/awslabs/aws-crt-php", "keywords": [ - "Alt Three", - "logging", - "validator" + "amazon", + "aws", + "crt", + "sdk" ], - "time": "2016-04-22 17:26:22" + "support": { + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.3" + }, + "time": "2023-10-16T20:10:06+00:00" }, { "name": "aws/aws-sdk-php", - "version": "3.18.30", + "version": "3.278.3", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "fbce85229b913a9e1aded54e464a9bbff0787bf1" + "reference": "596534c0627d8b38597061341e99b460437d1a16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/fbce85229b913a9e1aded54e464a9bbff0787bf1", - "reference": "fbce85229b913a9e1aded54e464a9bbff0787bf1", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/596534c0627d8b38597061341e99b460437d1a16", + "reference": "596534c0627d8b38597061341e99b460437d1a16", "shasum": "" }, "require": { - "guzzlehttp/guzzle": "^5.3.1|^6.2.1", - "guzzlehttp/promises": "~1.0", - "guzzlehttp/psr7": "~1.3.1", - "mtdowling/jmespath.php": "~2.2", - "php": ">=5.5" + "aws/aws-crt-php": "^1.0.4", + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^6.5.8 || ^7.4.5", + "guzzlehttp/promises": "^1.4.0", + "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", + "mtdowling/jmespath.php": "^2.6", + "php": ">=5.5", + "psr/http-message": "^1.0" }, "require-dev": { "andrewsville/php-token-reflection": "^1.4", "aws/aws-php-sns-message-validator": "~1.0", "behat/behat": "~3.0", + "composer/composer": "^1.10.22", + "dms/phpunit-arraysubset-asserts": "^0.4.0", "doctrine/cache": "~1.4", "ext-dom": "*", - "ext-json": "*", "ext-openssl": "*", - "ext-pcre": "*", - "ext-simplexml": "*", - "ext-spl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", "nette/neon": "^2.3", - "phpunit/phpunit": "~4.0|~5.0", - "psr/cache": "^1.0" + "paragonie/random_compat": ">= 2", + "phpunit/phpunit": "^4.8.35 || ^5.6.3 || ^9.5", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "sebastian/comparator": "^1.2.3 || ^4.0", + "yoast/phpunit-polyfills": "^1.0" }, "suggest": { "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", "doctrine/cache": "To use the DoctrineCacheAdapter", "ext-curl": "To send requests using cURL", - "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages" + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" }, "type": "library", "extra": { @@ -372,12 +287,12 @@ } }, "autoload": { - "psr-4": { - "Aws\\": "src/" - }, "files": [ "src/functions.php" - ] + ], + "psr-4": { + "Aws\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -401,53 +316,54 @@ "s3", "sdk" ], - "time": "2016-07-18 16:15:53" + "support": { + "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.278.3" + }, + "time": "2023-08-15T18:07:55+00:00" }, { - "name": "backup-manager/backup-manager", - "version": "1.1.1", + "name": "barryvdh/laravel-cors", + "version": "v0.11.4", "source": { "type": "git", - "url": "https://github.com/backup-manager/backup-manager.git", - "reference": "e793277e6f6efae6a31c7abbd8028cae7e151201" + "url": "https://github.com/fruitcake/laravel-cors.git", + "reference": "03492f1a3bc74a05de23f93b94ac7cc5c173eec9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/backup-manager/backup-manager/zipball/e793277e6f6efae6a31c7abbd8028cae7e151201", - "reference": "e793277e6f6efae6a31c7abbd8028cae7e151201", + "url": "https://api.github.com/repos/fruitcake/laravel-cors/zipball/03492f1a3bc74a05de23f93b94ac7cc5c173eec9", + "reference": "03492f1a3bc74a05de23f93b94ac7cc5c173eec9", "shasum": "" }, "require": { - "league/flysystem": "~1.0", - "php": ">=5.5.9", - "symfony/process": "~2.1||~3.0" + "asm89/stack-cors": "^1.2", + "illuminate/support": "^5.5|^6", + "php": ">=7", + "symfony/http-foundation": "^3.1|^4", + "symfony/http-kernel": "^3.1|^4" }, "require-dev": { - "aws/aws-sdk-php": "~3.0", - "dropbox/dropbox-sdk": "~1.1", - "league/flysystem-aws-s3-v3": "~1.0", - "league/flysystem-dropbox": "~1.0", - "league/flysystem-rackspace": "~1.0", - "league/flysystem-sftp": "~1.0", - "mockery/mockery": "~0.9", - "phpspec/phpspec": "~2.1", - "satooshi/php-coveralls": "~0.6" - }, - "suggest": { - "league/flysystem-aws-s3-v3": "AwsS3 and GoogleCS adapter support.", - "league/flysystem-dropbox": "Dropbox adapter support.", - "league/flysystem-rackspace": "Rackspace adapter support.", - "league/flysystem-sftp": "Sftp adapter support." + "laravel/framework": "^5.5", + "orchestra/testbench": "3.3.x|3.4.x|3.5.x|3.6.x|3.7.x", + "phpunit/phpunit": "^4.8|^5.2|^7.0", + "squizlabs/php_codesniffer": "^2.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "0.11-dev" + }, + "laravel": { + "providers": [ + "Barryvdh\\Cors\\ServiceProvider" + ] } }, "autoload": { "psr-4": { - "BackupManager\\": "src/" + "Barryvdh\\Cors\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -456,54 +372,59 @@ ], "authors": [ { - "name": "Shawn McCool", - "email": "shawn@heybigname.com", - "homepage": "http://heybigname.com/" - }, - { - "name": "Mitchell van Wijngaarden", - "email": "mitchell@kooding.nl", - "homepage": "http://heybigname.com/" + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" } ], - "description": "A framework agnostic database backup manager with user-definable procedures and support for S3, Dropbox, FTP, SFTP, and more with drivers for popular frameworks.", - "time": "2016-02-05 10:01:19" + "description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Laravel application", + "keywords": [ + "api", + "cors", + "crossdomain", + "laravel" + ], + "support": { + "issues": "https://github.com/fruitcake/laravel-cors/issues", + "source": "https://github.com/fruitcake/laravel-cors/tree/v0.11.4" + }, + "abandoned": true, + "time": "2019-08-28T11:27:11+00:00" }, { - "name": "backup-manager/laravel", - "version": "1.1.1", + "name": "bugsnag/bugsnag", + "version": "v3.29.1", "source": { "type": "git", - "url": "https://github.com/backup-manager/laravel.git", - "reference": "d7e6d12d24b8a27f58cf5eccb1ac943104c09856" + "url": "https://github.com/bugsnag/bugsnag-php.git", + "reference": "7fff8512b237a57323f600975ada6376e2b912c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/backup-manager/laravel/zipball/d7e6d12d24b8a27f58cf5eccb1ac943104c09856", - "reference": "d7e6d12d24b8a27f58cf5eccb1ac943104c09856", + "url": "https://api.github.com/repos/bugsnag/bugsnag-php/zipball/7fff8512b237a57323f600975ada6376e2b912c1", + "reference": "7fff8512b237a57323f600975ada6376e2b912c1", "shasum": "" }, "require": { - "backup-manager/backup-manager": "^1.0", - "illuminate/console": "^4.0||^5.0", - "illuminate/container": "^4.0||^5.0", - "illuminate/support": "^4.0||^5.0", - "php": ">=5.5.0", - "symfony/process": "^2.0||^3.0" + "composer/ca-bundle": "^1.0", + "guzzlehttp/guzzle": "^5.0|^6.0|^7.0", + "php": ">=5.5" }, "require-dev": { - "mockery/mockery": "dev-master", - "satooshi/php-coveralls": "~0.6" + "guzzlehttp/psr7": "^1.3", + "mtdowling/burgomaster": "dev-master#72151eddf5f0cf101502b94bf5031f9c53501a04", + "php-mock/php-mock-phpunit": "^1.1|^2.1", + "phpunit/phpunit": "^4.8.36|^7.5.15|^9.3.10", + "sebastian/version": ">=1.0.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "3.20-dev" } }, "autoload": { "psr-4": { - "BackupManager\\Laravel\\": "src/" + "Bugsnag\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -512,93 +433,122 @@ ], "authors": [ { - "name": "Shawn McCool", - "email": "shawn@heybigname.com", - "homepage": "http://heybigname.com/" - }, - { - "name": "Mitchell van Wijngaarden", - "email": "mitchell@kooding.nl", - "homepage": "http://heybigname.com/" + "name": "James Smith", + "email": "notifiers@bugsnag.com", + "homepage": "https://bugsnag.com" } ], - "description": "Database backup manager seamlessly integrated with Laravel 4 or 5 with user-definable procedures and support for S3, Dropbox, FTP, SFTP, and more.", - "time": "2016-02-22 10:52:12" + "description": "Official Bugsnag notifier for PHP applications.", + "homepage": "https://github.com/bugsnag/bugsnag-php", + "keywords": [ + "bugsnag", + "errors", + "exceptions", + "logging", + "tracking" + ], + "support": { + "issues": "https://github.com/bugsnag/bugsnag-php/issues", + "source": "https://github.com/bugsnag/bugsnag-php/tree/v3.29.1" + }, + "time": "2023-05-10T11:07:22+00:00" }, { - "name": "bacon/bacon-qr-code", - "version": "1.0.1", + "name": "bugsnag/bugsnag-laravel", + "version": "v2.26.0", "source": { "type": "git", - "url": "https://github.com/Bacon/BaconQrCode.git", - "reference": "031a2ce68c5794064b49d11775b2daf45c96e21c" + "url": "https://github.com/bugsnag/bugsnag-laravel.git", + "reference": "333a912e38ead3e02724381093778b271168c8a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/031a2ce68c5794064b49d11775b2daf45c96e21c", - "reference": "031a2ce68c5794064b49d11775b2daf45c96e21c", + "url": "https://api.github.com/repos/bugsnag/bugsnag-laravel/zipball/333a912e38ead3e02724381093778b271168c8a3", + "reference": "333a912e38ead3e02724381093778b271168c8a3", "shasum": "" }, "require": { - "php": ">=5.3.3" + "bugsnag/bugsnag": "^3.29.0", + "bugsnag/bugsnag-psr-logger": "^1.4|^2.0", + "illuminate/contracts": "^5.0|^6.0|^7.0|^8.0|^9.0|^10.0", + "illuminate/support": "^5.0|^6.0|^7.0|^8.0|^9.0|^10.0", + "monolog/monolog": "^1.12|^2.0|^3.0", + "php": ">=5.5" }, - "suggest": { - "ext-gd": "to generate QR code images" + "require-dev": { + "orchestra/testbench": "^3.1|^4.0|^5.0|^6.0|^7.0|^8.0", + "phpunit/phpunit": "^4.8.36|^6.3.1|^7.5.15|^8.3.5|^9.3.10" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.18-dev" + } + }, "autoload": { - "psr-0": { - "BaconQrCode": "src/" + "psr-4": { + "Bugsnag\\BugsnagLaravel\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-2-Clause" + "MIT" ], "authors": [ { - "name": "Ben Scholzen 'DASPRiD'", - "email": "mail@dasprids.de", - "homepage": "http://www.dasprids.de", - "role": "Developer" + "name": "James Smith", + "email": "notifiers@bugsnag.com" } ], - "description": "BaconQrCode is a QR code generator for PHP.", - "homepage": "https://github.com/Bacon/BaconQrCode", - "time": "2016-01-09 22:55:35" + "description": "Official Bugsnag notifier for Laravel applications.", + "homepage": "https://github.com/bugsnag/bugsnag-laravel", + "keywords": [ + "bugsnag", + "errors", + "exceptions", + "laravel", + "logging", + "tracking" + ], + "support": { + "issues": "https://github.com/bugsnag/bugsnag-laravel/issues", + "source": "https://github.com/bugsnag/bugsnag-laravel/tree/v2.26.0" + }, + "time": "2023-02-16T08:48:39+00:00" }, { - "name": "barryvdh/laravel-cors", - "version": "v0.8.1", + "name": "bugsnag/bugsnag-psr-logger", + "version": "v1.4.5", "source": { "type": "git", - "url": "https://github.com/barryvdh/laravel-cors.git", - "reference": "1998c8c7295d167cb744bbc45fbefad9b86b836c" + "url": "https://github.com/bugsnag/bugsnag-psr-logger.git", + "reference": "366430a94d983488d265c1068f47d78ebfbacd74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-cors/zipball/1998c8c7295d167cb744bbc45fbefad9b86b836c", - "reference": "1998c8c7295d167cb744bbc45fbefad9b86b836c", + "url": "https://api.github.com/repos/bugsnag/bugsnag-psr-logger/zipball/366430a94d983488d265c1068f47d78ebfbacd74", + "reference": "366430a94d983488d265c1068f47d78ebfbacd74", "shasum": "" }, "require": { - "illuminate/support": "5.1.x|5.2.x|5.3.x", - "php": ">=5.5.9", - "symfony/http-foundation": "~2.7|~3.0", - "symfony/http-kernel": "~2.7|~3.0" + "bugsnag/bugsnag": "^3.10", + "php": ">=5.5", + "psr/log": "^1.0|^2.0" }, "require-dev": { - "phpunit/phpunit": "^5.2" + "graham-campbell/testbench-core": "^1.1", + "mockery/mockery": "^0.9.4|^1.3.1", + "phpunit/phpunit": "^4.8.36|^7.5.15|^9.4.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "0.8-dev" + "dev-master": "1.5-dev" } }, "autoload": { "psr-4": { - "Barryvdh\\Cors\\": "src/" + "Bugsnag\\PsrLogger\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -607,49 +557,65 @@ ], "authors": [ { - "name": "Barry vd. Heuvel", - "email": "barryvdh@gmail.com" + "name": "James Smith", + "email": "notifiers@bugsnag.com", + "homepage": "https://bugsnag.com" } ], - "description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Laravel application", + "description": "Official Bugsnag PHP PSR Logger.", + "homepage": "https://github.com/bugsnag/bugsnag-psr", "keywords": [ - "api", - "cors", - "crossdomain", - "laravel" + "bugsnag", + "errors", + "exceptions", + "logging", + "psr", + "tracking" ], - "time": "2016-06-22 06:36:34" + "support": { + "issues": "https://github.com/bugsnag/bugsnag-psr-logger/issues", + "source": "https://github.com/bugsnag/bugsnag-psr-logger/tree/v1.4.5" + }, + "time": "2021-12-13T09:52:57+00:00" }, { - "name": "christian-riesen/base32", - "version": "1.3.1", + "name": "cachethq/badger", + "version": "v2.0.0", "source": { "type": "git", - "url": "https://github.com/ChristianRiesen/base32.git", - "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa" + "url": "https://github.com/CachetHQ/Badger.git", + "reference": "9d7f9e8f8529d902f3a30ad120a403a7ba2da1e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ChristianRiesen/base32/zipball/0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", - "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", + "url": "https://api.github.com/repos/CachetHQ/Badger/zipball/9d7f9e8f8529d902f3a30ad120a403a7ba2da1e3", + "reference": "9d7f9e8f8529d902f3a30ad120a403a7ba2da1e3", "shasum": "" }, "require": { - "php": ">=5.3.0" + "illuminate/contracts": "^5.5|^6.0", + "illuminate/support": "^5.5|^6.0", + "php": "^7.1.3" }, "require-dev": { - "phpunit/phpunit": "4.*", - "satooshi/php-coveralls": "0.*" + "graham-campbell/analyzer": "^2.1", + "graham-campbell/testbench": "^5.1", + "phpunit/phpunit": "^6.5|^7.0|^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "2.0-dev" + }, + "laravel": { + "providers": [ + "CachetHQ\\Badger\\BadgerServiceProvider" + ] } }, "autoload": { "psr-4": { - "Base32\\": "src/" + "CachetHQ\\Badger\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -658,52 +624,67 @@ ], "authors": [ { - "name": "Christian Riesen", - "email": "chris.riesen@gmail.com", - "homepage": "http://christianriesen.com", - "role": "Developer" + "name": "Cachet", + "email": "support@cachethq.io" } ], - "description": "Base32 encoder/decoder according to RFC 4648", - "homepage": "https://github.com/ChristianRiesen/base32", + "description": "A Badge Generator For Laravel 5 and 6.", "keywords": [ - "base32", - "decode", - "encode", - "rfc4648" + "CachetHQ", + "badge", + "badger", + "cachet", + "shield", + "svg" ], - "time": "2016-05-05 11:49:03" + "support": { + "issues": "https://github.com/CachetHQ/Badger/issues", + "source": "https://github.com/CachetHQ/Badger/tree/v2.0.0" + }, + "time": "2019-11-18T20:06:20+00:00" }, { - "name": "classpreloader/classpreloader", - "version": "3.0.0", + "name": "cachethq/emoji", + "version": "v3.0.0", "source": { "type": "git", - "url": "https://github.com/ClassPreloader/ClassPreloader.git", - "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a" + "url": "https://github.com/CachetHQ/Emoji.git", + "reference": "45227616c9b8077deeefe5561035e219b4118233" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/9b10b913c2bdf90c3d2e0d726b454fb7f77c552a", - "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a", + "url": "https://api.github.com/repos/CachetHQ/Emoji/zipball/45227616c9b8077deeefe5561035e219b4118233", + "reference": "45227616c9b8077deeefe5561035e219b4118233", "shasum": "" }, "require": { - "nikic/php-parser": "^1.0|^2.0", - "php": ">=5.5.9" + "graham-campbell/guzzle-factory": "^3.0", + "illuminate/contracts": "^5.5|^6.0", + "illuminate/support": "^5.5|^6.0", + "league/commonmark": "^1.0", + "php": "^7.1.3" }, "require-dev": { - "phpunit/phpunit": "^4.8|^5.0" + "graham-campbell/analyzer": "^2.1", + "graham-campbell/markdown": "^11.0", + "graham-campbell/testbench": "^5.1", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.5|^7.0|^8.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.0-dev" + }, + "laravel": { + "providers": [ + "CachetHQ\\Emoji\\EmojiServiceProvider" + ] } }, "autoload": { "psr-4": { - "ClassPreloader\\": "src/" + "CachetHQ\\Emoji\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -712,86 +693,115 @@ ], "authors": [ { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com" - }, - { - "name": "Graham Campbell", - "email": "graham@alt-three.com" + "name": "Cachet", + "email": "support@cachethq.io" } ], - "description": "Helps class loading performance by generating a single PHP file containing all of the autoloaded files for a specific use case", + "description": "An Emoji Parser For Laravel 5 and 6", "keywords": [ - "autoload", - "class", - "preload" + "CachetHQ", + "cachet", + "emoji", + "parser" ], - "time": "2015-11-09 22:51:51" + "support": { + "issues": "https://github.com/CachetHQ/Emoji/issues", + "source": "https://github.com/CachetHQ/Emoji/tree/v3.0.0" + }, + "time": "2019-11-19T17:04:13+00:00" }, { - "name": "dnoegel/php-xdg-base-dir", - "version": "0.1", + "name": "cachethq/twitter", + "version": "v3.0.0", "source": { "type": "git", - "url": "https://github.com/dnoegel/php-xdg-base-dir.git", - "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a" + "url": "https://github.com/CachetHQ/Twitter.git", + "reference": "81216cbc3c1f1a32df70bfb73837f59a35a22b1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a", - "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a", + "url": "https://api.github.com/repos/CachetHQ/Twitter/zipball/81216cbc3c1f1a32df70bfb73837f59a35a22b1c", + "reference": "81216cbc3c1f1a32df70bfb73837f59a35a22b1c", "shasum": "" }, "require": { - "php": ">=5.3.2" + "illuminate/contracts": "^5.5|^6.0", + "illuminate/support": "^5.5|^6.0", + "league/commonmark": "^1.0", + "php": "^7.1.3" }, "require-dev": { - "phpunit/phpunit": "@stable" + "graham-campbell/analyzer": "^2.1", + "graham-campbell/markdown": "^11.0", + "graham-campbell/testbench": "^5.1", + "phpunit/phpunit": "^6.5|^7.0|^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + }, + "laravel": { + "providers": [ + "CachetHQ\\Twitter\\TwitterServiceProvider" + ] + } }, - "type": "project", "autoload": { "psr-4": { - "XdgBaseDir\\": "src/" + "CachetHQ\\Twitter\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "implementation of xdg base directory specification for php", - "time": "2014-10-24 07:27:01" - }, - { - "name": "doctrine/annotations", - "version": "v1.2.7", + "authors": [ + { + "name": "Cachet", + "email": "support@cachethq.io" + } + ], + "description": "A Twitter handle parser for Laravel 5 and 6", + "keywords": [ + "CachetHQ", + "cachet", + "markdown", + "parser", + "twitter" + ], + "support": { + "issues": "https://github.com/CachetHQ/Twitter/issues", + "source": "https://github.com/CachetHQ/Twitter/tree/v3.0.0" + }, + "time": "2019-11-19T17:04:54+00:00" + }, + { + "name": "chillerlan/php-qrcode", + "version": "2.0.8", "source": { "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535" + "url": "https://github.com/chillerlan/php-qrcode.git", + "reference": "bf0382aaf2f79fa41c2dcb0f216675f74d633fe7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535", - "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "url": "https://api.github.com/repos/chillerlan/php-qrcode/zipball/bf0382aaf2f79fa41c2dcb0f216675f74d633fe7", + "reference": "bf0382aaf2f79fa41c2dcb0f216675f74d633fe7", "shasum": "" }, "require": { - "doctrine/lexer": "1.*", - "php": ">=5.3.2" + "chillerlan/php-traits": "^1.1", + "php": ">=7.0.3" }, "require-dev": { - "doctrine/cache": "1.*", - "phpunit/phpunit": "4.*" + "chillerlan/php-authenticator": "^2.0", + "phpunit/phpunit": "^6.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Annotations\\": "lib/" + "psr-4": { + "chillerlan\\QRCode\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -800,69 +810,56 @@ ], "authors": [ { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" + "name": "Kazuhiko Arase", + "homepage": "https://github.com/kazuhikoarase" }, { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Smiley", + "email": "smiley@chillerlan.net", + "homepage": "https://github.com/codemasher" } ], - "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org", + "description": "A QR code generator. PHP 7+", + "homepage": "https://github.com/chillerlan/php-qrcode", "keywords": [ - "annotations", - "docblock", - "parser" + "qr code" + ], + "support": { + "issues": "https://github.com/chillerlan/php-qrcode/issues", + "source": "https://github.com/chillerlan/php-qrcode/tree/v2.0.x" + }, + "funding": [ + { + "url": "https://ko-fi.com/codemasher", + "type": "ko_fi" + } ], - "time": "2015-08-31 12:32:49" + "time": "2020-04-12T07:38:35+00:00" }, { - "name": "doctrine/cache", - "version": "v1.6.0", + "name": "chillerlan/php-traits", + "version": "1.1.13", "source": { "type": "git", - "url": "https://github.com/doctrine/cache.git", - "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6" + "url": "https://github.com/chillerlan/php-traits.git", + "reference": "264759946b6aaeb427346b749fc9639b790b8e7f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6", - "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6", + "url": "https://api.github.com/repos/chillerlan/php-traits/zipball/264759946b6aaeb427346b749fc9639b790b8e7f", + "reference": "264759946b6aaeb427346b749fc9639b790b8e7f", "shasum": "" }, "require": { - "php": "~5.5|~7.0" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4" + "php": ">=7.0.3" }, "require-dev": { - "phpunit/phpunit": "~4.8|~5.0", - "predis/predis": "~1.0", - "satooshi/php-coveralls": "~0.6" + "phpunit/phpunit": "^6.5" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.6.x-dev" - } - }, "autoload": { "psr-4": { - "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + "chillerlan\\Traits\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -871,63 +868,61 @@ ], "authors": [ { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Smiley", + "email": "smiley@chillerlan.net", + "homepage": "https://github.com/codemasher" } ], - "description": "Caching library offering an object-oriented API for many cache backends", - "homepage": "http://www.doctrine-project.org", + "description": "Some useful traits for PHP 7+", + "homepage": "https://github.com/chillerlan/php-traits", "keywords": [ - "cache", - "caching" + "PHP7", + "container", + "dotenv", + "helper", + "trait" ], - "time": "2015-12-31 16:37:02" + "support": { + "issues": "https://github.com/chillerlan/php-traits/issues", + "source": "https://github.com/chillerlan/php-traits" + }, + "abandoned": true, + "time": "2018-06-22T00:30:47+00:00" }, { - "name": "doctrine/collections", - "version": "v1.3.0", + "name": "composer/ca-bundle", + "version": "1.3.7", "source": { "type": "git", - "url": "https://github.com/doctrine/collections.git", - "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a" + "url": "https://github.com/composer/ca-bundle.git", + "reference": "76e46335014860eec1aa5a724799a00a2e47cc85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a", - "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/76e46335014860eec1aa5a724799a00a2e47cc85", + "reference": "76e46335014860eec1aa5a724799a00a2e47cc85", "shasum": "" }, "require": { - "php": ">=5.3.2" + "ext-openssl": "*", + "ext-pcre": "*", + "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpstan/phpstan": "^0.12.55", + "psr/log": "^1.0", + "symfony/phpunit-bridge": "^4.2 || ^5", + "symfony/process": "^2.5 || ^3.0 || ^4.0 || ^5.0 || ^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-main": "1.x-dev" } }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Collections\\": "lib/" + "psr-4": { + "Composer\\CaBundle\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -936,69 +931,115 @@ ], "authors": [ { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Lets you find a path to the system CA bundle, and includes a fallback to the Mozilla CA bundle.", + "keywords": [ + "cabundle", + "cacert", + "certificate", + "ssl", + "tls" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/ca-bundle/issues", + "source": "https://github.com/composer/ca-bundle/tree/1.3.7" + }, + "funding": [ { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" + "url": "https://packagist.com", + "type": "custom" }, { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" + "url": "https://github.com/composer", + "type": "github" }, { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" } ], - "description": "Collections Abstraction library", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "array", - "collections", - "iterator" - ], - "time": "2015-04-14 22:21:58" + "time": "2023-08-30T09:31:38+00:00" }, { - "name": "doctrine/common", - "version": "v2.6.1", + "name": "dnoegel/php-xdg-base-dir", + "version": "v0.1.1", "source": { "type": "git", - "url": "https://github.com/doctrine/common.git", - "reference": "a579557bc689580c19fee4e27487a67fe60defc0" + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/a579557bc689580c19fee4e27487a67fe60defc0", - "reference": "a579557bc689580c19fee4e27487a67fe60defc0", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", + "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", "shasum": "" }, "require": { - "doctrine/annotations": "1.*", - "doctrine/cache": "1.*", - "doctrine/collections": "1.*", - "doctrine/inflector": "1.*", - "doctrine/lexer": "1.*", - "php": "~5.5|~7.0" + "php": ">=5.3.2" }, "require-dev": { - "phpunit/phpunit": "~4.8|~5.0" + "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7.x-dev" + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" } }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "support": { + "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues", + "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1" + }, + "time": "2019-12-04T15:06:13+00:00" + }, + { + "name": "doctrine/cache", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "56cd022adb5514472cb144c087393c1821911d09" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/56cd022adb5514472cb144c087393c1821911d09", + "reference": "56cd022adb5514472cb144c087393c1821911d09", + "shasum": "" + }, + "require": { + "php": "~7.1 || ^8.0" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "alcaeus/mongo-php-adapter": "^1.1", + "cache/integration-tests": "dev-master", + "doctrine/coding-standard": "^9", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "predis/predis": "~1.0", + "psr/cache": "^1.0 || ^2.0 || ^3.0", + "symfony/cache": "^4.4 || ^5.4 || ^6", + "symfony/var-exporter": "^4.4 || ^5.4 || ^6" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" + }, + "type": "library", "autoload": { "psr-4": { - "Doctrine\\Common\\": "lib/Doctrine/Common" + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" } }, "notification-url": "https://packagist.org/downloads/", @@ -1006,6 +1047,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -1014,10 +1059,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -1027,38 +1068,66 @@ "email": "schmittjoh@gmail.com" } ], - "description": "Common Library for Doctrine projects", - "homepage": "http://www.doctrine-project.org", + "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", + "homepage": "https://www.doctrine-project.org/projects/cache.html", "keywords": [ - "annotations", - "collections", - "eventmanager", - "persistence", - "spl" + "abstraction", + "apcu", + "cache", + "caching", + "couchdb", + "memcached", + "php", + "redis", + "xcache" + ], + "support": { + "issues": "https://github.com/doctrine/cache/issues", + "source": "https://github.com/doctrine/cache/tree/1.13.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", + "type": "tidelift" + } ], - "time": "2015-12-25 13:18:31" + "time": "2022-05-20T20:06:54+00:00" }, { "name": "doctrine/dbal", - "version": "v2.5.4", + "version": "v2.9.3", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769" + "reference": "7345cd59edfa2036eb0fa4264b77ae2576842035" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/abbdfd1cff43a7b99d027af3be709bc8fc7d4769", - "reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/7345cd59edfa2036eb0fa4264b77ae2576842035", + "reference": "7345cd59edfa2036eb0fa4264b77ae2576842035", "shasum": "" }, "require": { - "doctrine/common": ">=2.4,<2.7-dev", - "php": ">=5.3.2" + "doctrine/cache": "^1.0", + "doctrine/event-manager": "^1.0", + "ext-pdo": "*", + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "4.*", - "symfony/console": "2.*" + "doctrine/coding-standard": "^5.0", + "jetbrains/phpstorm-stubs": "^2018.1.2", + "phpstan/phpstan": "^0.10.1", + "phpunit/phpunit": "^7.4", + "symfony/console": "^2.0.5|^3.0|^4.0", + "symfony/phpunit-bridge": "^3.4.5|^4.0.5" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -1069,12 +1138,13 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5.x-dev" + "dev-master": "2.9.x-dev", + "dev-develop": "3.0.x-dev" } }, "autoload": { - "psr-0": { - "Doctrine\\DBAL\\": "lib/" + "psr-4": { + "Doctrine\\DBAL\\": "lib/Doctrine/DBAL" } }, "notification-url": "https://packagist.org/downloads/", @@ -1082,6 +1152,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -1090,54 +1164,107 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" } ], - "description": "Database Abstraction Layer", - "homepage": "http://www.doctrine-project.org", + "description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.", + "homepage": "https://www.doctrine-project.org/projects/dbal.html", "keywords": [ + "abstraction", "database", "dbal", + "mysql", "persistence", + "pgsql", + "php", "queryobject" ], - "time": "2016-01-05 22:11:12" + "support": { + "issues": "https://github.com/doctrine/dbal/issues", + "source": "https://github.com/doctrine/dbal/tree/2.9" + }, + "time": "2019-11-02T22:19:34+00:00" }, { - "name": "doctrine/inflector", - "version": "v1.1.0", + "name": "doctrine/deprecations", + "version": "1.1.2", "source": { "type": "git", - "url": "https://github.com/doctrine/inflector.git", - "reference": "90b2128806bfde671b6952ab8bea493942c1fdae" + "url": "https://github.com/doctrine/deprecations.git", + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae", - "reference": "90b2128806bfde671b6952ab8bea493942c1fdae", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/4f2d4f2836e7ec4e7a8625e75c6aa916004db931", + "reference": "4f2d4f2836e7ec4e7a8625e75c6aa916004db931", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^7.1 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "4.*" + "doctrine/coding-standard": "^9", + "phpstan/phpstan": "1.4.10 || 1.10.15", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "0.18.4", + "psr/log": "^1 || ^2 || ^3", + "vimeo/psalm": "4.30.0 || 5.12.0" + }, + "suggest": { + "psr/log": "Allows logging deprecations via PSR-3 logger implementation" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" + "autoload": { + "psr-4": { + "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" } }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", + "homepage": "https://www.doctrine-project.org/", + "support": { + "issues": "https://github.com/doctrine/deprecations/issues", + "source": "https://github.com/doctrine/deprecations/tree/1.1.2" + }, + "time": "2023-09-27T20:04:15+00:00" + }, + { + "name": "doctrine/event-manager", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/event-manager.git", + "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/95aa4cb529f1e96576f3fda9f5705ada4056a520", + "reference": "95aa4cb529f1e96576f3fda9f5705ada4056a520", + "shasum": "" + }, + "require": { + "doctrine/deprecations": "^0.5.3 || ^1", + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/common": "<2.9" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "~1.4.10 || ^1.8.8", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.24" + }, + "type": "library", "autoload": { - "psr-0": { - "Doctrine\\Common\\Inflector\\": "lib/" + "psr-4": { + "Doctrine\\Common\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1145,6 +1272,10 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" @@ -1153,10 +1284,6 @@ "name": "Benjamin Eberlei", "email": "kontakt@beberlei.de" }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, { "name": "Jonathan Wage", "email": "jonwage@gmail.com" @@ -1164,44 +1291,75 @@ { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" } ], - "description": "Common String Manipulations with regard to casing and singular/plural rules.", - "homepage": "http://www.doctrine-project.org", + "description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.", + "homepage": "https://www.doctrine-project.org/projects/event-manager.html", "keywords": [ - "inflection", - "pluralize", - "singularize", - "string" + "event", + "event dispatcher", + "event manager", + "event system", + "events" + ], + "support": { + "issues": "https://github.com/doctrine/event-manager/issues", + "source": "https://github.com/doctrine/event-manager/tree/1.2.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager", + "type": "tidelift" + } ], - "time": "2015-11-06 14:35:42" + "time": "2022-10-12T20:51:15+00:00" }, { - "name": "doctrine/lexer", - "version": "v1.0.1", + "name": "doctrine/inflector", + "version": "1.4.4", "source": { "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + "url": "https://github.com/doctrine/inflector.git", + "reference": "4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9", + "reference": "4bd5c1cdfcd00e9e2d8c484f79150f67e5d355d9", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^8.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpstan/phpstan-strict-rules": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Lexer\\": "lib/" + "psr-4": { + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector", + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" } }, "notification-url": "https://packagist.org/downloads/", @@ -1209,59 +1367,88 @@ "MIT" ], "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { "name": "Roman Borschel", "email": "roman@code-factory.org" }, { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" }, { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" } ], - "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "http://www.doctrine-project.org", + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", "keywords": [ - "lexer", - "parser" + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/1.4.4" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } ], - "time": "2014-09-09 13:34:57" + "time": "2021-04-16T17:34:40+00:00" }, { - "name": "fedeisas/laravel-mail-css-inliner", - "version": "1.5", + "name": "doctrine/lexer", + "version": "1.2.3", "source": { "type": "git", - "url": "https://github.com/fedeisas/laravel-mail-css-inliner.git", - "reference": "8c3cd958634e865a90fc398900ea59c427dd35cc" + "url": "https://github.com/doctrine/lexer.git", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fedeisas/laravel-mail-css-inliner/zipball/8c3cd958634e865a90fc398900ea59c427dd35cc", - "reference": "8c3cd958634e865a90fc398900ea59c427dd35cc", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", "shasum": "" }, "require": { - "illuminate/support": "~5.0", - "php": ">=5.4.0", - "tijsverkoyen/css-to-inline-styles": "~1.2" + "php": "^7.1 || ^8.0" }, "require-dev": { - "jakub-onderka/php-console-highlighter": "0.3.*", - "jakub-onderka/php-parallel-lint": "0.8.*", - "phpmd/phpmd": "~1.5", - "phpunit/phpunit": "~4.0", - "satooshi/php-coveralls": "~0.7@dev", - "squizlabs/php_codesniffer": "~1.5", - "swiftmailer/swiftmailer": "~5.0" + "doctrine/coding-standard": "^9.0", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.11" }, "type": "library", "autoload": { "psr-4": { - "Fedeisas\\LaravelMailCssInliner\\": "src/" + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" } }, "notification-url": "https://packagist.org/downloads/", @@ -1270,44 +1457,258 @@ ], "authors": [ { - "name": "Fede Isas", - "email": "fedeisas@hotmail.com" + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" } ], - "description": "Inline the CSS of your HTML emails using Laravel", + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", "keywords": [ - "css", - "laravel", - "mailer" + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2022-02-28T11:07:21+00:00" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "65b2d8ee1f10915efb3b55597da3404f096acba2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/65b2d8ee1f10915efb3b55597da3404f096acba2", + "reference": "65b2d8ee1f10915efb3b55597da3404f096acba2", + "shasum": "" + }, + "require": { + "php": "^7.0|^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.4|^7.0|^8.0|^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v2.3.1" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "time": "2020-10-13T00:52:37+00:00" + }, + { + "name": "egulias/email-validator", + "version": "2.1.25", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "0dbf5d78455d4d6a41d186da50adc1122ec066f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/0dbf5d78455d4d6a41d186da50adc1122ec066f4", + "reference": "0dbf5d78455d4d6a41d186da50adc1122ec066f4", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1.0.1", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.10" + }, + "require-dev": { + "dominicsayers/isemail": "^3.0.7", + "phpunit/phpunit": "^4.8.36|^7.5.15", + "satooshi/php-coveralls": "^1.0.1" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/2.1.25" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2020-12-29T14:50:06+00:00" + }, + { + "name": "erusev/parsedown", + "version": "1.7.4", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "type": "library", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" ], - "time": "2016-04-19 07:02:48" + "support": { + "issues": "https://github.com/erusev/parsedown/issues", + "source": "https://github.com/erusev/parsedown/tree/1.7.x" + }, + "time": "2019-12-30T22:54:17+00:00" }, { "name": "fideloper/proxy", - "version": "3.1.0", + "version": "4.4.2", "source": { "type": "git", "url": "https://github.com/fideloper/TrustedProxy.git", - "reference": "ec4dd30141e2515e307aea3539ff242e85c3f120" + "reference": "a751f2bc86dd8e6cfef12dc0cbdada82f5a18750" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fideloper/TrustedProxy/zipball/ec4dd30141e2515e307aea3539ff242e85c3f120", - "reference": "ec4dd30141e2515e307aea3539ff242e85c3f120", + "url": "https://api.github.com/repos/fideloper/TrustedProxy/zipball/a751f2bc86dd8e6cfef12dc0cbdada82f5a18750", + "reference": "a751f2bc86dd8e6cfef12dc0cbdada82f5a18750", "shasum": "" }, "require": { - "illuminate/contracts": "~5.0", + "illuminate/contracts": "^5.0|^6.0|^7.0|^8.0|^9.0", "php": ">=5.4.0" }, "require-dev": { - "illuminate/http": "~5.0", - "mockery/mockery": "~0.9.3" + "illuminate/http": "^5.0|^6.0|^7.0|^8.0|^9.0", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^8.5.8|^9.3.3" }, "type": "library", "extra": { - "branch-alias": { - "dev-master": "3.1-dev" + "laravel": { + "providers": [ + "Fideloper\\Proxy\\TrustedProxyServiceProvider" + ] } }, "autoload": { @@ -1331,38 +1732,48 @@ "proxy", "trusted proxy" ], - "time": "2015-12-24 15:02:55" + "support": { + "issues": "https://github.com/fideloper/TrustedProxy/issues", + "source": "https://github.com/fideloper/TrustedProxy/tree/4.4.2" + }, + "time": "2022-02-09T13:33:34+00:00" }, { "name": "graham-campbell/binput", - "version": "v3.4.0", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Laravel-Binput.git", - "reference": "814bcce1c012fbdf3a8275eef45e5d84ad01239d" + "reference": "9c0df9c3d0481a495bdc0638ee67bc199d70e3b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Laravel-Binput/zipball/814bcce1c012fbdf3a8275eef45e5d84ad01239d", - "reference": "814bcce1c012fbdf3a8275eef45e5d84ad01239d", + "url": "https://api.github.com/repos/GrahamCampbell/Laravel-Binput/zipball/9c0df9c3d0481a495bdc0638ee67bc199d70e3b4", + "reference": "9c0df9c3d0481a495bdc0638ee67bc199d70e3b4", "shasum": "" }, "require": { - "graham-campbell/security": "^3.5", - "illuminate/contracts": "5.1.*|5.2.*|5.3.*", - "illuminate/http": "5.1.*|5.2.*|5.3.*", - "illuminate/support": "5.1.*|5.2.*|5.3.*", - "php": ">=5.5.9" + "graham-campbell/security": "^6.2", + "illuminate/contracts": "^5.5|^6.0", + "illuminate/http": "^5.5|^6.0", + "illuminate/support": "^5.5|^6.0", + "php": "^7.1.3" }, "require-dev": { - "graham-campbell/testbench": "^3.1", - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.8|^5.0" + "graham-campbell/analyzer": "^2.1", + "graham-campbell/testbench": "^5.2", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.5|^7.0|^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "6.2-dev" + }, + "laravel": { + "providers": [ + "GrahamCampbell\\Binput\\BinputServiceProvider" + ] } }, "autoload": { @@ -1394,42 +1805,59 @@ "laravel", "security" ], - "time": "2016-04-26 14:18:44" + "support": { + "issues": "https://github.com/GrahamCampbell/Laravel-Binput/issues", + "source": "https://github.com/GrahamCampbell/Laravel-Binput/tree/master" + }, + "time": "2019-08-26T16:30:03+00:00" }, { - "name": "graham-campbell/core", - "version": "v5.1.0", + "name": "graham-campbell/exceptions", + "version": "v11.3.0", "source": { "type": "git", - "url": "https://github.com/GrahamCampbell/Laravel-Core.git", - "reference": "9ca45b4d0f9bde7084ffac6ca3337af153340790" + "url": "https://github.com/GrahamCampbell/Laravel-Exceptions.git", + "reference": "c33548417cf9903a049c7311ab57352a7e720b33" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Laravel-Core/zipball/9ca45b4d0f9bde7084ffac6ca3337af153340790", - "reference": "9ca45b4d0f9bde7084ffac6ca3337af153340790", + "url": "https://api.github.com/repos/GrahamCampbell/Laravel-Exceptions/zipball/c33548417cf9903a049c7311ab57352a7e720b33", + "reference": "c33548417cf9903a049c7311ab57352a7e720b33", "shasum": "" }, "require": { - "illuminate/console": "5.1.*|5.2.*|5.3.*", - "illuminate/contracts": "5.1.*|5.2.*|5.3.*", - "illuminate/support": "5.1.*|5.2.*|5.3.*", - "php": ">=5.5.9" + "illuminate/contracts": "5.5.*|5.6.*|5.7.*|5.8.*", + "illuminate/support": "5.5.*|5.6.*|5.7.*|5.8.*", + "php": "^7.1.3", + "psr/log": "^1.0", + "symfony/console": "^3.3|^4.0", + "symfony/debug": "^3.3|^4.0", + "symfony/http-foundation": "^3.3|^4.0" }, "require-dev": { - "graham-campbell/testbench": "^3.1", - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.8|^5.0" + "filp/whoops": "^2.1.4", + "graham-campbell/analyzer": "^2.1", + "graham-campbell/testbench": "^5.2", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.5|^7.0|^8.0" + }, + "suggest": { + "filp/whoops": "Enables use of the debug displayer." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.1-dev" + "dev-master": "11.3-dev" + }, + "laravel": { + "providers": [ + "GrahamCampbell\\Exceptions\\ExceptionsServiceProvider" + ] } }, "autoload": { "psr-4": { - "GrahamCampbell\\Core\\": "src/" + "GrahamCampbell\\Exceptions\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1442,61 +1870,57 @@ "email": "graham@alt-three.com" } ], - "description": "Core Provides Some Extra Functionality For Laravel 5", + "description": "Provides A Powerful Error Response System For Both Development And Production", "keywords": [ "Graham Campbell", "GrahamCampbell", - "Laravel Core", - "Laravel-Core", - "base", - "core", + "Laravel Exceptions", + "Laravel-Exceptions", + "error", + "errors", + "exception", + "exceptions", "framework", "laravel", - "starter" + "whoops" ], - "time": "2016-05-25 09:22:06" + "support": { + "issues": "https://github.com/GrahamCampbell/Laravel-Exceptions/issues", + "source": "https://github.com/GrahamCampbell/Laravel-Exceptions/tree/v11.3.0" + }, + "time": "2019-06-03T06:57:27+00:00" }, { - "name": "graham-campbell/exceptions", - "version": "v8.6.2", + "name": "graham-campbell/guzzle-factory", + "version": "v3.0.4", "source": { "type": "git", - "url": "https://github.com/GrahamCampbell/Laravel-Exceptions.git", - "reference": "7a36e51547258f750a1e68f6caa717bff26e710b" + "url": "https://github.com/GrahamCampbell/Guzzle-Factory.git", + "reference": "618cf7220b177c6d9939a36331df937739ffc596" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Laravel-Exceptions/zipball/7a36e51547258f750a1e68f6caa717bff26e710b", - "reference": "7a36e51547258f750a1e68f6caa717bff26e710b", + "url": "https://api.github.com/repos/GrahamCampbell/Guzzle-Factory/zipball/618cf7220b177c6d9939a36331df937739ffc596", + "reference": "618cf7220b177c6d9939a36331df937739ffc596", "shasum": "" }, "require": { - "illuminate/contracts": "5.1.*|5.2.*|5.3.*", - "illuminate/support": "5.1.*|5.2.*|5.3.*", - "paragonie/random_compat": "^1.1|^2.0", - "php": ">=5.5.9", - "psr/log": "^1.0", - "symfony/debug": "^2.7|^3.0", - "symfony/http-foundation": "^2.7|^3.0" + "guzzlehttp/guzzle": "^6.2", + "php": "^7.0|^8.0" }, "require-dev": { - "filp/whoops": "^1.1|^2.0", - "graham-campbell/testbench": "^3.1", - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.8|^5.0" - }, - "suggest": { - "filp/whoops": "Enables use of the debug displayer." + "graham-campbell/analyzer": "^2.4", + "phpunit/phpunit": "^6.5|^7.0|^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "8.6-dev" + "dev-master": "3.0-dev" } }, "autoload": { "psr-4": { - "GrahamCampbell\\Exceptions\\": "src/" + "GrahamCampbell\\GuzzleFactory\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1509,53 +1933,67 @@ "email": "graham@alt-three.com" } ], - "description": "Provides A Powerful Error Response System For Both Development And Production", + "description": "Provides A Simple Guzzle Factory With Good Defaults", "keywords": [ "Graham Campbell", "GrahamCampbell", - "Laravel Exceptions", - "Laravel-Exceptions", - "error", - "errors", - "exception", - "exceptions", - "framework", - "laravel", - "whoops" + "Guzzle", + "Guzzle Factory", + "Guzzle-Factory", + "http" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Guzzle-Factory/issues", + "source": "https://github.com/GrahamCampbell/Guzzle-Factory/tree/3.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/guzzle-factory", + "type": "tidelift" + } ], - "time": "2016-07-14 15:54:14" + "time": "2020-05-02T14:45:48+00:00" }, { "name": "graham-campbell/markdown", - "version": "v6.1.0", + "version": "v11.2.1", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Laravel-Markdown.git", - "reference": "2208ec910d9880d6bca28d332ae7f3b7350355d1" + "reference": "7ead48c43098b562707a30650843d4279786b0d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Laravel-Markdown/zipball/2208ec910d9880d6bca28d332ae7f3b7350355d1", - "reference": "2208ec910d9880d6bca28d332ae7f3b7350355d1", + "url": "https://api.github.com/repos/GrahamCampbell/Laravel-Markdown/zipball/7ead48c43098b562707a30650843d4279786b0d9", + "reference": "7ead48c43098b562707a30650843d4279786b0d9", "shasum": "" }, "require": { - "illuminate/contracts": "5.1.*|5.2.*|5.3.*", - "illuminate/support": "5.1.*|5.2.*|5.3.*", - "illuminate/view": "5.1.*|5.2.*|5.3.*", - "league/commonmark": "^0.13", - "php": ">=5.5.9" + "illuminate/contracts": "^5.5|^6.0|^7.0", + "illuminate/support": "^5.5|^6.0|^7.0", + "illuminate/view": "^5.5|^6.0|^7.0", + "league/commonmark": "^1.3", + "php": "^7.1.3" }, "require-dev": { - "graham-campbell/testbench": "^3.1", - "league/commonmark-extras": "^0.1", - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.8|^5.0" + "graham-campbell/analyzer": "^2.4", + "graham-campbell/testbench": "^5.4", + "mockery/mockery": "^1.3.1", + "phpunit/phpunit": "^6.5|^7.0|^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.1-dev" + "dev-master": "11.2-dev" + }, + "laravel": { + "providers": [ + "GrahamCampbell\\Markdown\\MarkdownServiceProvider" + ] } }, "autoload": { @@ -1573,7 +2011,7 @@ "email": "graham@alt-three.com" } ], - "description": "Markdown Is A CommonMark Wrapper For Laravel 5", + "description": "Markdown Is A CommonMark Wrapper For Laravel", "keywords": [ "Graham Campbell", "GrahamCampbell", @@ -1585,35 +2023,60 @@ "laravel", "markdown" ], - "time": "2016-04-26 14:28:21" + "support": { + "issues": "https://github.com/GrahamCampbell/Laravel-Markdown/issues", + "source": "https://github.com/GrahamCampbell/Laravel-Markdown/tree/11.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://www.patreon.com/GrahamJCampbell", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/markdown", + "type": "tidelift" + } + ], + "time": "2020-04-14T14:11:12+00:00" }, { "name": "graham-campbell/security", - "version": "v3.6.0", + "version": "v6.2.0", "source": { "type": "git", "url": "https://github.com/GrahamCampbell/Laravel-Security.git", - "reference": "07d4ec2658582032afe225928bde883474e2a543" + "reference": "93b3e09774987916f9a91071b2e53738180f2ba8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Laravel-Security/zipball/07d4ec2658582032afe225928bde883474e2a543", - "reference": "07d4ec2658582032afe225928bde883474e2a543", + "url": "https://api.github.com/repos/GrahamCampbell/Laravel-Security/zipball/93b3e09774987916f9a91071b2e53738180f2ba8", + "reference": "93b3e09774987916f9a91071b2e53738180f2ba8", "shasum": "" }, "require": { - "illuminate/contracts": "5.1.*|5.2.*|5.3.*", - "illuminate/support": "5.1.*|5.2.*|5.3.*", - "php": ">=5.5.9" + "graham-campbell/security-core": "^1.0", + "illuminate/contracts": "^5.5|^6.0", + "illuminate/support": "^5.5|^6.0", + "php": "^7.1.3" }, "require-dev": { - "graham-campbell/testbench": "^3.1", - "phpunit/phpunit": "^4.8|^5.0" + "graham-campbell/analyzer": "^2.1", + "graham-campbell/testbench": "^5.2", + "phpunit/phpunit": "^6.5|^7.0|^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.6-dev" + "dev-master": "6.2-dev" + }, + "laravel": { + "providers": [ + "GrahamCampbell\\Security\\SecurityServiceProvider" + ] } }, "autoload": { @@ -1642,44 +2105,42 @@ "laravel", "security" ], - "time": "2016-04-26 14:29:04" + "support": { + "issues": "https://github.com/GrahamCampbell/Laravel-Security/issues", + "source": "https://github.com/GrahamCampbell/Laravel-Security/tree/master" + }, + "time": "2019-08-26T16:30:00+00:00" }, { - "name": "guzzlehttp/guzzle", - "version": "6.2.1", + "name": "graham-campbell/security-core", + "version": "v1.0.3", "source": { "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "3f808fba627f2c5b69e2501217bf31af349c1427" + "url": "https://github.com/GrahamCampbell/Security-Core.git", + "reference": "3b14e58dba84b0238a3409818d6f67acc5c00bf9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/3f808fba627f2c5b69e2501217bf31af349c1427", - "reference": "3f808fba627f2c5b69e2501217bf31af349c1427", + "url": "https://api.github.com/repos/GrahamCampbell/Security-Core/zipball/3b14e58dba84b0238a3409818d6f67acc5c00bf9", + "reference": "3b14e58dba84b0238a3409818d6f67acc5c00bf9", "shasum": "" }, "require": { - "guzzlehttp/promises": "^1.0", - "guzzlehttp/psr7": "^1.3.1", - "php": ">=5.5" + "php": "^7.0" }, "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "^4.0", - "psr/log": "^1.0" + "graham-campbell/analyzer": "^2.4", + "phpunit/phpunit": "^6.5|^7.5|^8.4|^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.2-dev" + "dev-master": "1.0-dev" } }, "autoload": { - "files": [ - "src/functions_include.php" - ], "psr-4": { - "GuzzleHttp\\": "src/" + "GrahamCampbell\\SecurityCore\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1688,161 +2149,368 @@ ], "authors": [ { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" + "name": "Graham Campbell", + "email": "graham@alt-three.com" } ], - "description": "Guzzle is a PHP HTTP client library", - "homepage": "http://guzzlephp.org/", + "description": "Security Core Is A Port Of The Security Class From Codeigniter 3 For General Use", "keywords": [ - "client", - "curl", + "Graham Campbell", + "GrahamCampbell", + "Security Core", + "Security-Core", + "codeigniter", "framework", - "http", - "http client", - "rest", - "web service" + "laravel", + "security" ], - "time": "2016-07-15 17:22:37" - }, - { - "name": "guzzlehttp/promises", - "version": "1.2.0", + "support": { + "issues": "https://github.com/GrahamCampbell/Security-Core/issues", + "source": "https://github.com/GrahamCampbell/Security-Core/tree/v1.0.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://www.patreon.com/GrahamJCampbell", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/security-core", + "type": "tidelift" + } + ], + "time": "2020-04-13T13:30:49+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "6.5.8", "source": { "type": "git", - "url": "https://github.com/guzzle/promises.git", - "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579" + "url": "https://github.com/guzzle/guzzle.git", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579", - "reference": "c10d860e2a9595f8883527fa0021c7da9e65f579", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/a52f0440530b54fa079ce76e8c5d196a42cad981", + "reference": "a52f0440530b54fa079ce76e8c5d196a42cad981", "shasum": "" }, "require": { - "php": ">=5.5.0" + "ext-json": "*", + "guzzlehttp/promises": "^1.0", + "guzzlehttp/psr7": "^1.9", + "php": ">=5.5", + "symfony/polyfill-intl-idn": "^1.17" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "ext-curl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0", + "psr/log": "^1.1" + }, + "suggest": { + "psr/log": "Required for using the Log middleware" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "6.5-dev" } }, "autoload": { + "files": [ + "src/functions_include.php" + ], "psr-4": { - "GuzzleHttp\\Promise\\": "src/" + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/6.5.8" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2022-06-20T22:16:07+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "1.5.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "reference": "67ab6e18aaa14d753cc148911d273f6e6cb6721e", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "symfony/phpunit-bridge": "^4.4 || ^5.1" + }, + "type": "library", + "autoload": { "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], "description": "Guzzle promises library", "keywords": [ "promise" ], - "time": "2016-05-18 16:56:05" + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/1.5.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2023-05-21T12:31:43+00:00" }, { "name": "guzzlehttp/psr7", - "version": "1.3.1", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b" + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", - "reference": "5c6447c9df362e8f8093bda8f5d8873fe5c7f65b", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b", + "reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b", "shasum": "" }, "require": { "php": ">=5.4.0", - "psr/http-message": "~1.0" + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5 || ^3.0.0" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "ext-zlib": "*", + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" }, + "type": "library", "autoload": { - "psr-4": { - "GuzzleHttp\\Psr7\\": "src/" - }, "files": [ "src/functions_include.php" - ] + ], + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, { "name": "Michael Dowling", "email": "mtdowling@gmail.com", "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" } ], - "description": "PSR-7 message implementation", + "description": "PSR-7 message implementation that also provides common utility methods", "keywords": [ "http", "message", + "psr-7", + "request", + "response", "stream", - "uri" + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/1.9.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } ], - "time": "2016-06-24 23:00:38" + "time": "2023-04-17T16:00:37+00:00" }, { "name": "jakub-onderka/php-console-color", - "version": "0.1", + "version": "v0.2", "source": { "type": "git", "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", - "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1" + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/e0b393dacf7703fc36a4efc3df1435485197e6c1", - "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/d5deaecff52a0d61ccb613bb3804088da0307191", + "reference": "d5deaecff52a0d61ccb613bb3804088da0307191", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": ">=5.4.0" }, "require-dev": { "jakub-onderka/php-code-style": "1.0", - "jakub-onderka/php-parallel-lint": "0.*", + "jakub-onderka/php-parallel-lint": "1.0", "jakub-onderka/php-var-dump-check": "0.*", - "phpunit/phpunit": "3.7.*", + "phpunit/phpunit": "~4.3", "squizlabs/php_codesniffer": "1.*" }, "type": "library", "autoload": { - "psr-0": { - "JakubOnderka\\PhpConsoleColor": "src/" + "psr-4": { + "JakubOnderka\\PhpConsoleColor\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1852,41 +2520,46 @@ "authors": [ { "name": "Jakub Onderka", - "email": "jakub.onderka@gmail.com", - "homepage": "http://www.acci.cz" + "email": "jakub.onderka@gmail.com" } ], - "time": "2014-04-08 15:00:19" + "support": { + "issues": "https://github.com/JakubOnderka/PHP-Console-Color/issues", + "source": "https://github.com/JakubOnderka/PHP-Console-Color/tree/master" + }, + "abandoned": "php-parallel-lint/php-console-color", + "time": "2018-09-29T17:23:10+00:00" }, { "name": "jakub-onderka/php-console-highlighter", - "version": "v0.3.2", + "version": "v0.4", "source": { "type": "git", "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", - "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5" + "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/7daa75df45242c8d5b75a22c00a201e7954e4fb5", - "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5", + "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/9f7a229a69d52506914b4bc61bfdb199d90c5547", + "reference": "9f7a229a69d52506914b4bc61bfdb199d90c5547", "shasum": "" }, "require": { - "jakub-onderka/php-console-color": "~0.1", - "php": ">=5.3.0" + "ext-tokenizer": "*", + "jakub-onderka/php-console-color": "~0.2", + "php": ">=5.4.0" }, "require-dev": { "jakub-onderka/php-code-style": "~1.0", - "jakub-onderka/php-parallel-lint": "~0.5", + "jakub-onderka/php-parallel-lint": "~1.0", "jakub-onderka/php-var-dump-check": "~0.1", "phpunit/phpunit": "~4.0", "squizlabs/php_codesniffer": "~1.5" }, "type": "library", "autoload": { - "psr-0": { - "JakubOnderka\\PhpConsoleHighlighter": "src/" + "psr-4": { + "JakubOnderka\\PhpConsoleHighlighter\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1900,35 +2573,49 @@ "homepage": "http://www.acci.cz/" } ], - "time": "2015-04-20 18:58:01" + "description": "Highlight PHP code in terminal", + "support": { + "issues": "https://github.com/JakubOnderka/PHP-Console-Highlighter/issues", + "source": "https://github.com/JakubOnderka/PHP-Console-Highlighter/tree/master" + }, + "abandoned": "php-parallel-lint/php-console-highlighter", + "time": "2018-09-29T18:48:56+00:00" }, { "name": "jenssegers/date", - "version": "v3.2.2", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/jenssegers/date.git", - "reference": "2550344143b9de9b4b4ecbe64477d6eed5717b84" + "reference": "58393b0544fc2525b3fcd02aa4c989857107e05a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jenssegers/date/zipball/2550344143b9de9b4b4ecbe64477d6eed5717b84", - "reference": "2550344143b9de9b4b4ecbe64477d6eed5717b84", + "url": "https://api.github.com/repos/jenssegers/date/zipball/58393b0544fc2525b3fcd02aa4c989857107e05a", + "reference": "58393b0544fc2525b3fcd02aa4c989857107e05a", "shasum": "" }, "require": { - "nesbot/carbon": "^1.0", - "php": ">=5.4", - "symfony/translation": "^2.7|^3.0" + "nesbot/carbon": "^1.0|^2.0", + "php": ">=5.6", + "symfony/translation": "^2.7|^3.0|^4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0|^5.0", - "satooshi/php-coveralls": "^1.0" + "phpunit/phpunit": "^5.0|^6.0|^7.0", + "satooshi/php-coveralls": "^2.0" }, "type": "library", "extra": { "branch-alias": { "dev-master": "3.1-dev" + }, + "laravel": { + "providers": [ + "Jenssegers\\Date\\DateServiceProvider" + ], + "aliases": { + "Date": "Jenssegers\\Date\\Date" + } } }, "autoload": { @@ -1957,39 +2644,42 @@ "time", "translation" ], - "time": "2016-06-05 16:39:48" + "support": { + "issues": "https://github.com/jenssegers/date/issues", + "source": "https://github.com/jenssegers/date/tree/master" + }, + "time": "2019-03-10T08:50:58+00:00" }, { - "name": "jeremeamia/SuperClosure", - "version": "2.2.0", + "name": "kylekatarnls/update-helper", + "version": "1.2.1", "source": { "type": "git", - "url": "https://github.com/jeremeamia/super_closure.git", - "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938" + "url": "https://github.com/kylekatarnls/update-helper.git", + "reference": "429be50660ed8a196e0798e5939760f168ec8ce9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/29a88be2a4846d27c1613aed0c9071dfad7b5938", - "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938", + "url": "https://api.github.com/repos/kylekatarnls/update-helper/zipball/429be50660ed8a196e0798e5939760f168ec8ce9", + "reference": "429be50660ed8a196e0798e5939760f168ec8ce9", "shasum": "" }, "require": { - "nikic/php-parser": "^1.2|^2.0", - "php": ">=5.4", - "symfony/polyfill-php56": "^1.0" + "composer-plugin-api": "^1.1.0 || ^2.0.0", + "php": ">=5.3.0" }, "require-dev": { - "phpunit/phpunit": "^4.0|^5.0" + "codeclimate/php-test-reporter": "dev-master", + "composer/composer": "2.0.x-dev || ^2.0.0-dev", + "phpunit/phpunit": ">=4.8.35 <6.0" }, - "type": "library", + "type": "composer-plugin", "extra": { - "branch-alias": { - "dev-master": "2.2-dev" - } + "class": "UpdateHelper\\ComposerPlugin" }, "autoload": { - "psr-4": { - "SuperClosure\\": "src/" + "psr-0": { + "UpdateHelper\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1998,64 +2688,75 @@ ], "authors": [ { - "name": "Jeremy Lindblom", - "email": "jeremeamia@gmail.com", - "homepage": "https://github.com/jeremeamia", - "role": "Developer" + "name": "Kyle", + "email": "kylekatarnls@gmail.com" } ], - "description": "Serialize Closure objects, including their context and binding", - "homepage": "https://github.com/jeremeamia/super_closure", - "keywords": [ - "closure", - "function", - "lambda", - "parser", - "serializable", - "serialize", - "tokenizer" + "description": "Update helper", + "support": { + "issues": "https://github.com/kylekatarnls/update-helper/issues", + "source": "https://github.com/kylekatarnls/update-helper/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } ], - "time": "2015-12-05 17:17:57" + "time": "2020-04-07T20:44:10+00:00" }, { "name": "laravel/framework", - "version": "v5.2.39", + "version": "v5.7.29", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "c2a77050269b4e03bd9a735a9f24e573a7598b8a" + "reference": "2555bf6ef6e6739e5f49f4a5d40f6264c57abd56" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/c2a77050269b4e03bd9a735a9f24e573a7598b8a", - "reference": "c2a77050269b4e03bd9a735a9f24e573a7598b8a", + "url": "https://api.github.com/repos/laravel/framework/zipball/2555bf6ef6e6739e5f49f4a5d40f6264c57abd56", + "reference": "2555bf6ef6e6739e5f49f4a5d40f6264c57abd56", "shasum": "" }, "require": { - "classpreloader/classpreloader": "~3.0", - "doctrine/inflector": "~1.0", + "doctrine/inflector": "^1.1", + "dragonmantank/cron-expression": "^2.0", + "erusev/parsedown": "^1.7", "ext-mbstring": "*", "ext-openssl": "*", - "jeremeamia/superclosure": "~2.2", - "league/flysystem": "~1.0", - "monolog/monolog": "~1.11", - "mtdowling/cron-expression": "~1.0", - "nesbot/carbon": "~1.20", - "paragonie/random_compat": "~1.4", - "php": ">=5.5.9", - "psy/psysh": "0.7.*", - "swiftmailer/swiftmailer": "~5.1", - "symfony/console": "2.8.*|3.0.*", - "symfony/debug": "2.8.*|3.0.*", - "symfony/finder": "2.8.*|3.0.*", - "symfony/http-foundation": "2.8.*|3.0.*", - "symfony/http-kernel": "2.8.*|3.0.*", - "symfony/polyfill-php56": "~1.0", - "symfony/process": "2.8.*|3.0.*", - "symfony/routing": "2.8.*|3.0.*", - "symfony/translation": "2.8.*|3.0.*", - "symfony/var-dumper": "2.8.*|3.0.*", - "vlucas/phpdotenv": "~2.2" + "laravel/nexmo-notification-channel": "^1.0", + "laravel/slack-notification-channel": "^1.0", + "league/flysystem": "^1.0.8", + "monolog/monolog": "^1.12", + "nesbot/carbon": "^1.26.3", + "opis/closure": "^3.1", + "php": "^7.1.3", + "psr/container": "^1.0", + "psr/simple-cache": "^1.0", + "ramsey/uuid": "^3.7", + "swiftmailer/swiftmailer": "^6.0", + "symfony/console": "^4.1", + "symfony/debug": "^4.1", + "symfony/finder": "^4.1", + "symfony/http-foundation": "^4.1", + "symfony/http-kernel": "^4.1", + "symfony/process": "^4.1", + "symfony/routing": "^4.1", + "symfony/var-dumper": "^4.1", + "tijsverkoyen/css-to-inline-styles": "^2.2.1", + "vlucas/phpdotenv": "^2.2" + }, + "conflict": { + "tightenco/collect": "<5.5.33" }, "replace": { "illuminate/auth": "self.version", @@ -2070,12 +2771,12 @@ "illuminate/database": "self.version", "illuminate/encryption": "self.version", "illuminate/events": "self.version", - "illuminate/exception": "self.version", "illuminate/filesystem": "self.version", "illuminate/hashing": "self.version", "illuminate/http": "self.version", "illuminate/log": "self.version", "illuminate/mail": "self.version", + "illuminate/notifications": "self.version", "illuminate/pagination": "self.version", "illuminate/pipeline": "self.version", "illuminate/queue": "self.version", @@ -2088,38 +2789,50 @@ "illuminate/view": "self.version" }, "require-dev": { - "aws/aws-sdk-php": "~3.0", - "mockery/mockery": "~0.9.4", - "pda/pheanstalk": "~3.0", - "phpunit/phpunit": "~4.1", - "predis/predis": "~1.0", - "symfony/css-selector": "2.8.*|3.0.*", - "symfony/dom-crawler": "2.8.*|3.0.*" + "aws/aws-sdk-php": "^3.0", + "doctrine/dbal": "^2.6", + "filp/whoops": "^2.1.4", + "guzzlehttp/guzzle": "^6.3", + "league/flysystem-cached-adapter": "^1.0", + "mockery/mockery": "^1.0", + "moontoast/math": "^1.1", + "orchestra/testbench-core": "3.7.*", + "pda/pheanstalk": "^3.0|^4.0", + "phpunit/phpunit": "^7.5", + "predis/predis": "^1.1.1", + "symfony/css-selector": "^4.1", + "symfony/dom-crawler": "^4.1", + "true/punycode": "^2.1" }, "suggest": { - "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).", - "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).", - "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).", - "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~5.3|~6.0).", - "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).", - "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).", - "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", - "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", - "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~2.0).", - "symfony/css-selector": "Required to use some of the crawler integration testing tools (2.8.*|3.0.*).", - "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (2.8.*|3.0.*).", - "symfony/psr-http-message-bridge": "Required to psr7 bridging features (0.2.*)." + "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (^3.0).", + "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.6).", + "ext-pcntl": "Required to use all features of the queue worker.", + "ext-posix": "Required to use all features of the queue worker.", + "filp/whoops": "Required for friendly error pages in development (^2.1.4).", + "fzaninotto/faker": "Required to use the eloquent factory builder (^1.4).", + "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (^6.0).", + "laravel/tinker": "Required to use the tinker console command (^1.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^1.0).", + "league/flysystem-cached-adapter": "Required to use the Flysystem cache (^1.0).", + "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (^1.0).", + "league/flysystem-sftp": "Required to use the Flysystem SFTP driver (^1.0).", + "moontoast/math": "Required to use ordered UUIDs (^1.1).", + "nexmo/client": "Required to use the Nexmo transport (^1.0).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (^3.0|^4.0).", + "predis/predis": "Required to use the redis cache and queue drivers (^1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^3.0).", + "symfony/css-selector": "Required to use some of the crawler integration testing tools (^4.1).", + "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (^4.1).", + "symfony/psr-http-message-bridge": "Required to psr7 bridging features (^1.0)." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.2-dev" + "dev-master": "5.7-dev" } }, "autoload": { - "classmap": [ - "src/Illuminate/Queue/IlluminateQueueClosure.php" - ], "files": [ "src/Illuminate/Foundation/helpers.php", "src/Illuminate/Support/helpers.php" @@ -2135,135 +2848,120 @@ "authors": [ { "name": "Taylor Otwell", - "email": "taylorotwell@gmail.com" + "email": "taylor@laravel.com" } ], "description": "The Laravel Framework.", - "homepage": "http://laravel.com", + "homepage": "https://laravel.com", "keywords": [ "framework", "laravel" ], - "time": "2016-06-17 19:25:12" + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2020-04-14T14:16:19+00:00" }, { - "name": "league/commonmark", - "version": "0.13.4", + "name": "laravel/nexmo-notification-channel", + "version": "v1.0.1", "source": { "type": "git", - "url": "https://github.com/thephpleague/commonmark.git", - "reference": "83f8210427fb01f671e272bb8d44b4ed3a94d459" + "url": "https://github.com/laravel/vonage-notification-channel.git", + "reference": "03edd42a55b306ff980c9950899d5a2b03260d48" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/83f8210427fb01f671e272bb8d44b4ed3a94d459", - "reference": "83f8210427fb01f671e272bb8d44b4ed3a94d459", + "url": "https://api.github.com/repos/laravel/vonage-notification-channel/zipball/03edd42a55b306ff980c9950899d5a2b03260d48", + "reference": "03edd42a55b306ff980c9950899d5a2b03260d48", "shasum": "" }, "require": { - "ext-mbstring": "*", - "php": ">=5.4.8" - }, - "replace": { - "colinodell/commonmark-php": "*" + "nexmo/client": "^1.0", + "php": "^7.1.3" }, "require-dev": { - "cebe/markdown": "~1.0", - "erusev/parsedown": "~1.0", - "jgm/commonmark": "0.25", - "michelf/php-markdown": "~1.4", - "mikehaertl/php-shellcommand": "~1.2.0", - "phpunit/phpunit": "~4.3|~5.0", - "scrutinizer/ocular": "~1.1", - "symfony/finder": "~2.3|~3.0" - }, - "suggest": { - "league/commonmark-extras": "Library of useful extensions including smart punctuation" + "illuminate/notifications": "~5.7", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.0" }, - "bin": [ - "bin/commonmark" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "0.14-dev" + "dev-master": "1.0-dev" + }, + "laravel": { + "providers": [ + "Illuminate\\Notifications\\NexmoChannelServiceProvider" + ] } }, "autoload": { "psr-4": { - "League\\CommonMark\\": "src/" + "Illuminate\\Notifications\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Colin O'Dell", - "email": "colinodell@gmail.com", - "homepage": "https://www.colinodell.com", - "role": "Lead Developer" + "name": "Taylor Otwell", + "email": "taylor@laravel.com" } ], - "description": "Markdown parser for PHP based on the CommonMark spec", - "homepage": "https://github.com/thephpleague/commonmark", + "description": "Nexmo Notification Channel for laravel.", "keywords": [ - "commonmark", - "markdown", - "parser" + "laravel", + "nexmo", + "notifications" ], - "time": "2016-06-14 14:49:29" + "support": { + "issues": "https://github.com/laravel/vonage-notification-channel/issues", + "source": "https://github.com/laravel/vonage-notification-channel/tree/v1.0.1" + }, + "abandoned": "laravel/vonage-notification-channel", + "time": "2018-12-04T12:57:08+00:00" }, { - "name": "league/flysystem", - "version": "1.0.25", + "name": "laravel/slack-notification-channel", + "version": "v1.0.3", "source": { "type": "git", - "url": "https://github.com/thephpleague/flysystem.git", - "reference": "a76afa4035931be0c78ca8efc6abf3902362f437" + "url": "https://github.com/laravel/slack-notification-channel.git", + "reference": "6e164293b754a95f246faf50ab2bbea3e4923cc9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a76afa4035931be0c78ca8efc6abf3902362f437", - "reference": "a76afa4035931be0c78ca8efc6abf3902362f437", + "url": "https://api.github.com/repos/laravel/slack-notification-channel/zipball/6e164293b754a95f246faf50ab2bbea3e4923cc9", + "reference": "6e164293b754a95f246faf50ab2bbea3e4923cc9", "shasum": "" }, "require": { - "php": ">=5.4.0" - }, - "conflict": { - "league/flysystem-sftp": "<1.0.6" + "guzzlehttp/guzzle": "^6.0", + "php": "^7.1.3" }, "require-dev": { - "ext-fileinfo": "*", - "mockery/mockery": "~0.9", - "phpspec/phpspec": "^2.2", - "phpunit/phpunit": "~4.8" - }, - "suggest": { - "ext-fileinfo": "Required for MimeType", - "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", - "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", - "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", - "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", - "league/flysystem-copy": "Allows you to use Copy.com storage", - "league/flysystem-dropbox": "Allows you to use Dropbox storage", - "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", - "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", - "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", - "league/flysystem-webdav": "Allows you to use WebDAV storage", - "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter" + "illuminate/notifications": "~5.7", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "1.0-dev" + }, + "laravel": { + "providers": [ + "Illuminate\\Notifications\\SlackChannelServiceProvider" + ] } }, "autoload": { "psr-4": { - "League\\Flysystem\\": "src/" + "Illuminate\\Notifications\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2272,18 +2970,329 @@ ], "authors": [ { - "name": "Frank de Jonge", - "email": "info@frenky.net" + "name": "Taylor Otwell", + "email": "taylor@laravel.com" } ], - "description": "Filesystem abstraction: Many filesystems, one API.", + "description": "Slack Notification Channel for laravel.", "keywords": [ - "Cloud Files", - "WebDAV", - "abstraction", - "aws", - "cloud", - "copy.com", + "laravel", + "notifications", + "slack" + ], + "support": { + "issues": "https://github.com/laravel/slack-notification-channel/issues", + "source": "https://github.com/laravel/slack-notification-channel/tree/1.0" + }, + "time": "2018-12-12T13:12:06+00:00" + }, + { + "name": "laravel/tinker", + "version": "v1.0.10", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "ad571aacbac1539c30d480908f9d0c9614eaf1a7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/ad571aacbac1539c30d480908f9d0c9614eaf1a7", + "reference": "ad571aacbac1539c30d480908f9d0c9614eaf1a7", + "shasum": "" + }, + "require": { + "illuminate/console": "~5.1|^6.0", + "illuminate/contracts": "~5.1|^6.0", + "illuminate/support": "~5.1|^6.0", + "php": ">=5.5.9", + "psy/psysh": "0.7.*|0.8.*|0.9.*", + "symfony/var-dumper": "~3.0|~4.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.0|~5.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (~5.1)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Tinker\\TinkerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Tinker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Powerful REPL for the Laravel framework.", + "keywords": [ + "REPL", + "Tinker", + "laravel", + "psysh" + ], + "support": { + "issues": "https://github.com/laravel/tinker/issues", + "source": "https://github.com/laravel/tinker/tree/v1.0.10" + }, + "time": "2019-08-07T15:10:45+00:00" + }, + { + "name": "lcobucci/jwt", + "version": "3.4.6", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "3ef8657a78278dfeae7707d51747251db4176240" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/3ef8657a78278dfeae7707d51747251db4176240", + "reference": "3ef8657a78278dfeae7707d51747251db4176240", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-openssl": "*", + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "mikey179/vfsstream": "~1.5", + "phpmd/phpmd": "~2.2", + "phpunit/php-invoker": "~1.1", + "phpunit/phpunit": "^5.7 || ^7.3", + "squizlabs/php_codesniffer": "~2.3" + }, + "suggest": { + "lcobucci/clock": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, + "autoload": { + "files": [ + "compat/class-aliases.php", + "compat/json-exception-polyfill.php", + "compat/lcobucci-clock-polyfill.php" + ], + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Otávio Cobucci Oblonczyk", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/3.4.6" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2021-09-28T19:18:28+00:00" + }, + { + "name": "league/commonmark", + "version": "1.6.7", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "2b8185c13bc9578367a5bf901881d1c1b5bbd09b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/2b8185c13bc9578367a5bf901881d1c1b5bbd09b", + "reference": "2b8185c13bc9578367a5bf901881d1c1b5bbd09b", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^7.1 || ^8.0" + }, + "conflict": { + "scrutinizer/ocular": "1.7.*" + }, + "require-dev": { + "cebe/markdown": "~1.0", + "commonmark/commonmark.js": "0.29.2", + "erusev/parsedown": "~1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "~1.4", + "mikehaertl/php-shellcommand": "^1.4", + "phpstan/phpstan": "^0.12.90", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.2", + "scrutinizer/ocular": "^1.5", + "symfony/finder": "^4.2" + }, + "bin": [ + "bin/commonmark" + ], + "type": "library", + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and Github-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "support": { + "docs": "https://commonmark.thephpleague.com/", + "issues": "https://github.com/thephpleague/commonmark/issues", + "rss": "https://github.com/thephpleague/commonmark/releases.atom", + "source": "https://github.com/thephpleague/commonmark" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/commonmark", + "type": "tidelift" + } + ], + "time": "2022-01-13T17:18:13+00:00" + }, + { + "name": "league/flysystem", + "version": "1.0.70", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "585824702f534f8d3cf7fab7225e8466cc4b7493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/585824702f534f8d3cf7fab7225e8466cc4b7493", + "reference": "585824702f534f8d3cf7fab7225e8466cc4b7493", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": ">=5.5.9" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" + }, + "require-dev": { + "phpspec/phpspec": "^3.4 || ^4.0 || ^5.0 || ^6.0", + "phpunit/phpunit": "^5.7.26" + }, + "suggest": { + "ext-fileinfo": "Required for MimeType", + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frenky.net" + } + ], + "description": "Filesystem abstraction: Many filesystems, one API.", + "keywords": [ + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", "dropbox", "file systems", "files", @@ -2296,40 +3305,56 @@ "sftp", "storage" ], - "time": "2016-07-18 12:22:57" + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.0.70" + }, + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "time": "2020-07-26T07:20:36+00:00" }, { "name": "mccool/laravel-auto-presenter", - "version": "4.3.0", + "version": "7.7.0", "source": { "type": "git", "url": "https://github.com/laravel-auto-presenter/laravel-auto-presenter.git", - "reference": "08ce32a41aa5d6c842b4cc19ae442e211cb3dd96" + "reference": "e139110a82c8a1573d4015b4f6d600d79e1d33e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel-auto-presenter/laravel-auto-presenter/zipball/08ce32a41aa5d6c842b4cc19ae442e211cb3dd96", - "reference": "08ce32a41aa5d6c842b4cc19ae442e211cb3dd96", + "url": "https://api.github.com/repos/laravel-auto-presenter/laravel-auto-presenter/zipball/e139110a82c8a1573d4015b4f6d600d79e1d33e5", + "reference": "e139110a82c8a1573d4015b4f6d600d79e1d33e5", "shasum": "" }, "require": { - "illuminate/container": "5.1.*|5.2.*|5.3.*", - "illuminate/contracts": "5.1.*|5.2.*|5.3.*", - "illuminate/events": "5.1.*|5.2.*|5.3.*", - "illuminate/pagination": "5.1.*|5.2.*|5.3.*", - "illuminate/support": "5.1.*|5.2.*|5.3.*", - "illuminate/view": "5.1.*|5.2.*|5.3.*", - "php": ">=5.5.9" + "illuminate/container": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0", + "illuminate/contracts": "^5.5 || ^6.0 || ^7.0 || ^8.0|| ^9.0", + "illuminate/events": "^5.5 || ^6.0 || ^7.0 || ^8.0|| ^9.0", + "illuminate/pagination": "^5.5 || ^6.0 || ^7.0 || ^8.0|| ^9.0", + "illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0|| ^9.0", + "illuminate/view": "^5.5 || ^6.0 || ^7.0 || ^8.0|| ^9.0", + "php": "^7.1.3 || ^8.0" }, "require-dev": { - "graham-campbell/testbench": "^3.1", - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.8|^5.0" + "graham-campbell/analyzer": "^2.4 || ^3.0", + "graham-campbell/testbench": "^5.4", + "mockery/mockery": "^1.3.1", + "phpunit/phpunit": "^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.7" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.3-dev" + "dev-master": "7.7-dev" + }, + "laravel": { + "providers": [ + "McCool\\LaravelAutoPresenter\\AutoPresenterServiceProvider" + ] } }, "autoload": { @@ -2344,11 +3369,13 @@ "authors": [ { "name": "Shawn McCool", - "email": "shawn@heybigname.com" + "email": "shawn@mccool.email", + "homepage": "https://github.com/ShawnMcCool" }, { "name": "Graham Campbell", - "email": "graham@alt-three.com" + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" } ], "description": "A system for auto-decorating models with presenter objects.", @@ -2358,20 +3385,34 @@ "lpm", "presenter" ], - "time": "2016-05-01 15:29:13" + "support": { + "issues": "https://github.com/laravel-auto-presenter/laravel-auto-presenter/issues", + "source": "https://github.com/laravel-auto-presenter/laravel-auto-presenter/tree/7.7.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/mccool/laravel-auto-presenter", + "type": "tidelift" + } + ], + "time": "2022-02-09T09:14:24+00:00" }, { "name": "monolog/monolog", - "version": "1.20.0", + "version": "1.27.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "55841909e2bcde01b5318c35f2b74f8ecc86e037" + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/55841909e2bcde01b5318c35f2b74f8ecc86e037", - "reference": "55841909e2bcde01b5318c35f2b74f8ecc86e037", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", + "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", "shasum": "" }, "require": { @@ -2382,17 +3423,16 @@ "psr/log-implementation": "1.0.0" }, "require-dev": { - "aws/aws-sdk-php": "^2.4.9", + "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", "graylog2/gelf-php": "~1.0", - "jakub-onderka/php-parallel-lint": "0.9", "php-amqplib/php-amqplib": "~2.4", "php-console/php-console": "^3.1.3", + "phpstan/phpstan": "^0.12.59", "phpunit/phpunit": "~4.5", - "phpunit/phpunit-mock-objects": "2.3.0", "ruflin/elastica": ">=0.90 <3.0", "sentry/sentry": "^0.13", - "swiftmailer/swiftmailer": "~5.3" + "swiftmailer/swiftmailer": "^5.3|^6.0" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", @@ -2408,14 +3448,1733 @@ "sentry/sentry": "Allow sending log messages to a Sentry server" }, "type": "library", + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "http://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/1.27.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2022-06-09T08:53:42+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.6.1", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/9b87907a81b87bc76d19a7fb2d61e61486ee9edb", + "reference": "9b87907a81b87bc76d19a7fb2d61e61486ee9edb", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^1.4 || ^2.0", + "phpunit/phpunit": "^4.8.36 || ^7.5.15" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.6.1" + }, + "time": "2021-06-14T00:11:39+00:00" + }, + { + "name": "nesbot/carbon", + "version": "1.39.1", + "source": { + "type": "git", + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "4be0c005164249208ce1b5ca633cd57bdd42ff33" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4be0c005164249208ce1b5ca633cd57bdd42ff33", + "reference": "4be0c005164249208ce1b5ca633cd57bdd42ff33", + "shasum": "" + }, + "require": { + "kylekatarnls/update-helper": "^1.1", + "php": ">=5.3.9", + "symfony/translation": "~2.6 || ~3.0 || ~4.0" + }, + "require-dev": { + "composer/composer": "^1.2", + "friendsofphp/php-cs-fixer": "~2", + "phpunit/phpunit": "^4.8.35 || ^5.7" + }, + "bin": [ + "bin/upgrade-carbon" + ], + "type": "library", + "extra": { + "update-helper": "Carbon\\Upgrade", + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "http://nesbot.com" + } + ], + "description": "A simple API extension for DateTime.", + "homepage": "http://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "issues": "https://github.com/briannesbitt/Carbon/issues", + "source": "https://github.com/briannesbitt/Carbon" + }, + "time": "2019-10-14T05:51:36+00:00" + }, + { + "name": "nexmo/client", + "version": "1.9.1", + "source": { + "type": "git", + "url": "https://github.com/Nexmo/nexmo-php-complete.git", + "reference": "c6d11d953c8c5594590bb9ebaba9616e76948f93" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nexmo/nexmo-php-complete/zipball/c6d11d953c8c5594590bb9ebaba9616e76948f93", + "reference": "c6d11d953c8c5594590bb9ebaba9616e76948f93", + "shasum": "" + }, + "require": { + "nexmo/client-core": "^1.0", + "php": ">=5.6", + "php-http/guzzle6-adapter": "^1.0" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tim Lytle", + "email": "tim@nexmo.com", + "homepage": "http://twitter.com/tjlytle", + "role": "Developer" + }, + { + "name": "Michael Heap", + "email": "michael.heap@vonage.com", + "role": "Developer" + }, + { + "name": "Lorna Mitchell", + "email": "lorna.mitchell@vonage.com", + "role": "Developer" + } + ], + "description": "PHP Client for using Nexmo's API.", + "support": { + "email": "devrel@nexmo.com", + "source": "https://github.com/Nexmo/nexmo-php-complete/tree/1.9.1" + }, + "time": "2019-11-26T15:25:11+00:00" + }, + { + "name": "nexmo/client-core", + "version": "1.8.1", + "source": { + "type": "git", + "url": "https://github.com/Nexmo/nexmo-php.git", + "reference": "182d41a02ebd3e4be147baea45458ccfe2f528c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Nexmo/nexmo-php/zipball/182d41a02ebd3e4be147baea45458ccfe2f528c4", + "reference": "182d41a02ebd3e4be147baea45458ccfe2f528c4", + "shasum": "" + }, + "require": { + "lcobucci/jwt": "^3.2", + "php": ">=5.6", + "php-http/client-implementation": "^1.0", + "php-http/guzzle6-adapter": "^1.0", + "zendframework/zend-diactoros": "^1.8.4 || ^2.0" + }, + "require-dev": { + "estahn/phpunit-json-assertions": "^1.0.0", + "php-http/mock-client": "^0.3.0", + "phpunit/phpunit": "^5.7", + "squizlabs/php_codesniffer": "^3.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Nexmo\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Tim Lytle", + "email": "tim@nexmo.com", + "homepage": "http://twitter.com/tjlytle", + "role": "Developer" + } + ], + "description": "PHP Client for using Nexmo's API.", + "support": { + "email": "devrel@nexmo.com", + "source": "https://github.com/Nexmo/nexmo-php/tree/1.8.1" + }, + "time": "2019-05-13T20:27:43+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.17.1", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1" + }, + "time": "2023-08-13T19:53:39+00:00" + }, + { + "name": "opis/closure", + "version": "3.6.3", + "source": { + "type": "git", + "url": "https://github.com/opis/closure.git", + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/opis/closure/zipball/3d81e4309d2a927abbe66df935f4bb60082805ad", + "reference": "3d81e4309d2a927abbe66df935f4bb60082805ad", + "shasum": "" + }, + "require": { + "php": "^5.4 || ^7.0 || ^8.0" + }, + "require-dev": { + "jeremeamia/superclosure": "^2.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.6.x-dev" + } + }, + "autoload": { + "files": [ + "functions.php" + ], + "psr-4": { + "Opis\\Closure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marius Sarca", + "email": "marius.sarca@gmail.com" + }, + { + "name": "Sorin Sarca", + "email": "sarca_sorin@hotmail.com" + } + ], + "description": "A library that can be used to serialize closures (anonymous functions) and arbitrary objects.", + "homepage": "https://opis.io/closure", + "keywords": [ + "anonymous functions", + "closure", + "function", + "serializable", + "serialization", + "serialize" + ], + "support": { + "issues": "https://github.com/opis/closure/issues", + "source": "https://github.com/opis/closure/tree/3.6.3" + }, + "time": "2022-01-27T09:35:39+00:00" + }, + { + "name": "paragonie/constant_time_encoding", + "version": "v2.6.3", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "58c3f47f650c94ec05a151692652a868995d2938" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/58c3f47f650c94ec05a151692652a868995d2938", + "reference": "58c3f47f650c94ec05a151692652a868995d2938", + "shasum": "" + }, + "require": { + "php": "^7|^8" + }, + "require-dev": { + "phpunit/phpunit": "^6|^7|^8|^9", + "vimeo/psalm": "^1|^2|^3|^4" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "support": { + "email": "info@paragonie.com", + "issues": "https://github.com/paragonie/constant_time_encoding/issues", + "source": "https://github.com/paragonie/constant_time_encoding" + }, + "time": "2022-06-14T06:56:20+00:00" + }, + { + "name": "php-http/guzzle6-adapter", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/php-http/guzzle6-adapter.git", + "reference": "a56941f9dc6110409cfcddc91546ee97039277ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/guzzle6-adapter/zipball/a56941f9dc6110409cfcddc91546ee97039277ab", + "reference": "a56941f9dc6110409cfcddc91546ee97039277ab", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^6.0", + "php": ">=5.5.0", + "php-http/httplug": "^1.0" + }, + "provide": { + "php-http/async-client-implementation": "1.0", + "php-http/client-implementation": "1.0" + }, + "require-dev": { + "ext-curl": "*", + "php-http/adapter-integration-tests": "^0.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Adapter\\Guzzle6\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + }, + { + "name": "David de Boer", + "email": "david@ddeboer.nl" + } + ], + "description": "Guzzle 6 HTTP Adapter", + "homepage": "http://httplug.io", + "keywords": [ + "Guzzle", + "http" + ], + "support": { + "issues": "https://github.com/php-http/guzzle6-adapter/issues", + "source": "https://github.com/php-http/guzzle6-adapter/tree/master" + }, + "time": "2016-05-10T06:13:32+00:00" + }, + { + "name": "php-http/httplug", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/httplug.git", + "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/httplug/zipball/1c6381726c18579c4ca2ef1ec1498fdae8bdf018", + "reference": "1c6381726c18579c4ca2ef1ec1498fdae8bdf018", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "php-http/promise": "^1.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "henrikbjorn/phpspec-code-coverage": "^1.0", + "phpspec/phpspec": "^2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eric GELOEN", + "email": "geloen.eric@gmail.com" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "HTTPlug, the HTTP client abstraction for PHP", + "homepage": "http://httplug.io", + "keywords": [ + "client", + "http" + ], + "support": { + "issues": "https://github.com/php-http/httplug/issues", + "source": "https://github.com/php-http/httplug/tree/master" + }, + "time": "2016-08-31T08:30:17+00:00" + }, + { + "name": "php-http/promise", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-http/promise.git", + "reference": "ef4905bfb492ff389eb7f12e26925a0f20073050" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-http/promise/zipball/ef4905bfb492ff389eb7f12e26925a0f20073050", + "reference": "ef4905bfb492ff389eb7f12e26925a0f20073050", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "friends-of-phpspec/phpspec-code-coverage": "^4.3.2 || ^6.3", + "phpspec/phpspec": "^5.1.2 || ^6.2 || ^7.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Http\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Joel Wurtz", + "email": "joel.wurtz@gmail.com" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com" + } + ], + "description": "Promise used for asynchronous HTTP requests", + "homepage": "http://httplug.io", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/php-http/promise/issues", + "source": "https://github.com/php-http/promise/tree/1.2.0" + }, + "time": "2023-10-24T09:20:26+00:00" + }, + { + "name": "pragmarx/google2fa", + "version": "v5.0.0", + "source": { + "type": "git", + "url": "https://github.com/antonioribeiro/google2fa.git", + "reference": "17c969c82f427dd916afe4be50bafc6299aef1b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/17c969c82f427dd916afe4be50bafc6299aef1b4", + "reference": "17c969c82f427dd916afe4be50bafc6299aef1b4", + "shasum": "" + }, + "require": { + "paragonie/constant_time_encoding": "~1.0|~2.0", + "paragonie/random_compat": ">=1", + "php": ">=5.4", + "symfony/polyfill-php56": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4|~5|~6" + }, + "type": "library", + "extra": { + "component": "package", + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "PragmaRX\\Google2FA\\": "src/", + "PragmaRX\\Google2FA\\Tests\\": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Antonio Carlos Ribeiro", + "email": "acr@antoniocarlosribeiro.com", + "role": "Creator & Designer" + } + ], + "description": "A One Time Password Authentication package, compatible with Google Authenticator.", + "keywords": [ + "2fa", + "Authentication", + "Two Factor Authentication", + "google2fa" + ], + "support": { + "issues": "https://github.com/antonioribeiro/google2fa/issues", + "source": "https://github.com/antonioribeiro/google2fa/tree/master" + }, + "time": "2019-03-19T22:44:16+00:00" + }, + { + "name": "predis/predis", + "version": "v1.1.10", + "source": { + "type": "git", + "url": "https://github.com/predis/predis.git", + "reference": "a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/predis/predis/zipball/a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e", + "reference": "a2fb02d738bedadcffdbb07efa3a5e7bd57f8d6e", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "ext-curl": "Allows access to Webdis when paired with phpiredis", + "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" + }, + "type": "library", + "autoload": { + "psr-4": { + "Predis\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniele Alessandri", + "email": "suppakilla@gmail.com", + "homepage": "http://clorophilla.net", + "role": "Creator & Maintainer" + }, + { + "name": "Till Krüss", + "homepage": "https://till.im", + "role": "Maintainer" + } + ], + "description": "Flexible and feature-complete Redis client for PHP and HHVM", + "homepage": "http://github.com/predis/predis", + "keywords": [ + "nosql", + "predis", + "redis" + ], + "support": { + "issues": "https://github.com/predis/predis/issues", + "source": "https://github.com/predis/predis/tree/v1.1.10" + }, + "funding": [ + { + "url": "https://github.com/sponsors/tillkruss", + "type": "github" + } + ], + "time": "2022-01-05T17:46:08+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/master" + }, + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "e616d01114759c4c489f93b099585439f795fe35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", + "reference": "e616d01114759c4c489f93b099585439f795fe35", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + }, + "time": "2023-04-10T20:10:41+00:00" + }, + { + "name": "psr/http-message", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/master" + }, + "time": "2016-08-06T14:39:51+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "time": "2017-10-23T01:57:42+00:00" + }, + { + "name": "psy/psysh", + "version": "v0.9.12", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "90da7f37568aee36b116a030c5f99c915267edd4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/90da7f37568aee36b116a030c5f99c915267edd4", + "reference": "90da7f37568aee36b116a030c5f99c915267edd4", + "shasum": "" + }, + "require": { + "dnoegel/php-xdg-base-dir": "0.1.*", + "ext-json": "*", + "ext-tokenizer": "*", + "jakub-onderka/php-console-highlighter": "0.3.*|0.4.*", + "nikic/php-parser": "~1.3|~2.0|~3.0|~4.0", + "php": ">=5.4.0", + "symfony/console": "~2.3.10|^2.4.2|~3.0|~4.0|~5.0", + "symfony/var-dumper": "~2.7|~3.0|~4.0|~5.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", + "hoa/console": "~2.15|~3.16", + "phpunit/phpunit": "~4.8.35|~5.0|~6.0|~7.0" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", + "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history.", + "hoa/console": "A pure PHP readline implementation. You'll want this if your PHP install doesn't already support readline or libedit." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-develop": "0.9.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "support": { + "issues": "https://github.com/bobthecow/psysh/issues", + "source": "https://github.com/bobthecow/psysh/tree/v0.9.12" + }, + "time": "2019-12-06T14:19:43+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "ramsey/uuid", + "version": "3.9.7", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "dc75aa439eb4c1b77f5379fd958b3dc0e6014178" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/dc75aa439eb4c1b77f5379fd958b3dc0e6014178", + "reference": "dc75aa439eb4c1b77f5379fd958b3dc0e6014178", + "shasum": "" + }, + "require": { + "ext-json": "*", + "paragonie/random_compat": "^1 | ^2 | ^9.99.99", + "php": "^5.4 | ^7.0 | ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "codeception/aspect-mock": "^1 | ^2", + "doctrine/annotations": "^1.2", + "goaop/framework": "1.0.0-alpha.2 | ^1 | >=2.1.0 <=2.3.2", + "mockery/mockery": "^0.9.11 | ^1", + "moontoast/math": "^1.1", + "nikic/php-parser": "<=4.5.0", + "paragonie/random-lib": "^2", + "php-mock/php-mock-phpunit": "^0.3 | ^1.1 | ^2.6", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpunit/phpunit": ">=4.8.36 <9.0.0 | >=9.3.0", + "squizlabs/php_codesniffer": "^3.5", + "yoast/phpunit-polyfills": "^1.0" + }, + "suggest": { + "ext-ctype": "Provides support for PHP Ctype functions", + "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", + "ext-openssl": "Provides the OpenSSL extension for use with the OpenSslGenerator", + "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", + "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + }, + { + "name": "Marijn Huizendveld", + "email": "marijn.huizendveld@gmail.com" + }, + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + } + ], + "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", + "homepage": "https://github.com/ramsey/uuid", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "rss": "https://github.com/ramsey/uuid/releases.atom", + "source": "https://github.com/ramsey/uuid", + "wiki": "https://github.com/ramsey/uuid/wiki" + }, + "funding": [ + { + "url": "https://github.com/ramsey", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", + "type": "tidelift" + } + ], + "time": "2022-12-19T21:55:10+00:00" + }, + { + "name": "swiftmailer/swiftmailer", + "version": "v6.3.0", + "source": { + "type": "git", + "url": "https://github.com/swiftmailer/swiftmailer.git", + "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/8a5d5072dca8f48460fce2f4131fcc495eec654c", + "reference": "8a5d5072dca8f48460fce2f4131fcc495eec654c", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.0|^3.1", + "php": ">=7.0.0", + "symfony/polyfill-iconv": "^1.0", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "symfony/phpunit-bridge": "^4.4|^5.4" + }, + "suggest": { + "ext-intl": "Needed to support internationalized email addresses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "6.2-dev" + } + }, + "autoload": { + "files": [ + "lib/swift_required.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Corbyn" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Swiftmailer, free feature-rich PHP mailer", + "homepage": "https://swiftmailer.symfony.com", + "keywords": [ + "email", + "mail", + "mailer" + ], + "support": { + "issues": "https://github.com/swiftmailer/swiftmailer/issues", + "source": "https://github.com/swiftmailer/swiftmailer/tree/v6.3.0" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/swiftmailer/swiftmailer", + "type": "tidelift" + } + ], + "abandoned": "symfony/mailer", + "time": "2021-10-18T15:26:12+00:00" + }, + { + "name": "symfony/console", + "version": "v4.4.49", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", + "reference": "33fa45ffc81fdcc1ca368d4946da859c8cdb58d9", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "psr/log": ">=3", + "symfony/dependency-injection": "<3.4", + "symfony/event-dispatcher": "<4.3|>=5", + "symfony/lock": "<4.4", + "symfony/process": "<3.3" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/event-dispatcher": "^4.3", + "symfony/lock": "^4.4|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/var-dumper": "^4.3|^5.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/console/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-11-05T17:10:16+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "reference": "bd0a6737e48de45b4b0b7b6fc98c78404ddceaed", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" + }, + { + "name": "symfony/debug", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3" + }, + "conflict": { + "symfony/http-kernel": "<3.4" + }, + "require-dev": { + "symfony/http-kernel": "^3.4|^4.0|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "abandoned": "symfony/error-handler", + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/be731658121ef2d8be88f3a1ec938148a9237291", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-28T16:29:46+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v4.4.44", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.13", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e", + "shasum": "" + }, + "require": { + "php": ">=7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { "psr-4": { - "Monolog\\": "src/Monolog" + "Symfony\\Contracts\\EventDispatcher\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -2424,45 +5183,69 @@ ], "authors": [ { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", "keywords": [ - "log", - "logging", - "psr-3" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2016-07-02 14:02:10" + "time": "2022-01-02T09:41:36+00:00" }, { - "name": "mtdowling/cron-expression", - "version": "v1.1.0", + "name": "symfony/finder", + "version": "v4.4.44", "source": { "type": "git", - "url": "https://github.com/mtdowling/cron-expression.git", - "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5" + "url": "https://github.com/symfony/finder.git", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/c9ee7886f5a12902b225a1a12f36bb45f9ab89e5", - "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5", + "url": "https://api.github.com/repos/symfony/finder/zipball/66bd787edb5e42ff59d3523f623895af05043e4f", + "reference": "66bd787edb5e42ff59d3523f623895af05043e4f", "shasum": "" }, "require": { - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.0|~5.0" + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { - "psr-0": { - "Cron": "src/" - } + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2470,54 +5253,69 @@ ], "authors": [ { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", - "keywords": [ - "cron", - "schedule" + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2016-01-26 21:23:30" + "time": "2022-07-29T07:35:46+00:00" }, { - "name": "mtdowling/jmespath.php", - "version": "2.3.0", + "name": "symfony/http-client-contracts", + "version": "v1.1.13", "source": { "type": "git", - "url": "https://github.com/jmespath/jmespath.php.git", - "reference": "192f93e43c2c97acde7694993ab171b3de284093" + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "59f37624a82635962f04c98f31aed122e539a89e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/192f93e43c2c97acde7694993ab171b3de284093", - "reference": "192f93e43c2c97acde7694993ab171b3de284093", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/59f37624a82635962f04c98f31aed122e539a89e", + "reference": "59f37624a82635962f04c98f31aed122e539a89e", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": ">=7.1.3" }, - "require-dev": { - "phpunit/phpunit": "~4.0" + "suggest": { + "symfony/http-client-implementation": "" }, - "bin": [ - "bin/jp.php" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { "psr-4": { - "JmesPath\\": "src/" - }, - "files": [ - "src/JmesPath.php" - ] + "Symfony\\Contracts\\HttpClient\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2525,44 +5323,75 @@ ], "authors": [ { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Declaratively specify how to extract elements from a JSON document", + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", "keywords": [ - "json", - "jsonpath" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v1.1.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2016-01-05 18:25:05" + "time": "2022-04-11T14:52:04+00:00" }, { - "name": "nesbot/carbon", - "version": "1.21.0", + "name": "symfony/http-foundation", + "version": "v4.4.49", "source": { "type": "git", - "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7" + "url": "https://github.com/symfony/http-foundation.git", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7b08ec6f75791e130012f206e3f7b0e76e18e3d7", - "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/191413c7b832c015bb38eae963f2e57498c3c173", + "reference": "191413c7b832c015bb38eae963f2e57498c3c173", "shasum": "" }, "require": { - "php": ">=5.3.0", - "symfony/translation": "~2.6|~3.0" + "php": ">=7.1.3", + "symfony/mime": "^4.3|^5.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "phpunit/phpunit": "~4.0|~5.0" + "predis/predis": "~1.0", + "symfony/expression-language": "^3.4|^4.0|^5.0" }, "type": "library", "autoload": { "psr-4": { - "Carbon\\": "src/Carbon/" - } + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2570,98 +5399,174 @@ ], "authors": [ { - "name": "Brian Nesbitt", - "email": "brian@nesbot.com", - "homepage": "http://nesbot.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "A simple API extension for DateTime.", - "homepage": "http://carbon.nesbot.com", - "keywords": [ - "date", - "datetime", - "time" + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v4.4.49" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2015-11-04 20:07:17" + "time": "2022-11-04T16:17:57+00:00" }, { - "name": "nikic/php-parser", - "version": "v2.1.0", + "name": "symfony/http-kernel", + "version": "v4.4.50", "source": { "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3" + "url": "https://github.com/symfony/http-kernel.git", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/47b254ea51f1d6d5dc04b9b299e88346bf2369e3", - "reference": "47b254ea51f1d6d5dc04b9b299e88346bf2369e3", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aa6df6c045f034aa13ac752fc234bb300b9488ef", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": ">=5.4" + "php": ">=7.1.3", + "psr/log": "^1|^2", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/http-foundation": "^4.4.30|^5.3.7", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.43|<2.13,>=2" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.43|^2.13|^3.0.4" }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1-dev" - } + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" }, + "type": "library", "autoload": { "psr-4": { - "PhpParser\\": "lib/PhpParser" - } + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Nikita Popov" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v4.4.50" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2016-04-19 13:41:41" + "time": "2023-02-01T08:01:31+00:00" }, { - "name": "paragonie/random_compat", - "version": "v1.4.1", + "name": "symfony/mime", + "version": "v4.4.47", "source": { "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "c7e26a21ba357863de030f0b9e701c7d04593774" + "url": "https://github.com/symfony/mime.git", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774", - "reference": "c7e26a21ba357863de030f0b9e701c7d04593774", + "url": "https://api.github.com/repos/symfony/mime/zipball/0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", + "reference": "0eaf33cd6d1b3eaa50e7bc48b17f6e45789df35d", "shasum": "" }, "require": { - "php": ">=5.2.0" + "php": ">=7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16" }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*" + "conflict": { + "egulias/email-validator": "~3.0.0", + "symfony/mailer": "<4.4" }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1", + "symfony/dependency-injection": "^3.4|^4.1|^5.0" }, "type": "library", "autoload": { - "files": [ - "lib/random.php" + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2670,99 +5575,160 @@ ], "authors": [ { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", "keywords": [ - "csprng", - "pseudorandom", - "random" + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2016-03-18 20:34:03" + "time": "2022-10-03T15:15:11+00:00" }, { - "name": "pragmarx/google2fa", - "version": "v0.7.1", + "name": "symfony/polyfill-ctype", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/antonioribeiro/google2fa.git", - "reference": "908678ba9b26cf8ecd7ddca6bfd86afc5b4874df" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/908678ba9b26cf8ecd7ddca6bfd86afc5b4874df", - "reference": "908678ba9b26cf8ecd7ddca6bfd86afc5b4874df", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { - "christian-riesen/base32": "~1.0", - "php": ">=5.3.7", - "simplesoftwareio/simple-qrcode": "1.3.*" + "php": ">=7.1" }, - "require-dev": { - "phpspec/phpspec": "~2.1" + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" }, "type": "library", "extra": { - "component": "package", - "frameworks": [ - "Laravel" - ] + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "PragmaRX\\Google2FA\\": "src/" + "Symfony\\Polyfill\\Ctype\\": "" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Antonio Carlos Ribeiro", - "email": "acr@antoniocarlosribeiro.com", - "role": "Creator & Designer" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "A One Time Password Authentication package, compatible with Google Authenticator.", + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", "keywords": [ - "Authentication", - "Two Factor Authentication", - "google2fa", - "laravel" + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2015-11-07 13:57:42" + "time": "2023-01-26T09:26:14+00:00" }, { - "name": "psr/http-message", - "version": "1.0", + "name": "symfony/polyfill-iconv", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" + "url": "https://github.com/symfony/polyfill-iconv.git", + "reference": "6de50471469b8c9afc38164452ab2b6170ee71c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/6de50471469b8c9afc38164452ab2b6170ee71c1", + "reference": "6de50471469b8c9afc38164452ab2b6170ee71c1", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.1" + }, + "provide": { + "ext-iconv": "*" + }, + "suggest": { + "ext-iconv": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Psr\\Http\\Message\\": "src/" + "Symfony\\Polyfill\\Iconv\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -2771,108 +5737,80 @@ ], "authors": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Common interface for HTTP messages", + "description": "Symfony polyfill for the Iconv extension", + "homepage": "https://symfony.com", "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" + "compatibility", + "iconv", + "polyfill", + "portable", + "shim" ], - "time": "2015-05-04 20:22:00" - }, - { - "name": "psr/log", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", - "shasum": "" - }, - "type": "library", - "autoload": { - "psr-0": { - "Psr\\Log\\": "" - } + "support": { + "source": "https://github.com/symfony/polyfill-iconv/tree/v1.28.0" }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ + "funding": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" } ], - "description": "Common interface for logging libraries", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2012-12-21 11:40:51" + "time": "2023-01-26T09:26:14+00:00" }, { - "name": "psy/psysh", - "version": "v0.7.2", + "name": "symfony/polyfill-intl-idn", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/bobthecow/psysh.git", - "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280" + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "ecaafce9f77234a6a449d29e49267ba10499116d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/e64e10b20f8d229cac76399e1f3edddb57a0f280", - "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/ecaafce9f77234a6a449d29e49267ba10499116d", + "reference": "ecaafce9f77234a6a449d29e49267ba10499116d", "shasum": "" }, "require": { - "dnoegel/php-xdg-base-dir": "0.1", - "jakub-onderka/php-console-highlighter": "0.3.*", - "nikic/php-parser": "^1.2.1|~2.0", - "php": ">=5.3.9", - "symfony/console": "~2.3.10|^2.4.2|~3.0", - "symfony/var-dumper": "~2.7|~3.0" - }, - "require-dev": { - "fabpot/php-cs-fixer": "~1.5", - "phpunit/phpunit": "~3.7|~4.0|~5.0", - "squizlabs/php_codesniffer": "~2.0", - "symfony/finder": "~2.1|~3.0" + "php": ">=7.1", + "symfony/polyfill-intl-normalizer": "^1.10", + "symfony/polyfill-php72": "^1.10" }, "suggest": { - "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", - "ext-pdo-sqlite": "The doc command requires SQLite to work.", - "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", - "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history." + "ext-intl": "For best performance" }, - "bin": [ - "bin/psysh" - ], "type": "library", "extra": { "branch-alias": { - "dev-develop": "0.8.x-dev" + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { "files": [ - "src/Psy/functions.php" + "bootstrap.php" ], "psr-4": { - "Psy\\": "src/Psy/" + "Symfony\\Polyfill\\Intl\\Idn\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -2881,63 +5819,87 @@ ], "authors": [ { - "name": "Justin Hileman", - "email": "justin@justinhileman.info", - "homepage": "http://justinhileman.com" + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "An interactive shell for modern PHP.", - "homepage": "http://psysh.org", + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", "keywords": [ - "REPL", - "console", - "interactive", - "shell" + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2016-03-09 05:03:14" + "time": "2023-01-26T09:30:37+00:00" }, { - "name": "rcrowe/twigbridge", - "version": "v0.9.2", + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/rcrowe/TwigBridge.git", - "reference": "78a4b7da75042660258a3269751c259eee81c34a" + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rcrowe/TwigBridge/zipball/78a4b7da75042660258a3269751c259eee81c34a", - "reference": "78a4b7da75042660258a3269751c259eee81c34a", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", + "reference": "8c4ad05dd0120b6a53c1ca374dca2ad0a1c4ed92", "shasum": "" }, "require": { - "illuminate/support": "5.0.*|5.1.*|5.2.*", - "illuminate/view": "5.0.*|5.1.*|5.2.*", - "php": ">=5.4.0", - "twig/twig": "~1.15|~2.0" - }, - "require-dev": { - "laravel/framework": "5.0.*", - "mockery/mockery": "0.9.*", - "phpunit/phpunit": "~4.0", - "satooshi/php-coveralls": "~0.6", - "squizlabs/php_codesniffer": "~1.5" + "php": ">=7.1" }, "suggest": { - "laravelcollective/html": "For bringing back html/form in Laravel 5.x", - "twig/extensions": "~1.0" + "ext-intl": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "0.10-dev" + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "TwigBridge\\": "src", - "TwigBridge\\Tests\\": "tests" - } + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2945,47 +5907,68 @@ ], "authors": [ { - "name": "Barry vd. Heuvel", - "email": "barryvdh@gmail.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Rob Crowe", - "email": "hello@vivalacrowe.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Adds the power of Twig to Laravel", + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", "keywords": [ - "laravel", - "twig" + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2016-02-22 07:48:48" + "time": "2023-01-26T09:26:14+00:00" }, { - "name": "roumen/feed", - "version": "v2.10.4", + "name": "symfony/polyfill-php56", + "version": "v1.20.0", "source": { "type": "git", - "url": "https://github.com/RoumenDamianoff/laravel-feed.git", - "reference": "900594412cab37515b2b53c8953af1201024e48d" + "url": "https://github.com/symfony/polyfill-php56.git", + "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/RoumenDamianoff/laravel-feed/zipball/900594412cab37515b2b53c8953af1201024e48d", - "reference": "900594412cab37515b2b53c8953af1201024e48d", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", + "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", "shasum": "" }, "require": { - "illuminate/support": "^5.0", - "php": ">=5.5.9" + "php": ">=7.1" }, - "require-dev": { - "orchestra/testbench": "^3.0", - "phpunit/phpunit": "^4.8" - }, - "type": "library", - "autoload": { - "psr-0": { - "Roumen\\Feed": "src/" + "type": "metapackage", + "extra": { + "branch-alias": { + "dev-main": "1.20-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "notification-url": "https://packagist.org/downloads/", @@ -2994,51 +5977,74 @@ ], "authors": [ { - "name": "Roumen Damianoff", - "email": "roumen@dawebs.com", - "homepage": "https://roumen.it", - "role": "Developer" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "A simple feed generator for Laravel.", - "homepage": "https://roumen.it/projects/laravel-feed", + "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "homepage": "https://symfony.com", "keywords": [ - "atom", - "feed", - "generator", - "laravel", - "rss" + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php56/tree/v1.20.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2016-07-17 13:06:35" + "time": "2020-10-23T14:02:19+00:00" }, { - "name": "simplesoftwareio/simple-qrcode", - "version": "1.3.3", + "name": "symfony/polyfill-php72", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/SimpleSoftwareIO/simple-qrcode.git", - "reference": "17c5e45c79c40f717d4bc08cf5e568f29ebf9333" + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/SimpleSoftwareIO/simple-qrcode/zipball/17c5e45c79c40f717d4bc08cf5e568f29ebf9333", - "reference": "17c5e45c79c40f717d4bc08cf5e568f29ebf9333", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/70f4aebd92afca2f865444d30a4d2151c13c3179", + "reference": "70f4aebd92afca2f865444d30a4d2151c13c3179", "shasum": "" }, "require": { - "bacon/bacon-qr-code": "1.0.*", - "ext-gd": "*", - "illuminate/support": ">=4.2.0", - "php": ">=5.4.0" - }, - "require-dev": { - "mockery/mockery": "0.9.*", - "phpunit/phpunit": "4.7.*" + "php": ">=7.1" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, "autoload": { - "psr-0": { - "SimpleSoftwareIO\\QrCode\\": "src" + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php72\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -3047,50 +6053,77 @@ ], "authors": [ { - "name": "Simple Software LLC", - "email": "support@simplesoftware.io" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Simple QrCode is a QR code generator made for Laravel.", - "homepage": "http://www.simplesoftware.io", + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "homepage": "https://symfony.com", "keywords": [ - "Simple", - "generator", - "laravel", - "qrcode", - "wrapper" + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php72/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2016-01-31 02:09:25" + "time": "2023-01-26T09:26:14+00:00" }, { - "name": "swiftmailer/swiftmailer", - "version": "v5.4.3", + "name": "symfony/polyfill-php73", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/swiftmailer/swiftmailer.git", - "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153" + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", - "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", "shasum": "" }, "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "mockery/mockery": "~0.9.1" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "5.4-dev" + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { "files": [ - "lib/swift_required.php" + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3099,62 +6132,77 @@ ], "authors": [ { - "name": "Chris Corbyn" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Swiftmailer, free feature-rich PHP mailer", - "homepage": "http://swiftmailer.org", + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", "keywords": [ - "email", - "mail", - "mailer" + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } ], - "time": "2016-07-08 11:51:25" + "time": "2023-01-26T09:26:14+00:00" }, { - "name": "symfony/console", - "version": "v3.0.8", + "name": "symfony/polyfill-php80", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "a7abb7153f6d1da47f87ec50274844e246b09d9f" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/a7abb7153f6d1da47f87ec50274844e246b09d9f", - "reference": "a7abb7153f6d1da47f87ec50274844e246b09d9f", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/process": "" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { + "files": [ + "bootstrap.php" + ], "psr-4": { - "Symfony\\Component\\Console\\": "" + "Symfony\\Polyfill\\Php80\\": "" }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3163,44 +6211,67 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Console Component", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", "homepage": "https://symfony.com", - "time": "2016-06-29 07:02:21" + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-01-26T09:26:14+00:00" }, { - "name": "symfony/css-selector", - "version": "v3.1.2", + "name": "symfony/process", + "version": "v4.4.44", "source": { "type": "git", - "url": "https://github.com/symfony/css-selector.git", - "reference": "2851e1932d77ce727776154d659b232d061e816a" + "url": "https://github.com/symfony/process.git", + "reference": "5cee9cdc4f7805e2699d9fd66991a0e6df8252a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/2851e1932d77ce727776154d659b232d061e816a", - "reference": "2851e1932d77ce727776154d659b232d061e816a", + "url": "https://api.github.com/repos/symfony/process/zipball/5cee9cdc4f7805e2699d9fd66991a0e6df8252a2", + "reference": "5cee9cdc4f7805e2699d9fd66991a0e6df8252a2", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, "autoload": { "psr-4": { - "Symfony\\Component\\CssSelector\\": "" + "Symfony\\Component\\Process\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -3211,10 +6282,6 @@ "MIT" ], "authors": [ - { - "name": "Jean-François Simon", - "email": "jeanfrancois.simon@sensiolabs.com" - }, { "name": "Fabien Potencier", "email": "fabien@symfony.com" @@ -3224,44 +6291,70 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony CssSelector Component", + "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", - "time": "2016-06-29 05:41:56" + "support": { + "source": "https://github.com/symfony/process/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" }, { - "name": "symfony/debug", - "version": "v3.0.8", + "name": "symfony/routing", + "version": "v4.4.44", "source": { "type": "git", - "url": "https://github.com/symfony/debug.git", - "reference": "c54bc3539c3b87e86799533801e8ae0e971d78c2" + "url": "https://github.com/symfony/routing.git", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/c54bc3539c3b87e86799533801e8ae0e971d78c2", - "reference": "c54bc3539c3b87e86799533801e8ae0e971d78c2", + "url": "https://api.github.com/repos/symfony/routing/zipball/f7751fd8b60a07f3f349947a309b5bdfce22d6ae", + "reference": "f7751fd8b60a07f3f349947a309b5bdfce22d6ae", "shasum": "" }, "require": { - "php": ">=5.5.9", - "psr/log": "~1.0" + "php": ">=7.1.3", + "symfony/polyfill-php80": "^1.16" }, "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "symfony/config": "<4.2", + "symfony/dependency-injection": "<3.4", + "symfony/yaml": "<3.4" }, "require-dev": { - "symfony/class-loader": "~2.8|~3.0", - "symfony/http-kernel": "~2.8|~3.0" + "doctrine/annotations": "^1.10.4", + "psr/log": "^1|^2|^3", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/yaml": "^3.4|^4.0|^5.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } + "suggest": { + "doctrine/annotations": "For using the annotation loader", + "symfony/config": "For using the all-in-one router or any loader", + "symfony/expression-language": "For using expression matching", + "symfony/http-foundation": "For using a Symfony Request object", + "symfony/yaml": "For using the YAML loader" }, + "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Debug\\": "" + "Symfony\\Component\\Routing\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -3281,51 +6374,68 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Debug Component", + "description": "Maps an HTTP request to a set of configuration variables", "homepage": "https://symfony.com", - "time": "2016-06-29 05:40:00" + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v4.4.44" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-07-20T09:59:04+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v3.1.2", + "name": "symfony/service-contracts", + "version": "v1.1.13", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "7f9839ede2070f53e7e2f0849b9bd14748c434c5" + "url": "https://github.com/symfony/service-contracts.git", + "reference": "afa00c500c2d6aea6e3b2f4862355f507bc5ebb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/7f9839ede2070f53e7e2f0849b9bd14748c434c5", - "reference": "7f9839ede2070f53e7e2f0849b9bd14748c434c5", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/afa00c500c2d6aea6e3b2f4862355f507bc5ebb4", + "reference": "afa00c500c2d6aea6e3b2f4862355f507bc5ebb4", "shasum": "" }, "require": { - "php": ">=5.5.9" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0", - "symfony/dependency-injection": "~2.8|~3.0", - "symfony/expression-language": "~2.8|~3.0", - "symfony/stopwatch": "~2.8|~3.0" + "php": ">=7.1.3", + "psr/container": "^1.0" }, "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "symfony/service-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\Service\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3333,44 +6443,92 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "description": "Generic abstractions related to writing services", "homepage": "https://symfony.com", - "time": "2016-06-29 05:41:56" + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v1.1.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-05-27T14:01:05+00:00" }, { - "name": "symfony/finder", - "version": "v3.0.8", + "name": "symfony/translation", + "version": "v4.4.47", "source": { "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "3eb4e64c6145ef8b92adefb618a74ebdde9e3fe9" + "url": "https://github.com/symfony/translation.git", + "reference": "45036b1d53accc48fe9bab71ccd86d57eba0dd94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/3eb4e64c6145ef8b92adefb618a74ebdde9e3fe9", - "reference": "3eb4e64c6145ef8b92adefb618a74ebdde9e3fe9", + "url": "https://api.github.com/repos/symfony/translation/zipball/45036b1d53accc48fe9bab71ccd86d57eba0dd94", + "reference": "45036b1d53accc48fe9bab71ccd86d57eba0dd94", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/translation-contracts": "^1.1.6|^2" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } + "conflict": { + "symfony/config": "<3.4", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4", + "symfony/yaml": "<3.4" + }, + "provide": { + "symfony/translation-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/finder": "~2.8|~3.0|~4.0|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/intl": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1.2|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" }, + "suggest": { + "psr/log-implementation": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Finder\\": "" + "Symfony\\Component\\Translation\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -3390,44 +6548,61 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Finder Component", + "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", - "time": "2016-06-29 05:40:00" + "support": { + "source": "https://github.com/symfony/translation/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" }, { - "name": "symfony/http-foundation", - "version": "v3.0.8", + "name": "symfony/translation-contracts", + "version": "v1.1.13", "source": { "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "1341139f906d295baa4f4abd55293d07e25a065a" + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "7462e5c4cb8b9cd152f992e8f10963b5641921f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/1341139f906d295baa4f4abd55293d07e25a065a", - "reference": "1341139f906d295baa4f4abd55293d07e25a065a", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/7462e5c4cb8b9cd152f992e8f10963b5641921f6", + "reference": "7462e5c4cb8b9cd152f992e8f10963b5641921f6", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/polyfill-mbstring": "~1.1" + "php": ">=7.1.3" }, - "require-dev": { - "symfony/expression-language": "~2.8|~3.0" + "suggest": { + "symfony/translation-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\Translation\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3435,77 +6610,88 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpFoundation Component", + "description": "Generic abstractions related to translation", "homepage": "https://symfony.com", - "time": "2016-06-29 07:02:21" + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v1.1.13" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-06-27T13:16:42+00:00" }, { - "name": "symfony/http-kernel", - "version": "v3.0.8", + "name": "symfony/var-dumper", + "version": "v4.4.47", "source": { "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "177b63b2d50b63fa6d82ea41359ed9928cc7a1fb" + "url": "https://github.com/symfony/var-dumper.git", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/177b63b2d50b63fa6d82ea41359ed9928cc7a1fb", - "reference": "177b63b2d50b63fa6d82ea41359ed9928cc7a1fb", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/1069c7a3fca74578022fab6f81643248d02f8e63", + "reference": "1069c7a3fca74578022fab6f81643248d02f8e63", "shasum": "" }, "require": { - "php": ">=5.5.9", - "psr/log": "~1.0", - "symfony/debug": "~2.8|~3.0", - "symfony/event-dispatcher": "~2.8|~3.0", - "symfony/http-foundation": "~2.8.8|~3.0.8|~3.1.2|~3.2" + "php": ">=7.1.3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php72": "~1.5", + "symfony/polyfill-php80": "^1.16" }, "conflict": { - "symfony/config": "<2.8" + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<3.4" }, "require-dev": { - "symfony/browser-kit": "~2.8|~3.0", - "symfony/class-loader": "~2.8|~3.0", - "symfony/config": "~2.8|~3.0", - "symfony/console": "~2.8|~3.0", - "symfony/css-selector": "~2.8|~3.0", - "symfony/dependency-injection": "~2.8|~3.0", - "symfony/dom-crawler": "~2.8|~3.0", - "symfony/expression-language": "~2.8|~3.0", - "symfony/finder": "~2.8|~3.0", - "symfony/process": "~2.8|~3.0", - "symfony/routing": "~2.8|~3.0", - "symfony/stopwatch": "~2.8|~3.0", - "symfony/templating": "~2.8|~3.0", - "symfony/translation": "~2.8|~3.0", - "symfony/var-dumper": "~2.8|~3.0" + "ext-iconv": "*", + "symfony/console": "^3.4|^4.0|^5.0", + "symfony/process": "^4.4|^5.0", + "twig/twig": "^1.43|^2.13|^3.0.4" }, "suggest": { - "symfony/browser-kit": "", - "symfony/class-loader": "", - "symfony/config": "", - "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/finder": "", - "symfony/var-dumper": "" + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" }, + "bin": [ + "Resources/bin/var-dump-server" + ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, "autoload": { + "files": [ + "Resources/functions/dump.php" + ], "psr-4": { - "Symfony\\Component\\HttpKernel\\": "" + "Symfony\\Component\\VarDumper\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -3517,284 +6703,356 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpKernel Component", + "description": "Provides mechanisms for walking through any arbitrary PHP variable", "homepage": "https://symfony.com", - "time": "2016-06-30 16:30:17" + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v4.4.47" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-10-03T15:15:11+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.2.0", + "name": "tijsverkoyen/css-to-inline-styles", + "version": "2.2.6", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "dff51f72b0706335131b00a7f49606168c582594" + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "c42125b83a4fa63b187fdf29f9c93cb7733da30c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", - "reference": "dff51f72b0706335131b00a7f49606168c582594", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/c42125b83a4fa63b187fdf29f9c93cb7733da30c", + "reference": "c42125b83a4fa63b187fdf29f9c93cb7733da30c", "shasum": "" }, "require": { - "php": ">=5.3.3" + "ext-dom": "*", + "ext-libxml": "*", + "php": "^5.5 || ^7.0 || ^8.0", + "symfony/css-selector": "^2.7 || ^3.0 || ^4.0 || ^5.0 || ^6.0" }, - "suggest": { - "ext-mbstring": "For best performance" + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^7.5 || ^8.5.21 || ^9.5.10" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "2.2.x-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] + "TijsVerkoyen\\CssToInlineStyles\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Tijs Verkoyen", + "email": "css_to_inline_styles@verkoyen.eu", + "role": "Developer" } ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "time": "2016-05-18 14:26:46" + "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", + "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", + "support": { + "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/2.2.6" + }, + "time": "2023-01-03T09:29:04+00:00" }, { - "name": "symfony/polyfill-php56", - "version": "v1.2.0", + "name": "twig/twig", + "version": "v2.15.5", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php56.git", - "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a" + "url": "https://github.com/twigphp/Twig.git", + "reference": "fc02a6af3eeb97c4bf5650debc76c2eda85ac22e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/3edf57a8fbf9a927533344cef65ad7e1cf31030a", - "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/fc02a6af3eeb97c4bf5650debc76c2eda85ac22e", + "reference": "fc02a6af3eeb97c4bf5650debc76c2eda85ac22e", "shasum": "" }, "require": { - "php": ">=5.3.3", - "symfony/polyfill-util": "~1.0" + "php": ">=7.1.3", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3", + "symfony/polyfill-php72": "^1.8" + }, + "require-dev": { + "psr/container": "^1.0", + "symfony/phpunit-bridge": "^4.4.9|^5.0.9|^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "2.15-dev" } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php56\\": "" - }, - "files": [ - "bootstrap.php" - ] + "psr-0": { + "Twig_": "lib/" + }, + "psr-4": { + "Twig\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" } ], - "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", - "homepage": "https://symfony.com", + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v2.15.5" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } ], - "time": "2016-05-18 14:26:46" + "time": "2023-05-03T17:49:41+00:00" }, { - "name": "symfony/polyfill-util", - "version": "v1.2.0", + "name": "vlucas/phpdotenv", + "version": "v2.6.9", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-util.git", - "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99" + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "2e93cc98e2e8e869f8d9cfa61bb3a99ba4fc4141" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/ef830ce3d218e622b221d6bfad42c751d974bf99", - "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2e93cc98e2e8e869f8d9cfa61bb3a99ba4fc4141", + "reference": "2e93cc98e2e8e869f8d9cfa61bb3a99ba4fc4141", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^5.3.9 || ^7.0 || ^8.0", + "symfony/polyfill-ctype": "^1.17" + }, + "require-dev": { + "ext-filter": "*", + "ext-pcre": "*", + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.21" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator.", + "ext-pcre": "Required to use most of the library." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "2.6-dev" } }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Util\\": "" + "Dotenv\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" } ], - "description": "Symfony utilities for portability of PHP codes", - "homepage": "https://symfony.com", + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", "keywords": [ - "compat", - "compatibility", - "polyfill", - "shim" + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v2.6.9" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } ], - "time": "2016-05-18 14:26:46" + "time": "2021-12-12T22:59:22+00:00" }, { - "name": "symfony/process", - "version": "v3.0.8", + "name": "zendframework/zend-diactoros", + "version": "2.2.1", "source": { "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "d7cde1f9d94d87060204f863779389b61c382eeb" + "url": "https://github.com/zendframework/zend-diactoros.git", + "reference": "de5847b068362a88684a55b0dbb40d85986cfa52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/d7cde1f9d94d87060204f863779389b61c382eeb", - "reference": "d7cde1f9d94d87060204f863779389b61c382eeb", + "url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/de5847b068362a88684a55b0dbb40d85986cfa52", + "reference": "de5847b068362a88684a55b0dbb40d85986cfa52", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^7.1", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "ext-libxml": "*", + "http-interop/http-factory-tests": "^0.5.0", + "php-http/psr7-integration-tests": "dev-master", + "phpunit/phpunit": "^7.0.2", + "zendframework/zend-coding-standard": "~1.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "2.1.x-dev", + "dev-develop": "2.2.x-dev", + "dev-release-1.8": "1.8.x-dev" } }, "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/marshal_uri_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php" + ], "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Zend\\Diactoros\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } + "BSD-3-Clause" ], - "description": "Symfony Process Component", - "homepage": "https://symfony.com", - "time": "2016-06-29 05:40:00" - }, + "description": "PSR HTTP Message implementations", + "keywords": [ + "http", + "psr", + "psr-7" + ], + "support": { + "docs": "https://docs.zendframework.com/zend-diactoros/", + "forum": "https://discourse.zendframework.com/c/questions/exprssive", + "issues": "https://github.com/zendframework/zend-diactoros/issues", + "rss": "https://github.com/zendframework/zend-diactoros/releases.atom", + "slack": "https://zendframework-slack.herokuapp.com", + "source": "https://github.com/zendframework/zend-diactoros" + }, + "abandoned": "laminas/laminas-diactoros", + "time": "2019-11-13T19:16:13+00:00" + } + ], + "packages-dev": [ { - "name": "symfony/routing", - "version": "v3.0.8", + "name": "alt-three/testbench", + "version": "5.0.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/routing.git", - "reference": "9038984bd9c05ab07280121e9e10f61a7231457b" + "url": "https://github.com/AltThree/TestBench.git", + "reference": "246d9744ec1cde265e5ea40c7cd4eebd5577b601" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/9038984bd9c05ab07280121e9e10f61a7231457b", - "reference": "9038984bd9c05ab07280121e9e10f61a7231457b", + "url": "https://api.github.com/repos/AltThree/TestBench/zipball/246d9744ec1cde265e5ea40c7cd4eebd5577b601", + "reference": "246d9744ec1cde265e5ea40c7cd4eebd5577b601", "shasum": "" }, "require": { - "php": ">=5.5.9" - }, - "conflict": { - "symfony/config": "<2.8" + "graham-campbell/testbench-core": "^3.2", + "php": "^7.0 || ^8.0" }, "require-dev": { - "doctrine/annotations": "~1.0", - "doctrine/common": "~2.2", - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0", - "symfony/expression-language": "~2.8|~3.0", - "symfony/http-foundation": "~2.8|~3.0", - "symfony/yaml": "~2.8|~3.0" + "graham-campbell/analyzer": "^2.4 || ^3.0", + "phpunit/phpunit": "^6.5 || ^7.5 || ^8.4 || ^9.0" }, "suggest": { - "doctrine/annotations": "For using the annotation loader", - "symfony/config": "For using the all-in-one router or any loader", - "symfony/dependency-injection": "For loading routes from a service", - "symfony/expression-language": "For using expression matching", - "symfony/http-foundation": "For using a Symfony Request object", - "symfony/yaml": "For using the YAML loader" + "laravel/framework": "Enables the use of most traits." }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, "autoload": { "psr-4": { - "Symfony\\Component\\Routing\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "AltThree\\TestBench\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3802,69 +7060,71 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Alt Three", + "email": "support@alt-three.com" } ], - "description": "Symfony Routing Component", - "homepage": "https://symfony.com", + "description": "Provides some testing traits for apps", "keywords": [ - "router", - "routing", - "uri", - "url" + "Alt Three", + "TestBench", + "app" ], - "time": "2016-06-29 05:40:00" + "support": { + "issues": "https://github.com/AltThree/TestBench/issues", + "source": "https://github.com/AltThree/TestBench/tree/5.0" + }, + "abandoned": true, + "time": "2021-03-29T11:19:11+00:00" }, { - "name": "symfony/translation", - "version": "v3.0.8", + "name": "barryvdh/laravel-debugbar", + "version": "v3.4.2", "source": { "type": "git", - "url": "https://github.com/symfony/translation.git", - "reference": "6bf844e1ee3c820c012386c10427a5c67bbefec8" + "url": "https://github.com/barryvdh/laravel-debugbar.git", + "reference": "91ee8b3acf0d72a4937f4855bd245acbda9910ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/6bf844e1ee3c820c012386c10427a5c67bbefec8", - "reference": "6bf844e1ee3c820c012386c10427a5c67bbefec8", + "url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/91ee8b3acf0d72a4937f4855bd245acbda9910ac", + "reference": "91ee8b3acf0d72a4937f4855bd245acbda9910ac", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/config": "<2.8" + "illuminate/routing": "^5.5|^6|^7", + "illuminate/session": "^5.5|^6|^7", + "illuminate/support": "^5.5|^6|^7", + "maximebf/debugbar": "^1.16.3", + "php": ">=7.0", + "symfony/debug": "^3|^4|^5", + "symfony/finder": "^3|^4|^5" }, "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0", - "symfony/intl": "~2.8|~3.0", - "symfony/yaml": "~2.8|~3.0" - }, - "suggest": { - "psr/log": "To use logging capability in translator", - "symfony/config": "", - "symfony/yaml": "" + "orchestra/testbench": "^3.5|^4.0|^5.0", + "phpunit/phpunit": "^6.0|^7.0|^8.5|^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "3.2-dev" + }, + "laravel": { + "providers": [ + "Barryvdh\\Debugbar\\ServiceProvider" + ], + "aliases": { + "Debugbar": "Barryvdh\\Debugbar\\Facade" + } } }, "autoload": { + "files": [ + "src/helpers.php" + ], "psr-4": { - "Symfony\\Component\\Translation\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Barryvdh\\Debugbar\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3872,58 +7132,62 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" + } + ], + "description": "PHP Debugbar integration for Laravel", + "keywords": [ + "debug", + "debugbar", + "laravel", + "profiler", + "webprofiler" + ], + "support": { + "issues": "https://github.com/barryvdh/laravel-debugbar/issues", + "source": "https://github.com/barryvdh/laravel-debugbar/tree/3.4" + }, + "funding": [ { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "url": "https://github.com/barryvdh", + "type": "github" } ], - "description": "Symfony Translation Component", - "homepage": "https://symfony.com", - "time": "2016-06-29 05:40:00" + "time": "2020-08-30T07:08:17+00:00" }, { - "name": "symfony/var-dumper", - "version": "v3.0.8", + "name": "doctrine/instantiator", + "version": "1.5.0", "source": { "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "2f046e9a9d571f22cc8b26783564876713b06579" + "url": "https://github.com/doctrine/instantiator.git", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/2f046e9a9d571f22cc8b26783564876713b06579", - "reference": "2f046e9a9d571f22cc8b26783564876713b06579", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/polyfill-mbstring": "~1.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "twig/twig": "~1.20|~2.0" - }, - "suggest": { - "ext-symfony_debug": "" + "doctrine/coding-standard": "^9 || ^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.30 || ^5.4" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, "autoload": { - "files": [ - "Resources/functions/dump.php" - ], "psr-4": { - "Symfony\\Component\\VarDumper\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3931,215 +7195,265 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" } ], - "description": "Symfony mechanism for exploring and dumping PHP variables", - "homepage": "https://symfony.com", + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", "keywords": [ - "debug", - "dump" + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.5.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } ], - "time": "2016-06-29 05:40:00" + "time": "2022-12-30T00:15:36+00:00" }, { - "name": "tijsverkoyen/css-to-inline-styles", - "version": "1.5.5", + "name": "filp/whoops", + "version": "2.15.3", "source": { "type": "git", - "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "9753fc340726e327e4d48b7c0604f85475ae0bc3" + "url": "https://github.com/filp/whoops.git", + "reference": "c83e88a30524f9360b11f585f71e6b17313b7187" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/9753fc340726e327e4d48b7c0604f85475ae0bc3", - "reference": "9753fc340726e327e4d48b7c0604f85475ae0bc3", + "url": "https://api.github.com/repos/filp/whoops/zipball/c83e88a30524f9360b11f585f71e6b17313b7187", + "reference": "c83e88a30524f9360b11f585f71e6b17313b7187", "shasum": "" }, "require": { - "php": ">=5.3.0", - "symfony/css-selector": "~2.1|~3.0" + "php": "^5.5.9 || ^7.0 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "mockery/mockery": "^0.9 || ^1.0", + "phpunit/phpunit": "^4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^2.6 || ^3.0 || ^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.5.x-dev" + "dev-master": "2.7-dev" } }, "autoload": { "psr-4": { - "TijsVerkoyen\\CssToInlineStyles\\": "src" + "Whoops\\": "src/Whoops/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD" + "MIT" ], "authors": [ { - "name": "Tijs Verkoyen", - "email": "css_to_inline_styles@verkoyen.eu", + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", "role": "Developer" } ], - "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", - "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", - "time": "2015-12-08 16:14:14" + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.15.3" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2023-07-13T12:00:00+00:00" }, { - "name": "twig/twig", - "version": "v1.24.1", + "name": "fzaninotto/faker", + "version": "v1.9.2", "source": { "type": "git", - "url": "https://github.com/twigphp/Twig.git", - "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512" + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "848d8125239d7dbf8ab25cb7f054f1a630e68c2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/3566d311a92aae4deec6e48682dc5a4528c4a512", - "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/848d8125239d7dbf8ab25cb7f054f1a630e68c2e", + "reference": "848d8125239d7dbf8ab25cb7f054f1a630e68c2e", "shasum": "" }, "require": { - "php": ">=5.2.7" + "php": "^5.3.3 || ^7.0" }, "require-dev": { - "symfony/debug": "~2.7", - "symfony/phpunit-bridge": "~2.7" + "ext-intl": "*", + "phpunit/phpunit": "^4.8.35 || ^5.7", + "squizlabs/php_codesniffer": "^2.9.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.24-dev" + "dev-master": "1.9-dev" } }, "autoload": { - "psr-0": { - "Twig_": "lib/" + "psr-4": { + "Faker\\": "src/Faker/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com", - "homepage": "http://fabien.potencier.org", - "role": "Lead Developer" - }, - { - "name": "Armin Ronacher", - "email": "armin.ronacher@active-4.com", - "role": "Project Founder" - }, - { - "name": "Twig Team", - "homepage": "http://twig.sensiolabs.org/contributors", - "role": "Contributors" + "name": "François Zaninotto" } ], - "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "http://twig.sensiolabs.org", + "description": "Faker is a PHP library that generates fake data for you.", "keywords": [ - "templating" + "data", + "faker", + "fixtures" ], - "time": "2016-05-30 09:11:59" + "support": { + "issues": "https://github.com/fzaninotto/Faker/issues", + "source": "https://github.com/fzaninotto/Faker/tree/v1.9.2" + }, + "abandoned": true, + "time": "2020-12-11T09:56:16+00:00" }, { - "name": "vlucas/phpdotenv", - "version": "v2.3.0", + "name": "graham-campbell/analyzer", + "version": "v2.4.3", "source": { "type": "git", - "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "9ca5644c536654e9509b9d257f53c58630eb2a6a" + "url": "https://github.com/GrahamCampbell/Analyzer.git", + "reference": "baecd15b7e1185075a8db63ca1806c555cd60bc8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/9ca5644c536654e9509b9d257f53c58630eb2a6a", - "reference": "9ca5644c536654e9509b9d257f53c58630eb2a6a", + "url": "https://api.github.com/repos/GrahamCampbell/Analyzer/zipball/baecd15b7e1185075a8db63ca1806c555cd60bc8", + "reference": "baecd15b7e1185075a8db63ca1806c555cd60bc8", "shasum": "" }, "require": { - "php": ">=5.3.9" + "nikic/php-parser": "^3.0|^4.0", + "php": "^7.0|^8.0", + "phpdocumentor/reflection-docblock": "^4.2", + "phpdocumentor/type-resolver": "~0.4|^1.0" }, "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0" + "phpunit/phpunit": "^6.5|^7.5|^8.4|^9.0" + }, + "suggest": { + "phpunit/phpunit": "Required to use the analysis trait." }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "2.4-dev" } }, "autoload": { "psr-4": { - "Dotenv\\": "src/" + "GrahamCampbell\\Analyzer\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause-Attribution" + "MIT" ], "authors": [ { - "name": "Vance Lucas", - "email": "vance@vancelucas.com", - "homepage": "http://www.vancelucas.com" + "name": "Graham Campbell", + "email": "graham@alt-three.com" } ], - "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "description": "Checks if referenced classes really exist.", "keywords": [ - "dotenv", - "env", - "environment" + "Graham Campbell", + "GrahamCampbell", + "analysis", + "analyzer", + "classes", + "testing" ], - "time": "2016-06-14 14:14:52" - } - ], - "packages-dev": [ + "support": { + "issues": "https://github.com/GrahamCampbell/Analyzer/issues", + "source": "https://github.com/GrahamCampbell/Analyzer/tree/v2.4.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/analyzer", + "type": "tidelift" + } + ], + "time": "2020-05-02T14:42:06+00:00" + }, { - "name": "alt-three/testbench", - "version": "v1.4.0", + "name": "graham-campbell/testbench-core", + "version": "v3.4.1", "source": { "type": "git", - "url": "https://github.com/AltThree/TestBench.git", - "reference": "215ca7a1394d79d3ab649b78bc4c55ca63b73531" + "url": "https://github.com/GrahamCampbell/Laravel-TestBench-Core.git", + "reference": "f62a3d0200cbea9f8156ac2cd7d16684ad324c8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/AltThree/TestBench/zipball/215ca7a1394d79d3ab649b78bc4c55ca63b73531", - "reference": "215ca7a1394d79d3ab649b78bc4c55ca63b73531", + "url": "https://api.github.com/repos/GrahamCampbell/Laravel-TestBench-Core/zipball/f62a3d0200cbea9f8156ac2cd7d16684ad324c8d", + "reference": "f62a3d0200cbea9f8156ac2cd7d16684ad324c8d", "shasum": "" }, "require": { - "graham-campbell/testbench-core": "^1.1", - "php": ">=5.5.9" + "php": "^7.0 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^4.8|^5.0" + "graham-campbell/analyzer": "^2.4 || ^3.0", + "phpunit/phpunit": "^6.5 || ^7.5 || ^8.0 || ^9.0 || ^10.0" }, "suggest": { - "laravel/framework": "Enables the use of every trait." + "illuminate/support": "Required to use the laravel trait.", + "mockery/mockery": "Required to use the mockery trait.", + "phpunit/phpunit": "Required to use the most of the features." }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.4-dev" - } - }, "autoload": { "psr-4": { - "AltThree\\TestBench\\": "src/" + "GrahamCampbell\\TestBenchCore\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -4147,116 +7461,128 @@ "MIT" ], "authors": [ - { - "name": "James Brooks", - "email": "james@alt-three.com" - }, { "name": "Graham Campbell", - "email": "graham@alt-three.com" - }, - { - "name": "Joseph Cohen", - "email": "joe@alt-three.com" + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" } ], - "description": "Provides Some Testing Traits For Apps", + "description": "TestBench Core Provides Some Testing Functionality For Laravel", "keywords": [ - "Alt Three", + "Graham Campbell", + "GrahamCampbell", + "Laravel TestBench Core", + "Laravel-TestBench-Core", "TestBench", - "app" + "framework", + "laravel", + "testbench-core", + "testing" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Laravel-TestBench-Core/issues", + "source": "https://github.com/GrahamCampbell/Laravel-TestBench-Core/tree/v3.4.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/testbench-core", + "type": "tidelift" + } ], - "time": "2016-03-14 18:08:23" + "time": "2023-02-25T15:19:33+00:00" }, { - "name": "doctrine/instantiator", - "version": "1.0.5", + "name": "hamcrest/hamcrest-php", + "version": "v2.0.1", "source": { "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", + "reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^5.3|^7.0|^8.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" }, "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpunit/php-file-iterator": "^1.4 || ^2.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.1-dev" } }, "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } + "classmap": [ + "hamcrest" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } + "BSD-3-Clause" ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", + "description": "This is the PHP port of Hamcrest Matchers", "keywords": [ - "constructor", - "instantiate" + "test" ], - "time": "2015-06-14 21:17:01" + "support": { + "issues": "https://github.com/hamcrest/hamcrest-php/issues", + "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.0.1" + }, + "time": "2020-07-09T08:09:16+00:00" }, { - "name": "filp/whoops", - "version": "2.1.2", + "name": "maximebf/debugbar", + "version": "v1.19.1", "source": { "type": "git", - "url": "https://github.com/filp/whoops.git", - "reference": "d13505b240a6f580bc75ba591da30299d6cb0eec" + "url": "https://github.com/maximebf/php-debugbar.git", + "reference": "03dd40a1826f4d585ef93ef83afa2a9874a00523" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/d13505b240a6f580bc75ba591da30299d6cb0eec", - "reference": "d13505b240a6f580bc75ba591da30299d6cb0eec", + "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/03dd40a1826f4d585ef93ef83afa2a9874a00523", + "reference": "03dd40a1826f4d585ef93ef83afa2a9874a00523", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^7.1|^8", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^4|^5|^6" }, "require-dev": { - "mockery/mockery": "0.9.*", - "phpunit/phpunit": "^4.8 || ^5.0", - "symfony/var-dumper": "~3.0" + "phpunit/phpunit": ">=7.5.20 <10.0", + "twig/twig": "^1.38|^2.7|^3.0" }, "suggest": { - "symfony/var-dumper": "Pretty print complex values better with var-dumper available", - "whoops/soap": "Formats errors as SOAP responses" + "kriswallsmith/assetic": "The best way to manage assets", + "monolog/monolog": "Log using Monolog", + "predis/predis": "Redis storage" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "1.18-dev" } }, "autoload": { "psr-4": { - "Whoops\\": "src/Whoops/" + "DebugBar\\": "src/DebugBar/" } }, "notification-url": "https://packagist.org/downloads/", @@ -4265,208 +7591,236 @@ ], "authors": [ { - "name": "Filipe Dobreira", - "homepage": "https://github.com/filp", - "role": "Developer" + "name": "Maxime Bouroumeau-Fuseau", + "email": "maxime.bouroumeau@gmail.com", + "homepage": "http://maximebf.com" + }, + { + "name": "Barry vd. Heuvel", + "email": "barryvdh@gmail.com" } ], - "description": "php error handling for cool kids", - "homepage": "https://github.com/filp/whoops", + "description": "Debug bar in the browser for php application", + "homepage": "https://github.com/maximebf/php-debugbar", "keywords": [ - "error", - "exception", - "handling", - "library", - "whoops", - "zf2" + "debug", + "debugbar" ], - "time": "2016-04-07 06:16:25" + "support": { + "issues": "https://github.com/maximebf/php-debugbar/issues", + "source": "https://github.com/maximebf/php-debugbar/tree/v1.19.1" + }, + "time": "2023-10-12T08:10:52+00:00" }, { - "name": "fzaninotto/faker", - "version": "v1.6.0", + "name": "mockery/mockery", + "version": "1.3.6", "source": { "type": "git", - "url": "https://github.com/fzaninotto/Faker.git", - "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123" + "url": "https://github.com/mockery/mockery.git", + "reference": "dc206df4fa314a50bbb81cf72239a305c5bbd5c0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/44f9a286a04b80c76a4e5fb7aad8bb539b920123", - "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "url": "https://api.github.com/repos/mockery/mockery/zipball/dc206df4fa314a50bbb81cf72239a305c5bbd5c0", + "reference": "dc206df4fa314a50bbb81cf72239a305c5bbd5c0", "shasum": "" }, "require": { - "php": "^5.3.3|^7.0" + "hamcrest/hamcrest-php": "^2.0.1", + "lib-pcre": ">=7.0", + "php": ">=5.6.0" }, "require-dev": { - "ext-intl": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~1.5" + "phpunit/phpunit": "^5.7.10|^6.5|^7.5|^8.5|^9.3" }, "type": "library", "extra": { - "branch-alias": [] + "branch-alias": { + "dev-master": "1.3.x-dev" + } }, "autoload": { - "psr-4": { - "Faker\\": "src/Faker/" + "psr-0": { + "Mockery": "library/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "François Zaninotto" + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "http://blog.astrumfutura.com" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "http://davedevelopment.co.uk" } ], - "description": "Faker is a PHP library that generates fake data for you.", + "description": "Mockery is a simple yet flexible PHP mock object framework", + "homepage": "https://github.com/mockery/mockery", "keywords": [ - "data", - "faker", - "fixtures" + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" ], - "time": "2016-04-29 12:21:54" + "support": { + "issues": "https://github.com/mockery/mockery/issues", + "source": "https://github.com/mockery/mockery/tree/1.3.6" + }, + "time": "2022-09-07T15:05:49+00:00" }, { - "name": "graham-campbell/testbench-core", - "version": "v1.1.1", + "name": "myclabs/deep-copy", + "version": "1.11.1", "source": { "type": "git", - "url": "https://github.com/GrahamCampbell/Laravel-TestBench-Core.git", - "reference": "407e8cff5568ab95c4788ed5f7633e54be712de1" + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GrahamCampbell/Laravel-TestBench-Core/zipball/407e8cff5568ab95c4788ed5f7633e54be712de1", - "reference": "407e8cff5568ab95c4788ed5f7633e54be712de1", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^7.1 || ^8.0" }, - "require-dev": { - "phpunit/phpunit": "^4.8|^5.0" + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" }, - "suggest": { - "illuminate/support": "Required to use the laravel trait.", - "mockery/mockery": "Required to use the mockery trait.", - "phpunit/phpunit": "Required to use the most of the features." + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], "psr-4": { - "GrahamCampbell\\TestBenchCore\\": "src/" + "DeepCopy\\": "src/DeepCopy/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + }, + "funding": [ { - "name": "Graham Campbell", - "email": "graham@alt-three.com" + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" } ], - "description": "TestBench Core Provides Some Testing Functionality For Laravel 5", - "keywords": [ - "Graham Campbell", - "GrahamCampbell", - "Laravel TestBench Core", - "Laravel-TestBench-Core", - "TestBench", - "framework", - "laravel", - "testbench-core", - "testing" - ], - "time": "2016-01-30 13:57:27" + "time": "2023-03-08T13:26:56+00:00" }, { - "name": "hamcrest/hamcrest-php", - "version": "v1.2.2", + "name": "phar-io/manifest", + "version": "1.0.3", "source": { "type": "git", - "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c" + "url": "https://github.com/phar-io/manifest.git", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/b37020aa976fa52d3de9aa904aa2522dc518f79c", - "reference": "b37020aa976fa52d3de9aa904aa2522dc518f79c", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", "shasum": "" }, "require": { - "php": ">=5.3.2" - }, - "replace": { - "cordoval/hamcrest-php": "*", - "davedevelopment/hamcrest-php": "*", - "kodova/hamcrest-php": "*" - }, - "require-dev": { - "phpunit/php-file-iterator": "1.3.3", - "satooshi/php-coveralls": "dev-master" + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^2.0", + "php": "^5.6 || ^7.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "classmap": [ - "hamcrest" - ], - "files": [ - "hamcrest/Hamcrest.php" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD" + "BSD-3-Clause" ], - "description": "This is the PHP port of Hamcrest Matchers", - "keywords": [ - "test" + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } ], - "time": "2015-05-11 14:41:42" + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/master" + }, + "time": "2018-07-08T19:23:20+00:00" }, { - "name": "mockery/mockery", - "version": "0.9.5", + "name": "phar-io/version", + "version": "2.0.1", "source": { "type": "git", - "url": "https://github.com/padraic/mockery.git", - "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2" + "url": "https://github.com/phar-io/version.git", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/padraic/mockery/zipball/4db079511a283e5aba1b3c2fb19037c645e70fc2", - "reference": "4db079511a283e5aba1b3c2fb19037c645e70fc2", + "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", "shasum": "" }, "require": { - "hamcrest/hamcrest-php": "~1.1", - "lib-pcre": ">=7.0", - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" + "php": "^5.6 || ^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.9.x-dev" - } - }, "autoload": { - "psr-0": { - "Mockery": "library/" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4474,63 +7828,54 @@ ], "authors": [ { - "name": "Pádraic Brady", - "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" }, { - "name": "Dave Marshall", - "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", - "homepage": "http://github.com/padraic/mockery", - "keywords": [ - "BDD", - "TDD", - "library", - "mock", - "mock objects", - "mockery", - "stub", - "test", - "test double", - "testing" - ], - "time": "2016-05-22 21:52:33" + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/master" + }, + "time": "2018-07-08T19:19:57+00:00" }, { "name": "phpdocumentor/reflection-common", - "version": "1.0", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + "reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", - "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/6568f4687e5b41b054365f9ae03fcb1ed5f2069b", + "reference": "6568f4687e5b41b054365f9ae03fcb1ed5f2069b", "shasum": "" }, "require": { - "php": ">=5.5" - }, - "require-dev": { - "phpunit/phpunit": "^4.6" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "phpDocumentor\\Reflection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -4552,33 +7897,44 @@ "reflection", "static analysis" ], - "time": "2015-12-27 11:43:31" + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master" + }, + "time": "2020-04-27T09:25:28+00:00" }, { "name": "phpdocumentor/reflection-docblock", - "version": "3.1.0", + "version": "4.3.4", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd" + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c", + "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c", "shasum": "" }, "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0@dev", - "phpdocumentor/type-resolver": "^0.2.0", + "php": "^7.0", + "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", + "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", "webmozart/assert": "^1.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.4" + "doctrine/instantiator": "^1.0.5", + "mockery/mockery": "^1.0", + "phpdocumentor/type-resolver": "0.4.*", + "phpunit/phpunit": "^6.4" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, "autoload": { "psr-4": { "phpDocumentor\\Reflection\\": [ @@ -4597,41 +7953,44 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-06-10 09:48:41" + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/4.x" + }, + "time": "2019-12-28T18:55:12+00:00" }, { "name": "phpdocumentor/type-resolver", - "version": "0.2", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", + "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", "shasum": "" }, "require": { - "php": ">=5.5", - "phpdocumentor/reflection-common": "^1.0" + "php": "^7.1", + "phpdocumentor/reflection-common": "^2.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "ext-tokenizer": "^7.1", + "mockery/mockery": "~1", + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.x-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "phpDocumentor\\Reflection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -4644,41 +8003,47 @@ "email": "me@mikevanriel.com" } ], - "time": "2016-06-10 07:14:17" + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/0.7.2" + }, + "time": "2019-08-22T18:11:29+00:00" }, { "name": "phpspec/prophecy", - "version": "v1.6.1", + "version": "v1.10.3", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + "reference": "451c3cd1418cf640de218914901e51b064abb093" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/451c3cd1418cf640de218914901e51b064abb093", + "reference": "451c3cd1418cf640de218914901e51b064abb093", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", - "sebastian/comparator": "^1.1", - "sebastian/recursion-context": "^1.0" + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", + "sebastian/comparator": "^1.2.3|^2.0|^3.0|^4.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0|^4.0" }, "require-dev": { - "phpspec/phpspec": "^2.0" + "phpspec/phpspec": "^2.5 || ^3.2", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.10.x-dev" } }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "psr-4": { + "Prophecy\\": "src/Prophecy" } }, "notification-url": "https://packagist.org/downloads/", @@ -4706,43 +8071,48 @@ "spy", "stub" ], - "time": "2016-06-07 08:13:47" + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/v1.10.3" + }, + "time": "2020-03-05T15:02:03+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "2.2.4", + "version": "6.1.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", "shasum": "" }, "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": "~1.3", - "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", - "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0" + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": "^7.1", + "phpunit/php-file-iterator": "^2.0", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.1 || ^4.0", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" }, "require-dev": { - "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4" + "phpunit/phpunit": "^7.0" }, "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.2.1", - "ext-xmlwriter": "*" + "ext-xdebug": "^2.6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2.x-dev" + "dev-master": "6.1-dev" } }, "autoload": { @@ -4757,7 +8127,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -4768,29 +8138,36 @@ "testing", "xunit" ], - "time": "2015-10-06 15:47:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/master" + }, + "time": "2018-10-31T16:06:48+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.1", + "version": "2.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5", + "reference": "42c5ba5220e6904cbfe8b1a1bda7c0cfdc8c12f5", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -4805,7 +8182,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -4815,7 +8192,17 @@ "filesystem", "iterator" ], - "time": "2015-06-21 13:08:43" + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:42:26+00:00" }, { "name": "phpunit/php-text-template", @@ -4856,29 +8243,38 @@ "keywords": [ "template" ], - "time": "2015-06-21 13:50:34" + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + }, + "time": "2015-06-21T13:50:34+00:00" }, { "name": "phpunit/php-timer", - "version": "1.0.8", + "version": "2.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", - "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662", + "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "~4|~5" + "phpunit/phpunit": "^8.5" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -4891,7 +8287,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -4900,33 +8296,43 @@ "keywords": [ "timer" ], - "time": "2016-05-12 18:03:57" + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:20:02+00:00" }, { "name": "phpunit/php-token-stream", - "version": "1.4.8", + "version": "3.1.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + "reference": "9c1da83261628cb24b6a6df371b6e312b3954768" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/9c1da83261628cb24b6a6df371b6e312b3954768", + "reference": "9c1da83261628cb24b6a6df371b6e312b3954768", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=5.3.3" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "~4.2" + "phpunit/phpunit": "^7.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "3.1-dev" } }, "autoload": { @@ -4949,53 +8355,261 @@ "keywords": [ "tokenizer" ], - "time": "2015-09-15 10:49:45" + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/3.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2021-07-26T12:15:06+00:00" }, { "name": "phpunit/phpunit", - "version": "4.8.21", + "version": "7.5.20", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "9467db479d1b0487c99733bb1e7944d32deded2c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9467db479d1b0487c99733bb1e7944d32deded2c", + "reference": "9467db479d1b0487c99733bb1e7944d32deded2c", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "^1.7", + "phar-io/manifest": "^1.0.2", + "phar-io/version": "^2.0", + "php": "^7.1", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^6.0.7", + "phpunit/php-file-iterator": "^2.0.1", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.1", + "sebastian/comparator": "^3.0", + "sebastian/diff": "^3.0", + "sebastian/environment": "^4.0", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^2.0", + "sebastian/version": "^2.0.1" + }, + "conflict": { + "phpunit/phpunit-mock-objects": "*" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.5-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/7.5.20" + }, + "time": "2020-01-08T08:45:45+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:15:22+00:00" + }, + { + "name": "sebastian/comparator", + "version": "3.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1dc7ceb4a24aede938c7af2a9ed1de09609ca770" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1dc7ceb4a24aede938c7af2a9ed1de09609ca770", + "reference": "1dc7ceb4a24aede938c7af2a9ed1de09609ca770", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/3.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:31:48+00:00" + }, + { + "name": "sebastian/diff", + "version": "3.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "ea76b17bced0500a28098626b84eda12dbcf119c" + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/ea76b17bced0500a28098626b84eda12dbcf119c", - "reference": "ea76b17bced0500a28098626b84eda12dbcf119c", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/6296a0c086dd0117c1b78b059374d7fcbe7545ae", + "reference": "6296a0c086dd0117c1b78b059374d7fcbe7545ae", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "~2.1", - "phpunit/php-file-iterator": "~1.4", - "phpunit/php-text-template": "~1.2", - "phpunit/php-timer": ">=1.0.6", - "phpunit/phpunit-mock-objects": "~2.3", - "sebastian/comparator": "~1.1", - "sebastian/diff": "~1.2", - "sebastian/environment": "~1.3", - "sebastian/exporter": "~1.2", - "sebastian/global-state": "~1.0", - "sebastian/version": "~1.0", - "symfony/yaml": "~2.1|~3.0" + "php": ">=7.1" }, - "suggest": { - "phpunit/php-invoker": "~1.1" + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" }, - "bin": [ - "phpunit" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "4.8.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -5010,49 +8624,60 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" } ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "phpunit", - "testing", - "xunit" + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2015-12-12 07:45:58" + "time": "2023-05-07T05:30:20+00:00" }, { - "name": "phpunit/phpunit-mock-objects", - "version": "2.3.8", + "name": "sebastian/environment", + "version": "4.2.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", + "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": ">=5.3.3", - "phpunit/php-text-template": "~1.2", - "sebastian/exporter": "~1.2" + "php": ">=7.1" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^7.5" }, "suggest": { - "ext-soap": "*" + "ext-posix": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3.x-dev" + "dev-master": "4.2-dev" } }, "autoload": { @@ -5067,44 +8692,54 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" + "email": "sebastian@phpunit.de" } ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", "keywords": [ - "mock", - "xunit" + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/4.2.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2015-10-02 06:51:40" + "time": "2020-11-30T07:53:42+00:00" }, { - "name": "sebastian/comparator", - "version": "1.2.0", + "name": "sebastian/exporter", + "version": "3.1.5", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "73a9676f2833b9a7c36968f9d882589cd75511e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/73a9676f2833b9a7c36968f9d882589cd75511e6", + "reference": "73a9676f2833b9a7c36968f9d882589cd75511e6", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2" + "php": ">=7.0", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "ext-mbstring": "*", + "phpunit/phpunit": "^8.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -5117,6 +8752,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -5126,47 +8765,59 @@ "email": "github@wallbash.com" }, { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" + "name": "Adam Harvey", + "email": "aharvey@php.net" }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", "keywords": [ - "comparator", - "compare", - "equality" + "export", + "exporter" ], - "time": "2015-07-26 15:48:44" + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:00:17+00:00" }, { - "name": "sebastian/diff", - "version": "1.4.1", + "name": "sebastian/global-state", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", - "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.8" + "phpunit/phpunit": "^6.0" + }, + "suggest": { + "ext-uopz": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -5179,46 +8830,48 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" } ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", "keywords": [ - "diff" + "global state" ], - "time": "2015-12-08 07:14:41" + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/2.0.0" + }, + "time": "2017-04-27T15:39:26+00:00" }, { - "name": "sebastian/environment", - "version": "1.3.7", + "name": "sebastian/object-enumerator", + "version": "3.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716" + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716", - "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -5236,41 +8889,44 @@ "email": "sebastian@phpunit.de" } ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2016-05-17 03:18:57" + "time": "2020-11-30T07:40:27+00:00" }, { - "name": "sebastian/exporter", - "version": "1.2.2", + "name": "sebastian/object-reflector", + "version": "1.1.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", - "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" + "php": ">=7.0" }, "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "1.1-dev" } }, "autoload": { @@ -5283,62 +8939,49 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" } ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2016-06-17 09:04:28" + "time": "2020-11-30T07:37:18+00:00" }, { - "name": "sebastian/global-state", - "version": "1.1.1", + "name": "sebastian/recursion-context", + "version": "3.0.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb", + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.0" }, "require-dev": { - "phpunit/phpunit": "~4.2" - }, - "suggest": { - "ext-uopz": "*" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -5354,39 +8997,51 @@ { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" } ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2015-10-12 03:26:01" + "time": "2020-11-30T07:34:24+00:00" }, { - "name": "sebastian/recursion-context", - "version": "1.0.2", + "name": "sebastian/resource-operations", + "version": "2.0.2", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3", + "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3", "shasum": "" }, "require": { - "php": ">=5.3.3" - }, - "require-dev": { - "phpunit/phpunit": "~4.4" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -5399,38 +9054,48 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" - }, + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.2" + }, + "funding": [ { - "name": "Adam Harvey", - "email": "aharvey@php.net" + "url": "https://github.com/sebastianbergmann", + "type": "github" } ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2015-11-11 19:50:13" + "time": "2020-11-30T07:30:19+00:00" }, { "name": "sebastian/version", - "version": "1.0.6", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", "shasum": "" }, + "require": { + "php": ">=5.6" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -5449,94 +9114,84 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21 13:59:46" + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/master" + }, + "time": "2016-10-03T07:35:21+00:00" }, { - "name": "symfony/dom-crawler", - "version": "v3.1.2", + "name": "theseer/tokenizer", + "version": "1.1.3", "source": { "type": "git", - "url": "https://github.com/symfony/dom-crawler.git", - "reference": "99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0" + "url": "https://github.com/theseer/tokenizer.git", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0", - "reference": "99ec4a23330fcd0c8667095f3ef7aa204ffd9dc0", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", + "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", "shasum": "" }, "require": { - "php": ">=5.5.9", - "symfony/polyfill-mbstring": "~1.0" - }, - "require-dev": { - "symfony/css-selector": "~2.8|~3.0" - }, - "suggest": { - "symfony/css-selector": "" + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, "autoload": { - "psr-4": { - "Symfony\\Component\\DomCrawler\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" + "classmap": [ + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" } ], - "description": "Symfony DomCrawler Component", - "homepage": "https://symfony.com", - "time": "2016-06-29 05:41:56" + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/master" + }, + "time": "2019-06-13T22:48:21+00:00" }, { - "name": "symfony/yaml", - "version": "v3.1.2", + "name": "tightenco/mailthief", + "version": "v0.3.14", "source": { "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de" + "url": "https://github.com/tighten/mailthief.git", + "reference": "9a8c2443be2b3d77753596f70ae6cd879b5b26a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/2884c26ce4c1d61aebf423a8b912950fe7c764de", - "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de", + "url": "https://api.github.com/repos/tighten/mailthief/zipball/9a8c2443be2b3d77753596f70ae6cd879b5b26a6", + "reference": "9a8c2443be2b3d77753596f70ae6cd879b5b26a6", "shasum": "" }, "require": { - "php": ">=5.5.9" + "illuminate/mail": "5.*", + "illuminate/view": "5.*" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } + "require-dev": { + "laravel/framework": ">=5.0 <5.5", + "mockery/mockery": "^0.9.5", + "phpunit/phpunit": "^5.5" }, + "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "MailThief\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5544,44 +9199,43 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Adam Wathan", + "email": "adam.wathan@gmail.com" } ], - "description": "Symfony Yaml Component", - "homepage": "https://symfony.com", - "time": "2016-06-29 05:41:56" + "description": "A fake Mailer for Laravel applications that takes the pain out of testing mail.", + "support": { + "issues": "https://github.com/tighten/mailthief/issues", + "source": "https://github.com/tighten/mailthief/tree/v0.3.14" + }, + "time": "2018-02-10T04:17:52+00:00" }, { "name": "webmozart/assert", - "version": "1.0.2", + "version": "1.9.1", "source": { "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde" + "url": "https://github.com/webmozarts/assert.git", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde", - "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", + "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^5.3.3 || ^7.0 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<3.9.1" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "phpunit/phpunit": "^4.8.36 || ^7.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, "autoload": { "psr-4": { "Webmozart\\Assert\\": "src/" @@ -5603,19 +9257,31 @@ "check", "validate" ], - "time": "2015-08-24 13:29:44" + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.9.1" + }, + "time": "2020-07-08T17:02:28+00:00" } ], "aliases": [], "minimum-stability": "dev", - "stability-flags": [], + "stability-flags": { + "alt-three/testbench": 20 + }, "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": ">=5.5.9" + "php": "^7.1.3", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-xml": "*" + }, + "platform-dev": { + "ext-sqlite3": "*" }, - "platform-dev": [], "platform-overrides": { - "php": "5.5.9" - } + "php": "7.1.3" + }, + "plugin-api-version": "2.3.0" } diff --git a/config/app.php b/config/app.php index 3a5d4fd9d57..b9599092fed 100644 --- a/config/app.php +++ b/config/app.php @@ -11,6 +11,18 @@ return [ + /* + |-------------------------------------------------------------------------- + | Application Name + |-------------------------------------------------------------------------- + | + | This value is the name of your application. This value is used when the + | framework needs to place the application's name in a notification or + | any other location as required by the application or its packages. + */ + + 'name' => 'Cachet', + /* |-------------------------------------------------------------------------- | Application Environment @@ -35,7 +47,7 @@ | */ - 'debug' => env('APP_DEBUG', false), + 'debug' => (bool) env('APP_DEBUG', false), /* |-------------------------------------------------------------------------- @@ -61,7 +73,7 @@ | */ - 'timezone' => 'UTC', + 'timezone' => env('APP_TIMEZONE', 'UTC'), /* |-------------------------------------------------------------------------- @@ -135,58 +147,57 @@ /* * Laravel Framework Service Providers... */ - 'Illuminate\Auth\AuthServiceProvider', - 'Illuminate\Broadcasting\BroadcastServiceProvider', - 'AltThree\Bus\BusServiceProvider', - 'Illuminate\Cache\CacheServiceProvider', - 'Illuminate\Foundation\Providers\ConsoleSupportServiceProvider', - 'Illuminate\Cookie\CookieServiceProvider', - 'Illuminate\Database\DatabaseServiceProvider', - 'Illuminate\Encryption\EncryptionServiceProvider', - 'Illuminate\Filesystem\FilesystemServiceProvider', - 'Illuminate\Foundation\Providers\FoundationServiceProvider', - 'Illuminate\Hashing\HashServiceProvider', - 'Illuminate\Mail\MailServiceProvider', - 'Illuminate\Pagination\PaginationServiceProvider', - 'Illuminate\Pipeline\PipelineServiceProvider', - 'Illuminate\Queue\QueueServiceProvider', - 'Illuminate\Redis\RedisServiceProvider', - 'Illuminate\Auth\Passwords\PasswordResetServiceProvider', - 'Illuminate\Session\SessionServiceProvider', - 'Illuminate\Translation\TranslationServiceProvider', - 'Illuminate\Validation\ValidationServiceProvider', - 'Illuminate\View\ViewServiceProvider', + Illuminate\Auth\AuthServiceProvider::class, + Illuminate\Broadcasting\BroadcastServiceProvider::class, + AltThree\Bus\BusServiceProvider::class, + Illuminate\Cache\CacheServiceProvider::class, + Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, + Illuminate\Cookie\CookieServiceProvider::class, + Illuminate\Database\DatabaseServiceProvider::class, + Illuminate\Encryption\EncryptionServiceProvider::class, + Illuminate\Filesystem\FilesystemServiceProvider::class, + Illuminate\Foundation\Providers\FoundationServiceProvider::class, + Illuminate\Hashing\HashServiceProvider::class, + Illuminate\Mail\MailServiceProvider::class, + Illuminate\Notifications\NotificationServiceProvider::class, + Illuminate\Pagination\PaginationServiceProvider::class, + Illuminate\Pipeline\PipelineServiceProvider::class, + Illuminate\Queue\QueueServiceProvider::class, + Illuminate\Redis\RedisServiceProvider::class, + Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, + Illuminate\Session\SessionServiceProvider::class, + Illuminate\Translation\TranslationServiceProvider::class, + Illuminate\Validation\ValidationServiceProvider::class, + Illuminate\View\ViewServiceProvider::class, /* * Packages Service Providers... */ - 'AltThree\Badger\BadgerServiceProvider', - 'AltThree\Emoji\EmojiServiceProvider', - 'BackupManager\Laravel\Laravel5ServiceProvider', - 'Barryvdh\Cors\ServiceProvider', - 'Fedeisas\LaravelMailCssInliner\LaravelMailCssInlinerServiceProvider', - 'Fideloper\Proxy\TrustedProxyServiceProvider', - 'GrahamCampbell\Binput\BinputServiceProvider', - 'GrahamCampbell\Exceptions\ExceptionsServiceProvider', - 'GrahamCampbell\Core\CoreServiceProvider', - 'GrahamCampbell\Markdown\MarkdownServiceProvider', - 'GrahamCampbell\Security\SecurityServiceProvider', - 'Jenssegers\Date\DateServiceProvider', - 'McCool\LaravelAutoPresenter\AutoPresenterServiceProvider', - 'PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider', - 'Roumen\Feed\FeedServiceProvider', - 'TwigBridge\ServiceProvider', + env('APP_DEBUG') ? Bugsnag\BugsnagLaravel\BugsnagServiceProvider::class : null, + Barryvdh\Cors\ServiceProvider::class, + env('APP_DEBUG') ? Barryvdh\Debugbar\ServiceProvider::class : null, + CachetHQ\Badger\BadgerServiceProvider::class, + CachetHQ\Emoji\EmojiServiceProvider::class, + CachetHQ\Twitter\TwitterServiceProvider::class, + GrahamCampbell\Binput\BinputServiceProvider::class, + GrahamCampbell\Exceptions\ExceptionsServiceProvider::class, + GrahamCampbell\Markdown\MarkdownServiceProvider::class, + GrahamCampbell\Security\SecurityServiceProvider::class, + Jenssegers\Date\DateServiceProvider::class, + Laravel\Tinker\TinkerServiceProvider::class, + McCool\LaravelAutoPresenter\AutoPresenterServiceProvider::class, /* * Application Service Providers... */ - 'CachetHQ\Cachet\Foundation\Providers\AppServiceProvider', - 'CachetHQ\Cachet\Foundation\Providers\ComposerServiceProvider', - 'CachetHQ\Cachet\Foundation\Providers\ConsoleServiceProvider', - 'CachetHQ\Cachet\Foundation\Providers\ConfigServiceProvider', - 'CachetHQ\Cachet\Foundation\Providers\EventServiceProvider', - 'CachetHQ\Cachet\Foundation\Providers\RepositoryServiceProvider', - 'CachetHQ\Cachet\Foundation\Providers\RouteServiceProvider', + CachetHQ\Cachet\Providers\AppServiceProvider::class, + CachetHQ\Cachet\Providers\ComposerServiceProvider::class, + CachetHQ\Cachet\Providers\ConsoleServiceProvider::class, + CachetHQ\Cachet\Providers\ConfigServiceProvider::class, + CachetHQ\Cachet\Providers\EventServiceProvider::class, + CachetHQ\Cachet\Providers\IntegrationServiceProvider::class, + CachetHQ\Cachet\Providers\RepositoryServiceProvider::class, + CachetHQ\Cachet\Providers\RouteServiceProvider::class, ]), @@ -203,38 +214,41 @@ 'aliases' => [ - 'App' => 'Illuminate\Support\Facades\App', - 'Artisan' => 'Illuminate\Support\Facades\Artisan', - 'Auth' => 'Illuminate\Support\Facades\Auth', - 'Blade' => 'Illuminate\Support\Facades\Blade', - 'Cache' => 'Illuminate\Support\Facades\Cache', - 'Config' => 'Illuminate\Support\Facades\Config', - 'Cookie' => 'Illuminate\Support\Facades\Cookie', - 'Crypt' => 'Illuminate\Support\Facades\Crypt', - 'DB' => 'Illuminate\Support\Facades\DB', - 'Event' => 'Illuminate\Support\Facades\Event', - 'File' => 'Illuminate\Support\Facades\File', - 'Gate' => 'Illuminate\Support\Facades\Gate', - 'Hash' => 'Illuminate\Support\Facades\Hash', - 'Lang' => 'Illuminate\Support\Facades\Lang', - 'Log' => 'Illuminate\Support\Facades\Log', - 'Mail' => 'Illuminate\Support\Facades\Mail', - 'Password' => 'Illuminate\Support\Facades\Password', - 'Queue' => 'Illuminate\Support\Facades\Queue', - 'Redirect' => 'Illuminate\Support\Facades\Redirect', - 'Redis' => 'Illuminate\Support\Facades\Redis', - 'Request' => 'Illuminate\Support\Facades\Request', - 'Response' => 'Illuminate\Support\Facades\Response', - 'Route' => 'Illuminate\Support\Facades\Route', - 'Schema' => 'Illuminate\Support\Facades\Schema', - 'Session' => 'Illuminate\Support\Facades\Session', - 'Storage' => 'Illuminate\Support\Facades\Storage', - 'URL' => 'Illuminate\Support\Facades\URL', - 'Validator' => 'Illuminate\Support\Facades\Validator', - 'View' => 'Illuminate\Support\Facades\View', - - 'Binput' => 'GrahamCampbell\Binput\Facades\Binput', - 'Str' => 'Illuminate\Support\Str', + 'App' => Illuminate\Support\Facades\App::class, + 'Artisan' => Illuminate\Support\Facades\Artisan::class, + 'Auth' => Illuminate\Support\Facades\Auth::class, + 'Blade' => Illuminate\Support\Facades\Blade::class, + 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, + 'Bus' => Illuminate\Support\Facades\Bus::class, + 'Cache' => Illuminate\Support\Facades\Cache::class, + 'Config' => Illuminate\Support\Facades\Config::class, + 'Cookie' => Illuminate\Support\Facades\Cookie::class, + 'Crypt' => Illuminate\Support\Facades\Crypt::class, + 'DB' => Illuminate\Support\Facades\DB::class, + 'Eloquent' => Illuminate\Database\Eloquent\Model::class, + 'Event' => Illuminate\Support\Facades\Event::class, + 'File' => Illuminate\Support\Facades\File::class, + 'Gate' => Illuminate\Support\Facades\Gate::class, + 'Hash' => Illuminate\Support\Facades\Hash::class, + 'Lang' => Illuminate\Support\Facades\Lang::class, + 'Log' => Illuminate\Support\Facades\Log::class, + 'Mail' => Illuminate\Support\Facades\Mail::class, + 'Notification' => Illuminate\Support\Facades\Notification::class, + 'Password' => Illuminate\Support\Facades\Password::class, + 'Queue' => Illuminate\Support\Facades\Queue::class, + 'Redirect' => Illuminate\Support\Facades\Redirect::class, + 'Redis' => Illuminate\Support\Facades\Redis::class, + 'Request' => Illuminate\Support\Facades\Request::class, + 'Response' => Illuminate\Support\Facades\Response::class, + 'Route' => Illuminate\Support\Facades\Route::class, + 'Schema' => Illuminate\Support\Facades\Schema::class, + 'Session' => Illuminate\Support\Facades\Session::class, + 'Storage' => Illuminate\Support\Facades\Storage::class, + 'URL' => Illuminate\Support\Facades\URL::class, + 'Validator' => Illuminate\Support\Facades\Validator::class, + 'View' => Illuminate\Support\Facades\View::class, + 'Binput' => GrahamCampbell\Binput\Facades\Binput::class, + 'Str' => Illuminate\Support\Str::class, ], diff --git a/config/auth.php b/config/auth.php index 97aef242b07..a0697fac50f 100644 --- a/config/auth.php +++ b/config/auth.php @@ -76,8 +76,13 @@ 'providers' => [ 'users' => [ 'driver' => 'eloquent', - 'model' => 'CachetHQ\Cachet\Models\User', + 'model' => \CachetHQ\Cachet\Models\User::class, ], + + // 'users' => [ + // 'driver' => 'database', + // 'table' => 'users', + // ], ], /* @@ -85,10 +90,6 @@ | Resetting Passwords |-------------------------------------------------------------------------- | - | Here you may set the options for resetting passwords including the view - | that is your password reset e-mail. You may also set the name of the - | table that maintains all of the reset tokens for your application. - | | You may specify multiple password reset configurations if you have more | than one user table or model in the application and you want to have | separate password reset settings based on the specific user types. @@ -102,7 +103,6 @@ 'passwords' => [ 'users' => [ 'provider' => 'users', - 'email' => 'auth.emails.password', 'table' => 'password_resets', 'expire' => 60, ], diff --git a/config/avatar.php b/config/avatar.php new file mode 100644 index 00000000000..68590dd603b --- /dev/null +++ b/config/avatar.php @@ -0,0 +1,88 @@ + 'gd', + + // Whether all characters supplied must be replaced with their closest ASCII counterparts + 'ascii' => false, + + // Image shape: circle or square + 'shape' => 'circle', + + // Image width, in pixel + 'width' => 100, + + // Image height, in pixel + 'height' => 100, + + // Number of characters used as initials. If name consists of single word, the first N character will be used + 'chars' => 2, + + // font size + 'fontSize' => 48, + + // convert initial letter in uppercase + 'uppercase' => false, + + // Fonts used to render text. + // If contains more than one fonts, randomly selected based on name supplied + // You can provide absolute path, path relative to folder resources/laravolt/avatar/fonts/, or mixed. + 'fonts' => ['OpenSans-Bold.ttf', 'rockwell.ttf'], + + // List of foreground colors to be used, randomly selected based on name supplied + 'foregrounds' => [ + '#FFFFFF', + ], + + // List of background colors to be used, randomly selected based on name supplied + 'backgrounds' => [ + '#f44336', + '#E91E63', + '#9C27B0', + '#673AB7', + '#3F51B5', + '#2196F3', + '#03A9F4', + '#00BCD4', + '#009688', + '#4CAF50', + '#8BC34A', + '#CDDC39', + '#FFC107', + '#FF9800', + '#FF5722', + ], + + 'border' => [ + 'size' => 1, + + // border color, available value are: + // 'foreground' (same as foreground color) + // 'background' (same as background color) + // or any valid hex ('#aabbcc') + 'color' => 'foreground', + ], + +]; diff --git a/config/backup-manager.php b/config/backup-manager.php deleted file mode 100644 index 40c8539bc14..00000000000 --- a/config/backup-manager.php +++ /dev/null @@ -1,70 +0,0 @@ - [ - 'type' => 'Local', - 'root' => database_path('backups'), - ], - 's3' => [ - 'type' => 'AwsS3', - 'key' => '', - 'secret' => '', - 'region' => 'us-east-1', - 'bucket' => '', - 'root' => '', - ], - 'gcs' => [ - 'type' => 'Gcs', - 'key' => '', - 'secret' => '', - 'bucket' => '', - 'root' => '', - ], - 'rackspace' => [ - 'type' => 'Rackspace', - 'username' => '', - 'key' => '', - 'container' => '', - 'zone' => '', - 'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/', - 'root' => '', - ], - 'dropbox' => [ - 'type' => 'Dropbox', - 'token' => '', - 'key' => '', - 'secret' => '', - 'app' => '', - 'root' => '', - ], - 'ftp' => [ - 'type' => 'Ftp', - 'host' => '', - 'username' => '', - 'password' => '', - 'port' => 21, - 'passive' => true, - 'ssl' => true, - 'timeout' => 30, - 'root' => '', - ], - 'sftp' => [ - 'type' => 'Sftp', - 'host' => '', - 'username' => '', - 'password' => '', - 'port' => 21, - 'timeout' => 10, - 'privateKey' => '', - 'root' => '', - ], -]; diff --git a/config/broadcasting.php b/config/broadcasting.php index 9305cdeb5c3..01c1213a4c7 100644 --- a/config/broadcasting.php +++ b/config/broadcasting.php @@ -20,9 +20,11 @@ | framework when an event needs to be broadcast. You may set this to | any of the connections defined in the "connections" array below. | + | Supported: "pusher", "redis", "log", "null" + | */ - 'default' => env('BROADCAST_DRIVER', 'pusher'), + 'default' => env('BROADCAST_DRIVER', 'null'), /* |-------------------------------------------------------------------------- @@ -39,9 +41,9 @@ 'pusher' => [ 'driver' => 'pusher', - 'key' => null, - 'secret' => null, - 'app_id' => null, + 'key' => env('PUSHER_APP_KEY'), + 'secret' => env('PUSHER_APP_SECRET'), + 'app_id' => env('PUSHER_APP_ID'), 'options' => [ // ], @@ -56,6 +58,10 @@ 'driver' => 'log', ], + 'null' => [ + 'driver' => 'null', + ], + ], ]; diff --git a/config/cache.php b/config/cache.php index ce53b14c79c..06ec44c36ea 100644 --- a/config/cache.php +++ b/config/cache.php @@ -20,6 +20,8 @@ | using this caching library. This connection is used when another is | not explicitly specified when executing a given caching function. | + | Supported: "apc", "array", "database", "file", "memcached", "redis" + | */ 'default' => env('CACHE_DRIVER', 'file'), @@ -53,15 +55,23 @@ 'file' => [ 'driver' => 'file', - 'path' => storage_path('framework/cache'), + 'path' => storage_path('framework/cache/data'), ], 'memcached' => [ - 'driver' => 'memcached', + 'driver' => 'memcached', + 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), + 'sasl' => [ + env('MEMCACHED_USERNAME'), + env('MEMCACHED_PASSWORD'), + ], + 'options' => [ + // Memcached::OPT_CONNECT_TIMEOUT => 2000, + ], 'servers' => [ [ - 'host' => '127.0.0.1', - 'port' => 11211, + 'host' => env('MEMCACHED_HOST', '127.0.0.1'), + 'port' => env('MEMCACHED_PORT', 11211), 'weight' => 100, ], ], @@ -70,6 +80,9 @@ 'redis' => [ 'driver' => 'redis', 'connection' => 'default', + 'password' => env('REDIS_PASSWORD', null), + 'port' => env('REDIS_PORT', 6379), + 'database' => env('REDIS_DB', 0), ], ], diff --git a/config/cachet.php b/config/cachet.php index b6231302b86..6e0c9f8debd 100644 --- a/config/cachet.php +++ b/config/cachet.php @@ -22,4 +22,45 @@ 'timezone' => 'UTC', + /* + |-------------------------------------------------------------------------- + | Docker + |-------------------------------------------------------------------------- + | + | Is the installation running under a Docker container? + | + */ + + 'is_docker' => env('DOCKER', false), + + /* + |-------------------------------------------------------------------------- + | Beacon + |-------------------------------------------------------------------------- + | + | Has the installation agreed to sending us Beacon data? + | + | Default: true + | + */ + + 'beacon' => env('CACHET_BEACON', true), + + /* + |-------------------------------------------------------------------------- + | Templates configurations + |-------------------------------------------------------------------------- + | + | Security fix: now user can provide information which will be included to the Twig sandbox settings + | + | Default: Described below + | + */ + 'twig' => [ + 'methods' => [], + 'functions' => [], + 'filters' => ['escape'], + 'tags' => ['if'], + 'props' => [], + ], ]; diff --git a/config/cors.php b/config/cors.php index fb12f8c9df4..6e843598beb 100644 --- a/config/cors.php +++ b/config/cors.php @@ -10,6 +10,7 @@ */ return [ + /* |-------------------------------------------------------------------------- | Laravel CORS @@ -19,11 +20,13 @@ | to accept any value. | */ - 'supportsCredentials' => false, - 'allowedOrigins' => ['*'], - 'allowedHeaders' => ['X-Cachet-Token'], - 'allowedMethods' => ['*'], - 'exposedHeaders' => [], - 'maxAge' => 3600, - 'hosts' => [], + + 'supportsCredentials' => false, + 'allowedOrigins' => ['*'], + 'allowedOriginsPatterns' => [], + 'allowedHeaders' => ['X-Cachet-Token'], + 'allowedMethods' => ['*'], + 'exposedHeaders' => [], + 'maxAge' => 3600, + ]; diff --git a/config/css-inliner.php b/config/css-inliner.php deleted file mode 100644 index f1e9c78bf34..00000000000 --- a/config/css-inliner.php +++ /dev/null @@ -1,41 +0,0 @@ - true, - - /* - |-------------------------------------------------------------------------- - | Remove classes - |-------------------------------------------------------------------------- - | - | Settings this to false disables the removal of class attributes from - | your html elements (do not enable this if you use media queries) - | - */ - - 'strip-classes' => true, - -]; diff --git a/config/database.php b/config/database.php index 5d47720b65a..bb5f8221b91 100644 --- a/config/database.php +++ b/config/database.php @@ -11,19 +11,6 @@ return [ - /* - |-------------------------------------------------------------------------- - | PDO Fetch Style - |-------------------------------------------------------------------------- - | - | By default, database results will be returned as instances of the PHP - | stdClass object; however, you may desire to retrieve records in an - | array format for simplicity. Here you can tweak the fetch style. - | - */ - - 'fetch' => PDO::FETCH_CLASS, - /* |-------------------------------------------------------------------------- | Default Database Connection Name @@ -58,43 +45,35 @@ 'sqlite' => [ 'driver' => 'sqlite', 'database' => env('DB_DATABASE', database_path('database.sqlite')), - 'prefix' => env('DB_PREFIX', null), + 'prefix' => '', ], 'mysql' => [ - 'driver' => 'mysql', - 'host' => env('DB_HOST', null), - 'database' => env('DB_DATABASE', null), - 'username' => env('DB_USERNAME', null), - 'password' => env('DB_PASSWORD', null), - 'port' => env('DB_PORT', '3306'), - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => env('DB_PREFIX', null), - 'strict' => false, - 'engine' => null, + 'driver' => 'mysql', + 'host' => env('DB_HOST', '127.0.0.1'), + 'unix_socket' => env('DB_UNIX_SOCKET', null), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8mb4', + 'collation' => 'utf8mb4_unicode_ci', + 'prefix' => env('DB_PREFIX', null), + 'strict' => false, + 'engine' => null, ], 'pgsql' => [ - 'driver' => 'pgsql', - 'host' => env('DB_HOST', null), - 'database' => env('DB_DATABASE', null), - 'username' => env('DB_USERNAME', null), - 'password' => env('DB_PASSWORD', null), - 'port' => env('DB_PORT', '5432'), - 'charset' => 'utf8', - 'prefix' => env('DB_PREFIX', null), - 'schema' => env('DB_SCHEMA', 'public'), - ], - - 'sqlsrv' => [ - 'driver' => 'sqlsrv', - 'host' => env('DB_HOST', null), - 'database' => env('DB_DATABASE', null), - 'username' => env('DB_USERNAME', null), - 'password' => env('DB_PASSWORD', null), - 'port' => env('DB_PORT', null), - 'prefix' => env('DB_PREFIX', null), + 'driver' => 'pgsql', + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '5432'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => 'utf8', + 'prefix' => env('DB_PREFIX', null), + 'schema' => env('DB_SCHEMA', 'public'), + 'sslmode' => 'prefer', ], ], @@ -125,13 +104,13 @@ 'redis' => [ - 'cluster' => false, + 'client' => 'predis', 'default' => [ 'host' => env('REDIS_HOST', '127.0.0.1'), + 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), 'database' => env('REDIS_DATABASE', 0), - 'password' => env('REDIS_PASSWORD', null), ], ], diff --git a/config/debugbar.php b/config/debugbar.php new file mode 100644 index 00000000000..f2591b99f80 --- /dev/null +++ b/config/debugbar.php @@ -0,0 +1,201 @@ + env('DEBUGBAR_ENABLED', null), + + /* + |-------------------------------------------------------------------------- + | Storage settings + |-------------------------------------------------------------------------- + | + | DebugBar stores data for session/ajax requests. + | You can disable this, so the debugbar stores data in headers/session, + | but this can cause problems with large data collectors. + | By default, file storage (in the storage folder) is used. Redis and PDO + | can also be used. For PDO, run the package migrations first. + | + */ + 'storage' => [ + 'enabled' => true, + 'driver' => 'file', // redis, file, pdo, custom + 'path' => storage_path('debugbar'), // For file driver + 'connection' => null, // Leave null for default connection (Redis/PDO) + 'provider' => '', // Instance of StorageInterface for custom driver + ], + + /* + |-------------------------------------------------------------------------- + | Vendors + |-------------------------------------------------------------------------- + | + | Vendor files are included by default, but can be set to false. + | This can also be set to 'js' or 'css', to only include javascript or css vendor files. + | Vendor files are for css: font-awesome (including fonts) and highlight.js (css files) + | and for js: jquery and and highlight.js + | So if you want syntax highlighting, set it to true. + | jQuery is set to not conflict with existing jQuery scripts. + | + */ + + 'include_vendors' => true, + + /* + |-------------------------------------------------------------------------- + | Capture Ajax Requests + |-------------------------------------------------------------------------- + | + | The Debugbar can capture Ajax requests and display them. If you don't want this (ie. because of errors), + | you can use this option to disable sending the data through the headers. + | + | Optionally, you can also send ServerTiming headers on ajax requests for the Chrome DevTools. + */ + + 'capture_ajax' => true, + 'add_ajax_timing' => false, + + /* + |-------------------------------------------------------------------------- + | Custom Error Handler for Deprecated warnings + |-------------------------------------------------------------------------- + | + | When enabled, the Debugbar shows deprecated warnings for Symfony components + | in the Messages tab. + | + */ + 'error_handler' => false, + + /* + |-------------------------------------------------------------------------- + | Clockwork integration + |-------------------------------------------------------------------------- + | + | The Debugbar can emulate the Clockwork headers, so you can use the Chrome + | Extension, without the server-side code. It uses Debugbar collectors instead. + | + */ + 'clockwork' => false, + + /* + |-------------------------------------------------------------------------- + | DataCollectors + |-------------------------------------------------------------------------- + | + | Enable/disable DataCollectors + | + */ + + 'collectors' => [ + 'phpinfo' => true, // Php version + 'messages' => true, // Messages + 'time' => true, // Time Datalogger + 'memory' => true, // Memory usage + 'exceptions' => true, // Exception displayer + 'log' => true, // Logs from Monolog (merged in messages if enabled) + 'db' => true, // Show database (PDO) queries and bindings + 'views' => true, // Views with their data + 'route' => true, // Current route information + 'auth' => true, // Display Laravel authentication status + 'gate' => true, // Display Laravel Gate checks + 'session' => true, // Display session data + 'symfony_request' => true, // Only one can be enabled.. + 'mail' => true, // Catch mail messages + 'laravel' => false, // Laravel version and environment + 'events' => false, // All events fired + 'default_request' => false, // Regular or special Symfony request logger + 'logs' => false, // Add the latest log messages + 'files' => false, // Show the included files + 'config' => false, // Display config settings + ], + + /* + |-------------------------------------------------------------------------- + | Extra options + |-------------------------------------------------------------------------- + | + | Configure some DataCollectors + | + */ + + 'options' => [ + 'auth' => [ + 'show_name' => true, // Also show the users name/email in the debugbar + ], + 'db' => [ + 'with_params' => true, // Render SQL with the parameters substituted + 'backtrace' => true, // Use a backtrace to find the origin of the query in your files. + 'timeline' => false, // Add the queries to the timeline + 'explain' => [ // Show EXPLAIN output on queries + 'enabled' => false, + 'types' => ['SELECT'], // ['SELECT', 'INSERT', 'UPDATE', 'DELETE']; for MySQL 5.6.3+ + ], + 'hints' => true, // Show hints for common mistakes + ], + 'mail' => [ + 'full_log' => false, + ], + 'views' => [ + 'data' => false, //Note: Can slow down the application, because the data can be quite large.. + ], + 'route' => [ + 'label' => true, // show complete route on bar + ], + 'logs' => [ + 'file' => null, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Inject Debugbar in Response + |-------------------------------------------------------------------------- + | + | Usually, the debugbar is added just before , by listening to the + | Response after the App is done. If you disable this, you have to add them + | in your template yourself. See http://phpdebugbar.com/docs/rendering.html + | + */ + + 'inject' => true, + + /* + |-------------------------------------------------------------------------- + | DebugBar route prefix + |-------------------------------------------------------------------------- + | + | Sometimes you want to set route prefix to be used by DebugBar to load + | its resources from. Usually the need comes from misconfigured web server or + | from trying to overcome bugs like this: http://trac.nginx.org/nginx/ticket/97 + | + */ + 'route_prefix' => '_debugbar', + + /* + |-------------------------------------------------------------------------- + | DebugBar route domain + |-------------------------------------------------------------------------- + | + | By default DebugBar route served from the same domain that request served. + | To override default domain, specify it as a non-empty value. + */ + 'route_domain' => null, +]; diff --git a/config/emoji.php b/config/emoji.php index d7964b23443..38834500e33 100644 --- a/config/emoji.php +++ b/config/emoji.php @@ -23,4 +23,38 @@ 'token' => env('GITHUB_TOKEN', null), + /* + |-------------------------------------------------------------------------- + | Cache Connection + |-------------------------------------------------------------------------- + | + | Here you may tell us what cache connection to use. To use the default, + | set this to null. + | + */ + + 'connection' => null, + + /* + |-------------------------------------------------------------------------- + | Cache Key + |-------------------------------------------------------------------------- + | + | Here you may tell us what cache key to use for storing the emoji map. + | + */ + + 'key' => 'emoji', + + /* + |-------------------------------------------------------------------------- + | Cache Life + |-------------------------------------------------------------------------- + | + | Here you may tell us how long in minutes to cache the emoji map. + | + */ + + 'life' => 10080, + ]; diff --git a/config/exceptions.php b/config/exceptions.php index 6c73dd23ea6..bbdd386e0e4 100644 --- a/config/exceptions.php +++ b/config/exceptions.php @@ -29,7 +29,7 @@ 'GrahamCampbell\Exceptions\Transformers\AuthTransformer', 'GrahamCampbell\Exceptions\Transformers\CsrfTransformer', 'GrahamCampbell\Exceptions\Transformers\ModelTransformer', - 'CachetHQ\Cachet\Foundation\Exceptions\Transformers\BusTransformer', + 'CachetHQ\Cachet\Exceptions\Transformers\BusTransformer', ], /* @@ -47,9 +47,11 @@ */ 'displayers' => [ - 'CachetHQ\Cachet\Foundation\Exceptions\Displayers\JsonValidationDisplayer', - 'CachetHQ\Cachet\Foundation\Exceptions\Displayers\RedirectDisplayer', - 'CachetHQ\Cachet\Foundation\Exceptions\Displayers\ThrottleDisplayer', + 'CachetHQ\Cachet\Exceptions\Displayers\MaintenanceDisplayer', + 'CachetHQ\Cachet\Exceptions\Displayers\SettingsDisplayer', + 'CachetHQ\Cachet\Exceptions\Displayers\RedirectDisplayer', + 'CachetHQ\Cachet\Exceptions\Displayers\ThrottleDisplayer', + 'CachetHQ\Cachet\Exceptions\Displayers\JsonValidationDisplayer', 'GrahamCampbell\Exceptions\Displayers\DebugDisplayer', 'GrahamCampbell\Exceptions\Displayers\HtmlDisplayer', 'GrahamCampbell\Exceptions\Displayers\JsonDisplayer', @@ -73,7 +75,7 @@ 'GrahamCampbell\Exceptions\Filters\VerboseFilter', 'GrahamCampbell\Exceptions\Filters\CanDisplayFilter', 'GrahamCampbell\Exceptions\Filters\ContentTypeFilter', - 'CachetHQ\Cachet\Foundation\Exceptions\Filters\ApiFilter', + 'CachetHQ\Cachet\Exceptions\Filters\ApiFilter', ], /* @@ -106,7 +108,7 @@ 'Illuminate\Auth\Access\AuthorizationException' => 'warning', 'Illuminate\Database\Eloquent\ModelNotFoundException' => 'warning', 'Illuminate\Session\TokenMismatchException' => 'notice', - 'Symfony\Component\HttpKernel\Exception\HttpExceptionInterface' => 'warning', + 'Symfony\Component\HttpKernel\Exception\HttpExceptionInterface' => 'notice', 'Symfony\Component\Debug\Exception\FatalErrorException' => 'critical', 'Exception' => 'error', ], diff --git a/config/filesystems.php b/config/filesystems.php index 35acb7105b3..d63eb16e4e7 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -17,14 +17,12 @@ |-------------------------------------------------------------------------- | | Here you may specify the default filesystem disk that should be used - | by the framework. A "local" driver, as well as a variety of cloud - | based drivers are available for your choosing. Just store away! - | - | Supported: "local", "ftp", "s3", "rackspace" + | by the framework. The "local" disk, as well as a variety of cloud + | based disks are available to your application. Just store away! | */ - 'default' => 'local', + 'default' => env('FILESYSTEM_DRIVER', 'local'), /* |-------------------------------------------------------------------------- @@ -37,7 +35,7 @@ | */ - 'cloud' => 's3', + 'cloud' => env('FILESYSTEM_CLOUD', 's3'), /* |-------------------------------------------------------------------------- @@ -48,6 +46,8 @@ | may even configure multiple disks of the same driver. Defaults have | been setup for each driver as an example of the required options. | + | Supported Drivers: "local", "ftp", "s3", "rackspace" + | */ 'disks' => [ @@ -57,18 +57,24 @@ 'root' => storage_path('app'), ], + 'database' => [ + 'driver' => 'local', + 'root' => database_path('backups'), + ], + 'public' => [ 'driver' => 'local', 'root' => storage_path('app/public'), + 'url' => env('APP_URL').'/storage', 'visibility' => 'public', ], 's3' => [ 'driver' => 's3', - 'key' => 'your-key', - 'secret' => 'your-secret', - 'region' => 'your-region', - 'bucket' => 'your-bucket', + 'key' => env('AWS_KEY'), + 'secret' => env('AWS_SECRET'), + 'region' => env('AWS_REGION'), + 'bucket' => env('AWS_BUCKET'), ], ], diff --git a/config/hashing.php b/config/hashing.php new file mode 100644 index 00000000000..30adba29435 --- /dev/null +++ b/config/hashing.php @@ -0,0 +1,61 @@ + 'bcrypt', + + /* + |-------------------------------------------------------------------------- + | Bcrypt Options + |-------------------------------------------------------------------------- + | + | Here you may specify the configuration options that should be used when + | passwords are hashed using the Bcrypt algorithm. This will allow you + | to control the amount of time it takes to hash the given password. + | + */ + + 'bcrypt' => [ + 'rounds' => env('BCRYPT_ROUNDS', 10), + ], + + /* + |-------------------------------------------------------------------------- + | Argon Options + |-------------------------------------------------------------------------- + | + | Here you may specify the configuration options that should be used when + | passwords are hashed using the Argon algorithm. These will allow you + | to control the amount of time it takes to hash the given password. + | + */ + + 'argon' => [ + 'memory' => 1024, + 'threads' => 2, + 'time' => 2, + ], + +]; diff --git a/config/langs.php b/config/langs.php index 68e8d358786..d41fc5c6539 100644 --- a/config/langs.php +++ b/config/langs.php @@ -10,36 +10,35 @@ */ return [ - // Enabled langs - 'af' => [ + 'af' => [ 'name' => 'Afrikaans', 'subset' => 'latin', ], - 'ar' => [ + 'ar' => [ 'name' => 'Arabic', 'subset' => 'latin', ], - 'ca' => [ + 'ca' => [ 'name' => 'Catalan', 'subset' => 'latin', ], - 'cs' => [ + 'cs' => [ 'name' => 'Czech', 'subset' => 'latin,latin-ext', ], - 'da' => [ + 'da' => [ 'name' => 'Danish', 'subset' => 'latin,latin-ext', ], - 'de' => [ + 'de' => [ 'name' => 'Deutsch', 'subset' => 'latin,latin-ext', ], - 'el' => [ + 'el' => [ 'name' => 'Greek', 'subset' => 'greek,greek-ext', ], - 'en' => [ + 'en' => [ 'name' => 'English', 'subset' => 'latin', ], @@ -47,55 +46,59 @@ 'name' => 'CrowdIn - InContext Localization', 'subset' => 'latin', ], - 'es' => [ + 'es' => [ 'name' => 'Español', 'subset' => 'latin,latin-ext', ], - 'fa' => [ + 'fa' => [ 'name' => 'Persian', 'subset' => 'latin', ], - 'fi' => [ + 'fi' => [ 'name' => 'Finnish', 'subset' => 'latin,latin-ext', ], - 'fr' => [ + 'fr' => [ 'name' => 'Français', 'subset' => 'latin,latin-ext', ], - 'he' => [ + 'he' => [ 'name' => 'Hebrew', 'subset' => 'latin', ], - 'hu' => [ + 'hu' => [ 'name' => 'Hungarian', 'subset' => 'latin,latin-ext', ], - 'id' => [ + 'id' => [ 'name' => 'Indonesian', 'subset' => 'latin', ], - 'it' => [ + 'it' => [ 'name' => 'Italiano', 'subset' => 'latin,latin-ext', ], - 'ja' => [ + 'ja' => [ 'name' => 'Japanese', 'subset' => 'latin', ], - 'ko' => [ + 'ko' => [ 'name' => '한글', 'subset' => 'latin', ], - 'nl' => [ + 'ms' => [ + 'name' => 'Malay', + 'subset' => 'latin', + ], + 'nl' => [ 'name' => 'Nederlands', 'subset' => 'latin,latin-ext', ], - 'no' => [ + 'no' => [ 'name' => 'Norwegian', 'subset' => 'latin,latin-ext', ], - 'pl' => [ + 'pl' => [ 'name' => 'Polski', 'subset' => 'latin,latin-ext', ], @@ -107,19 +110,19 @@ 'name' => 'Portuguese, Portugal', 'subset' => 'latin,latin-ext', ], - 'ro' => [ + 'ro' => [ 'name' => 'Romanian', 'subset' => 'latin,latin-ext', ], - 'ru' => [ + 'ru' => [ 'name' => 'Русский', 'subset' => 'latin,cyrillic', ], - 'sq' => [ + 'sq' => [ 'name' => 'Albanian', 'subset' => 'latin,latin-ext', ], - 'sr' => [ + 'sr' => [ 'name' => 'Sebrian (Cyrillic)', 'subset' => 'latin,cyrillic,cyrillic-ext', ], @@ -127,15 +130,15 @@ 'name' => 'Swedish', 'subset' => 'latin,latin-ext', ], - 'tr' => [ + 'tr' => [ 'name' => 'Turkish', 'subset' => 'latin,latin-ext', ], - 'uk' => [ + 'uk' => [ 'name' => 'Ukranian', 'subset' => 'latin,cyrillic-ext', ], - 'vi' => [ + 'vi' => [ 'name' => 'Vietnamese', 'subset' => 'latin,vietnamese', ], diff --git a/config/logging.php b/config/logging.php new file mode 100644 index 00000000000..a397bd2ffaa --- /dev/null +++ b/config/logging.php @@ -0,0 +1,99 @@ + env('LOG_CHANNEL', 'stack'), + + /* + |-------------------------------------------------------------------------- + | Log Channels + |-------------------------------------------------------------------------- + | + | Here you may configure the log channels for your application. Out of + | the box, Laravel uses the Monolog PHP logging library. This gives + | you a variety of powerful log handlers / formatters to utilize. + | + | Available Drivers: "single", "daily", "slack", "syslog", + | "errorlog", "monolog", + | "custom", "stack" + | + */ + + 'channels' => [ + 'stack' => [ + 'driver' => 'stack', + 'channels' => ['single'], + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel.log'), + 'level' => 'debug', + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/laravel.log'), + 'level' => 'debug', + 'days' => 7, + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => 'Laravel Log', + 'emoji' => ':boom:', + 'level' => 'critical', + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'handler' => StreamHandler::class, + 'with' => [ + 'stream' => 'php://stderr', + ], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => 'debug', + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => 'debug', + ], + + 'bugsnag' => [ + 'driver' => 'bugsnag', + ], + + 'debug' => [ + 'driver' => 'stack', + 'channels' => ['bugsnag', 'single'], + ], + ], + +]; diff --git a/config/mail.php b/config/mail.php index 94ee71a5b03..122eddc5d09 100644 --- a/config/mail.php +++ b/config/mail.php @@ -20,8 +20,8 @@ | sending of e-mail. You may specify which one you're using throughout | your application here. By default, Laravel is setup for SMTP mail. | - | Supported: "smtp", "mail", "sendmail", "mailgun", "mandrill", - | "ses", "sparkpost", "log" + | Supported: "smtp", "sendmail", "mailgun", "mandrill", "ses", + | "sparkpost", "log", "array" | */ @@ -64,7 +64,10 @@ | */ - 'from' => ['address' => env('MAIL_ADDRESS'), 'name' => env('MAIL_NAME')], + 'from' => [ + 'address' => env('MAIL_ADDRESS'), + 'name' => env('MAIL_NAME', 'Cachet'), + ], /* |-------------------------------------------------------------------------- @@ -92,30 +95,38 @@ 'username' => env('MAIL_USERNAME'), + 'password' => env('MAIL_PASSWORD'), + /* |-------------------------------------------------------------------------- - | SMTP Server Password + | Sendmail System Path |-------------------------------------------------------------------------- | - | Here you may set the password required by your SMTP server to send out - | messages from your application. This will be given to the server on - | connection so that the application will be able to send messages. + | When using the "sendmail" driver to send e-mails, we will need to know + | the path to where Sendmail lives on this server. A default path has + | been provided here, which will work well on most of your systems. | */ - 'password' => env('MAIL_PASSWORD'), + 'sendmail' => '/usr/sbin/sendmail -bs', /* |-------------------------------------------------------------------------- - | Sendmail System Path + | Markdown Mail Settings |-------------------------------------------------------------------------- | - | When using the "sendmail" driver to send e-mails, we will need to know - | the path to where Sendmail lives on this server. A default path has - | been provided here, which will work well on most of your systems. + | If you are using Markdown based email rendering, you may configure your + | theme and component paths here, allowing you to customize the design + | of the emails. Or, you may simply stick with the Laravel defaults! | */ - 'sendmail' => '/usr/sbin/sendmail -bs', + 'markdown' => [ + 'theme' => 'default', + + 'paths' => [ + resource_path('views/vendor/mail'), + ], + ], ]; diff --git a/config/markdown.php b/config/markdown.php index 16e72db8117..b6517bbc29d 100644 --- a/config/markdown.php +++ b/config/markdown.php @@ -39,7 +39,10 @@ | */ - 'extensions' => env('CACHET_EMOJI', false) ? ['AltThree\Emoji\EmojiExtension'] : [], + 'extensions' => array_filter([ + env('CACHET_EMOJI', false) ? 'CachetHQ\Emoji\EmojiExtension' : null, + env('CACHET_AUTO_TWITTER', true) ? 'CachetHQ\Twitter\TwitterExtension' : null, + ]), /* |-------------------------------------------------------------------------- @@ -59,7 +62,7 @@ 'renderer' => [ 'block_separator' => "\n", 'inner_separator' => "\n", - 'soft_break' => "\n", + 'soft_break' => "\n\n", ], /* @@ -116,16 +119,41 @@ /* |-------------------------------------------------------------------------- - | Safe Mode + | HTML Input |-------------------------------------------------------------------------- | - | This option specifies if raw HTML is rendered in the document. Setting - | this to true will not render HTML, and false will. + | This option specifies how to handle untrusted HTML input. | - | Default: false + | Default: 'strip' | */ - 'safe' => true, + 'html_input' => 'strip', + + /* + |-------------------------------------------------------------------------- + | Allow Unsafe Links + |-------------------------------------------------------------------------- + | + | This option specifies whether to allow risky image URLs and links. + | + | Default: true + | + */ + + 'allow_unsafe_links' => false, + + /* + |-------------------------------------------------------------------------- + | Maximum Nesting Level + |-------------------------------------------------------------------------- + | + | This option specifies the maximum permitted block nesting level. + | + | Default: INF + | + */ + + 'max_nesting_level' => INF, ]; diff --git a/config/queue.php b/config/queue.php index 21cafd9c398..a279d302863 100644 --- a/config/queue.php +++ b/config/queue.php @@ -16,15 +16,15 @@ | Default Queue Driver |-------------------------------------------------------------------------- | - | The Laravel queue API supports a variety of back-ends via an unified + | Laravel's queue API supports an assortment of back-ends via a single | API, giving you convenient access to each back-end using the same | syntax for each one. Here you may set the default queue driver. | - | Supported: "null", "sync", "database", "beanstalkd", "sqs", "redis" + | Supported: "sync", "database", "beanstalkd", "sqs", "redis", "null" | */ - 'default' => env('QUEUE_DRIVER', 'database'), + 'default' => env('QUEUE_DRIVER', 'sync'), /* |-------------------------------------------------------------------------- @@ -44,17 +44,17 @@ ], 'database' => [ - 'driver' => 'database', - 'table' => 'jobs', - 'queue' => 'default', - 'expire' => 60, + 'driver' => 'database', + 'table' => 'jobs', + 'queue' => 'default', + 'retry_after' => 90, ], 'beanstalkd' => [ - 'driver' => 'beanstalkd', - 'host' => 'localhost', - 'queue' => 'default', - 'ttr' => 60, + 'driver' => 'beanstalkd', + 'host' => 'localhost', + 'queue' => 'default', + 'retry_after' => 90, ], 'sqs' => [ @@ -67,10 +67,10 @@ ], 'redis' => [ - 'driver' => 'redis', - 'connection' => 'default', - 'queue' => 'default', - 'expire' => 86400, + 'driver' => 'redis', + 'connection' => 'default', + 'queue' => 'default', + 'retry_after' => 90, ], ], diff --git a/config/services.php b/config/services.php index f1a4e4c1b09..097fef01a8f 100644 --- a/config/services.php +++ b/config/services.php @@ -17,13 +17,13 @@ |-------------------------------------------------------------------------- | | This file is for storing the credentials for third party services such - | as Stripe, Mailgun, Mandrill, and others. This file provides a sane + | as Stripe, Mailgun, SparkPost and others. This file provides a sane | default location for this type of information, allowing packages | to have a conventional place to find your various credentials. | */ - 'github' => [ + 'github' => [ 'token' => env('GITHUB_TOKEN'), ], @@ -36,10 +36,16 @@ 'secret' => env('MAIL_PASSWORD'), ], + 'nexmo' => [ + 'key' => env('NEXMO_KEY'), + 'secret' => env('NEXMO_SECRET'), + 'sms_from' => env('NEXMO_SMS_FROM'), + ], + 'ses' => [ 'key' => env('MAIL_USERNAME'), 'secret' => env('MAIL_PASSWORD'), - 'region' => 'us-east-1', + 'region' => env('SES_REGION', 'us-east-1'), ], 'sparkpost' => [ diff --git a/config/session.php b/config/session.php index 12f49d0fe85..dd1c1ead62c 100644 --- a/config/session.php +++ b/config/session.php @@ -94,6 +94,19 @@ 'table' => 'sessions', + /* + |-------------------------------------------------------------------------- + | Session Cache Store + |-------------------------------------------------------------------------- + | + | When using the "apc" or "memcached" session drivers, you may specify a + | cache store that should be used for these sessions. This value must + | correspond with one of the application's configured cache stores. + | + */ + + 'store' => null, + /* |-------------------------------------------------------------------------- | Session Sweeping Lottery @@ -144,7 +157,7 @@ | */ - 'domain' => null, + 'domain' => env('SESSION_DOMAIN', null), /* |-------------------------------------------------------------------------- @@ -157,7 +170,7 @@ | */ - 'secure' => false, + 'secure' => env('SESSION_SECURE_COOKIE', false), /* |-------------------------------------------------------------------------- diff --git a/config/setting.php b/config/setting.php index 109231b5977..d7917b33e90 100644 --- a/config/setting.php +++ b/config/setting.php @@ -33,6 +33,18 @@ 'enable_subscribers' => true, + /* + |-------------------------------------------------------------------------- + | Suppress notifications while in maintenance + |-------------------------------------------------------------------------- + | + | Whether to suppress notification channels if an issue is created during + | planned or in-progress maintenance periods. + | + */ + + 'suppress_notifications_in_maintenance' => true, + /* |-------------------------------------------------------------------------- | Automatic Localization @@ -43,7 +55,7 @@ | */ - 'automatic_localization' => false, + 'automatic_localization' => false, /* |-------------------------------------------------------------------------- @@ -56,4 +68,59 @@ 'show_support' => true, + /* + |-------------------------------------------------------------------------- + | Enable External Dependencies + |-------------------------------------------------------------------------- + | + | Whether to disable third-party dependencies. + | + */ + + 'enable_external_dependencies' => true, + + /* + |-------------------------------------------------------------------------- + | Show the timezone + |-------------------------------------------------------------------------- + | + | Whether to show the status page timezone in the footer. + | + */ + + 'show_timezone' => false, + + /* + |-------------------------------------------------------------------------- + | Skip subscriber verifications + |-------------------------------------------------------------------------- + | + | Whether to allow skipping of subscriber verifications. + | + */ + + 'skip_subscriber_verification' => false, + + /* + |-------------------------------------------------------------------------- + | Only disrupted days + |-------------------------------------------------------------------------- + | + | Whether to only show days with incidents, or each day in the timeline. + | + */ + + 'only_disrupted_days' => false, + + /* + |-------------------------------------------------------------------------- + | Always authenticate + |-------------------------------------------------------------------------- + | + | Whether to lock down Cachet and only allow viewing pages + | when authenticated. + | + */ + + 'always_authenticate' => false, ]; diff --git a/config/tinker.php b/config/tinker.php new file mode 100644 index 00000000000..c2cecedf91b --- /dev/null +++ b/config/tinker.php @@ -0,0 +1,27 @@ + [], + +]; diff --git a/config/trustedproxy.php b/config/trustedproxy.php index 3f10875ddc4..e2fab5269b8 100644 --- a/config/trustedproxy.php +++ b/config/trustedproxy.php @@ -9,65 +9,45 @@ * file that was distributed with this source code. */ -use Illuminate\Http\Request; - return [ /* - |-------------------------------------------------------------------------- - | Trusted Proxies - |-------------------------------------------------------------------------- - | - | Set trusted proxy IP addresses. Both IPv4 and IPv6 addresses are - | supported, along with CIDR notation. The "*" character is syntactic sugar - | within TrustedProxy to trust any proxy; a requirement when you cannot - | know the address of your proxy (e.g. if using Rackspace balancers). - | - | By default, we are trusting CloudFlare only. - | - */ + * Set trusted proxy IP addresses. + * + * Both IPv4 and IPv6 addresses are + * supported, along with CIDR notation. + * + * The "*" character is syntactic sugar + * within TrustedProxy to trust any proxy + * that connects directly to your server, + * a requirement when you cannot know the address + * of your proxy (e.g. if using ELB or similar). + * + */ + 'proxies' => env('TRUSTED_PROXIES'), // [,], '*' - 'proxies' => [ - '103.21.244.0/22', - '103.22.200.0/22', - '103.31.4.0/22', - '104.16.0.0/12', - '108.162.192.0/18', - '131.0.72.0/22', - '141.101.64.0/18', - '162.158.0.0/15', - '172.64.0.0/13', - '173.245.48.0/20', - '188.114.96.0/20', - '190.93.240.0/20', - '197.234.240.0/22', - '198.41.128.0/17', - '199.27.128.0/21', - '2400:cb00::/32', - '2405:8100::/32', - '2405:b500::/32', - '2606:4700::/32', - '2803:f800::/32', - ], + /* + * To trust one or more specific proxies that connect + * directly to your server, use an array of IP addresses: + */ + // 'proxies' => ['192.168.1.1'], /* - |-------------------------------------------------------------------------- - | Respected Headers - |-------------------------------------------------------------------------- - | - | Change these if the proxy does not send the default header names. Note - | that headers such as X-Forwarded-For are transformed to - | HTTP_X_FORWARDED_FOR format. - | - | By default, we are using the Symfony defaults. - | - */ + * Or, to trust all proxies that connect + * directly to your server, use a "*" + */ + // 'proxies' => '*', - 'headers' => [ - Request::HEADER_CLIENT_IP => 'X_FORWARDED_FOR', - Request::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST', - Request::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO', - Request::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT', - ], + /* + * Which headers to use to detect proxy related data (For, Host, Proto, Port) + * + * Options include: + * + * - Illuminate\Http\Request::HEADER_X_FORWARDED_ALL (use all x-forwarded-* headers to establish trust) + * - Illuminate\Http\Request::HEADER_FORWARDED (use the FORWARDED header to establish trust) + * + * @link https://symfony.com/doc/current/deployment/proxies.html + */ + 'headers' => Illuminate\Http\Request::HEADER_X_FORWARDED_ALL, ]; diff --git a/config/view.php b/config/view.php index 7427ba137ed..f2463322cd2 100644 --- a/config/view.php +++ b/config/view.php @@ -22,7 +22,9 @@ | */ - 'paths' => [realpath(base_path('resources/views'))], + 'paths' => [ + resource_path('views'), + ], /* |-------------------------------------------------------------------------- diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 00000000000..92fe4b70c78 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,10 @@ +files: + - + source: '/resources/lang/en/*.php' + translation: '/resources/lang/%locale%/%original_file_name%' + languages_mapping: + locale: + 'en-ES': 'es' + 'fa-IR': 'fa' + 'ko-KR': 'kr' + 'de-DE': 'de' diff --git a/database/backups/.gitignore b/database/backups/.gitignore deleted file mode 100644 index 72e8ffc0db8..00000000000 --- a/database/backups/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index 15862fa3fef..850f9b76a67 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -13,8 +13,11 @@ use CachetHQ\Cachet\Models\ComponentGroup; use CachetHQ\Cachet\Models\Incident; use CachetHQ\Cachet\Models\IncidentTemplate; +use CachetHQ\Cachet\Models\IncidentUpdate; use CachetHQ\Cachet\Models\Metric; use CachetHQ\Cachet\Models\MetricPoint; +use CachetHQ\Cachet\Models\Schedule; +use CachetHQ\Cachet\Models\Setting; use CachetHQ\Cachet\Models\Subscriber; use CachetHQ\Cachet\Models\Subscription; use CachetHQ\Cachet\Models\User; @@ -25,7 +28,7 @@ 'name' => $faker->sentence(), 'description' => $faker->paragraph(), 'link' => $faker->url(), - 'status' => random_int(1, 4), + 'status' => mt_rand(1, 4), 'order' => 0, ]; }); @@ -34,16 +37,19 @@ return [ 'name' => $faker->words(2, true), 'order' => 0, - 'collapsed' => random_int(0, 3), + 'collapsed' => mt_rand(0, 4), + 'visible' => $faker->boolean(), ]; }); $factory->define(Incident::class, function ($faker) { return [ - 'name' => $faker->sentence(), - 'message' => $faker->paragraph(), - 'status' => random_int(1, 4), - 'visible' => 1, + 'name' => $faker->sentence(), + 'user_id' => factory(User::class)->create()->id, + 'message' => $faker->paragraph(), + 'status' => mt_rand(1, 4), + 'visible' => 1, + 'stickied' => false, ]; }); @@ -55,6 +61,15 @@ ]; }); +$factory->define(IncidentUpdate::class, function ($faker) { + return [ + 'incident_id' => factory(Incident::class)->create()->id, + 'message' => $faker->paragraph(), + 'status' => mt_rand(1, 4), + 'user_id' => factory(User::class)->create()->id, + ]; +}); + $factory->define(Metric::class, function ($faker) { return [ 'name' => $faker->sentence(), @@ -70,9 +85,34 @@ $factory->define(MetricPoint::class, function ($faker) { return [ - 'metric_id' => factory(Metric::class)->create()->id, - 'value' => random_int(1, 100), - 'counter' => 1, + 'metric_id' => factory(Metric::class)->create()->id, + 'value' => mt_rand(1, 100), + 'counter' => 1, + 'created_at' => Carbon::now(), + 'updated_at' => Carbon::now(), + ]; +}); + +$factory->define(Schedule::class, function ($faker) { + return [ + 'name' => $faker->sentence(), + 'message' => $faker->paragraph(), + 'status' => Schedule::UPCOMING, + 'scheduled_at' => Carbon::now()->addDays(7), + ]; +}); + +$factory->define(Setting::class, function ($faker) { + return [ + 'name' => 'app_name', + 'value' => 'Cachet Test Demo', + ]; +}); + +$factory->define(Setting::class, function ($faker) { + return [ + 'name' => 'app_refresh_rate', + 'value' => '0', ]; }); diff --git a/database/migrations/2015_05_24_210939_create_jobs_table.php b/database/migrations/2015_05_24_210939_create_jobs_table.php index 9797329a008..3bf01a646c0 100644 --- a/database/migrations/2015_05_24_210939_create_jobs_table.php +++ b/database/migrations/2015_05_24_210939_create_jobs_table.php @@ -11,6 +11,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; class CreateJobsTable extends Migration { diff --git a/database/migrations/2015_05_24_210948_create_failed_jobs_table.php b/database/migrations/2015_05_24_210948_create_failed_jobs_table.php index 011a433f273..6140896bb89 100644 --- a/database/migrations/2015_05_24_210948_create_failed_jobs_table.php +++ b/database/migrations/2015_05_24_210948_create_failed_jobs_table.php @@ -11,6 +11,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; class CreateFailedJobsTable extends Migration { diff --git a/database/migrations/2015_06_10_122216_AlterTableComponentsDropUserIdColumn.php b/database/migrations/2015_06_10_122216_AlterTableComponentsDropUserIdColumn.php index 41d57a3d135..da818389299 100644 --- a/database/migrations/2015_06_10_122216_AlterTableComponentsDropUserIdColumn.php +++ b/database/migrations/2015_06_10_122216_AlterTableComponentsDropUserIdColumn.php @@ -30,6 +30,8 @@ public function up() */ public function down() { - // + Schema::table('components', function (Blueprint $table) { + $table->integer('user_id')->unsigned()->nullable()->default(null)->after('group_id'); + }); } } diff --git a/database/migrations/2015_06_10_122229_AlterTableIncidentsDropUserIdColumn.php b/database/migrations/2015_06_10_122229_AlterTableIncidentsDropUserIdColumn.php index ce694c7467c..44e4ba6a12e 100644 --- a/database/migrations/2015_06_10_122229_AlterTableIncidentsDropUserIdColumn.php +++ b/database/migrations/2015_06_10_122229_AlterTableIncidentsDropUserIdColumn.php @@ -30,6 +30,8 @@ public function up() */ public function down() { - // + Schema::table('incidents', function (Blueprint $table) { + $table->integer('user_id')->unsigned()->nullable()->default(null)->after('message'); + }); } } diff --git a/database/migrations/2015_10_31_211944_CreateInvitesTable.php b/database/migrations/2015_10_31_211944_CreateInvitesTable.php index ae839be810c..b97f820eb40 100644 --- a/database/migrations/2015_10_31_211944_CreateInvitesTable.php +++ b/database/migrations/2015_10_31_211944_CreateInvitesTable.php @@ -11,6 +11,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; class CreateInvitesTable extends Migration { diff --git a/database/migrations/2015_12_26_162258_AlterTableMetricsAddDefaultViewColumn.php b/database/migrations/2015_12_26_162258_AlterTableMetricsAddDefaultViewColumn.php index e27be812422..9014ea11a45 100644 --- a/database/migrations/2015_12_26_162258_AlterTableMetricsAddDefaultViewColumn.php +++ b/database/migrations/2015_12_26_162258_AlterTableMetricsAddDefaultViewColumn.php @@ -35,7 +35,7 @@ public function up() public function down() { Schema::table('metrics', function (Blueprint $table) { - // + $table->dropColumn('default_view'); }); } } diff --git a/database/migrations/2016_03_08_125729_CreateIncidentUpdatesTable.php b/database/migrations/2016_03_08_125729_CreateIncidentUpdatesTable.php new file mode 100644 index 00000000000..1f8f23bed2c --- /dev/null +++ b/database/migrations/2016_03_08_125729_CreateIncidentUpdatesTable.php @@ -0,0 +1,46 @@ +increments('id'); + $table->integer('incident_id')->unsigned(); + $table->integer('status'); + $table->longText('message'); + $table->integer('user_id')->unsigned(); + $table->timestamps(); + + $table->index('incident_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('incident_updates'); + } +} diff --git a/database/migrations/2016_04_29_061916_AlterTableSubscribersAddGlobalColumn.php b/database/migrations/2016_04_29_061916_AlterTableSubscribersAddGlobalColumn.php index 5646703abb1..b5f65ddc5c0 100644 --- a/database/migrations/2016_04_29_061916_AlterTableSubscribersAddGlobalColumn.php +++ b/database/migrations/2016_04_29_061916_AlterTableSubscribersAddGlobalColumn.php @@ -11,6 +11,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\Schema; class AlterTableSubscribersAddGlobalColumn extends Migration { diff --git a/database/migrations/2016_07_25_052444_AlterTableComponentGroupsAddVisibleColumn.php b/database/migrations/2016_07_25_052444_AlterTableComponentGroupsAddVisibleColumn.php new file mode 100644 index 00000000000..4d933d3ebc2 --- /dev/null +++ b/database/migrations/2016_07_25_052444_AlterTableComponentGroupsAddVisibleColumn.php @@ -0,0 +1,46 @@ +tinyInteger('visible') + ->after('order') + ->unsigned() + ->default(\CachetHQ\Cachet\Models\ComponentGroup::VISIBLE_AUTHENTICATED); + + $table->index('visible'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('component_groups', function (Blueprint $table) { + $table->dropColumn('visible'); + }); + } +} diff --git a/database/migrations/2016_08_23_114610_AlterTableUsersAddWelcomedColumn.php b/database/migrations/2016_08_23_114610_AlterTableUsersAddWelcomedColumn.php new file mode 100644 index 00000000000..2783fa19f17 --- /dev/null +++ b/database/migrations/2016_08_23_114610_AlterTableUsersAddWelcomedColumn.php @@ -0,0 +1,41 @@ +boolean('welcomed')->default(false)->after('level'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->dropColumn('welcomed'); + }); + } +} diff --git a/database/migrations/2016_09_04_100000_AlterTableIncidentsAddStickiedColumn.php b/database/migrations/2016_09_04_100000_AlterTableIncidentsAddStickiedColumn.php new file mode 100644 index 00000000000..056c21e1148 --- /dev/null +++ b/database/migrations/2016_09_04_100000_AlterTableIncidentsAddStickiedColumn.php @@ -0,0 +1,39 @@ +boolean('stickied')->after('visible')->default(false); + + $table->index('stickied'); + }); + } + + /** + * Reverse the migrations. + */ + public function down() + { + Schema::table('incidents', function (Blueprint $table) { + $table->dropColumn('stickied'); + }); + } +} diff --git a/database/migrations/2016_10_24_183415_AlterTableIncidentsAddOccurredAtColumn.php b/database/migrations/2016_10_24_183415_AlterTableIncidentsAddOccurredAtColumn.php new file mode 100644 index 00000000000..9fad949701b --- /dev/null +++ b/database/migrations/2016_10_24_183415_AlterTableIncidentsAddOccurredAtColumn.php @@ -0,0 +1,49 @@ +timestamp('occurred_at')->nullable()->after('scheduled_at'); + }); + + // We need a better way of handling data migrations... + $system = app(System::class); + $prefix = $system->getTablePrefix(); + + DB::update("UPDATE {$prefix}incidents SET occurred_at = created_at"); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('incidents', function (Blueprint $table) { + $table->dropColumn('occurred_at'); + }); + } +} diff --git a/database/migrations/2016_10_30_174400_CreateSchedulesTable.php b/database/migrations/2016_10_30_174400_CreateSchedulesTable.php new file mode 100644 index 00000000000..77211985451 --- /dev/null +++ b/database/migrations/2016_10_30_174400_CreateSchedulesTable.php @@ -0,0 +1,45 @@ +increments('id'); + $table->string('name'); + $table->longText('message')->nullable()->default(null); + $table->tinyInteger('status')->unsigned()->default(0); + $table->timestamp('scheduled_at'); + $table->timestamp('completed_at')->nullable()->default(null); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('schedules'); + } +} diff --git a/database/migrations/2016_10_30_174410_CreateScheduleComponentsTable.php b/database/migrations/2016_10_30_174410_CreateScheduleComponentsTable.php new file mode 100644 index 00000000000..0ff151d897c --- /dev/null +++ b/database/migrations/2016_10_30_174410_CreateScheduleComponentsTable.php @@ -0,0 +1,43 @@ +increments('id'); + $table->integer('schedule_id')->unsigned(); + $table->integer('component_id')->unsigned(); + $table->tinyInteger('component_status')->unsigned(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('schedule_components'); + } +} diff --git a/database/migrations/2016_10_30_182324_AlterTableIncidentsRemoveScheduledColumns.php b/database/migrations/2016_10_30_182324_AlterTableIncidentsRemoveScheduledColumns.php new file mode 100644 index 00000000000..a2d4ef5a993 --- /dev/null +++ b/database/migrations/2016_10_30_182324_AlterTableIncidentsRemoveScheduledColumns.php @@ -0,0 +1,50 @@ +getTablePrefix(); + DB::update("INSERT INTO {$prefix}schedules (name, message, scheduled_at, created_at, updated_at) SELECT name, message, scheduled_at, created_at, updated_at FROM {$prefix}incidents WHERE scheduled_at IS NOT NULL"); + + DB::table('incidents')->whereNotNull('scheduled_at')->delete(); + + Schema::table('incidents', function (Blueprint $table) { + $table->dropColumn('scheduled_at'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('incidents', function (Blueprint $table) { + $table->timestamp('scheduled_at')->before('created_at')->nullable()->default(null); + }); + } +} diff --git a/database/migrations/2016_12_04_163502_AlterTableMetricsAddVisibleColumn.php b/database/migrations/2016_12_04_163502_AlterTableMetricsAddVisibleColumn.php new file mode 100644 index 00000000000..51e36de0394 --- /dev/null +++ b/database/migrations/2016_12_04_163502_AlterTableMetricsAddVisibleColumn.php @@ -0,0 +1,43 @@ +unsignedTinyInteger('visible')->after('order')->default(1); + + $table->index('visible'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('metrics', function (Blueprint $table) { + $table->dropColumn('visible'); + }); + } +} diff --git a/database/migrations/2016_12_05_185045_AlterTableComponentsAddMetaColumn.php b/database/migrations/2016_12_05_185045_AlterTableComponentsAddMetaColumn.php new file mode 100644 index 00000000000..fdfe6974e5f --- /dev/null +++ b/database/migrations/2016_12_05_185045_AlterTableComponentsAddMetaColumn.php @@ -0,0 +1,41 @@ +longText('meta')->nullable()->default(null)->after('enabled'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('components', function (Blueprint $table) { + $table->dropColumn('meta'); + }); + } +} diff --git a/database/migrations/2016_12_29_124643_AlterTableSubscribersAddPhoneNumberSlackColumns.php b/database/migrations/2016_12_29_124643_AlterTableSubscribersAddPhoneNumberSlackColumns.php new file mode 100644 index 00000000000..a47b79404f5 --- /dev/null +++ b/database/migrations/2016_12_29_124643_AlterTableSubscribersAddPhoneNumberSlackColumns.php @@ -0,0 +1,43 @@ +string('email')->nullable()->default(null)->change(); + $table->string('phone_number')->nullable()->default(null)->after('verify_code'); + $table->string('slack_webhook_url')->nullable()->default(null)->after('phone_number'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('subscribers', function (Blueprint $table) { + $table->dropColumn(['phone_number', 'slack_webhook_url']); + }); + } +} diff --git a/database/migrations/2016_12_29_155956_AlterTableComponentsMakeLinkNullable.php b/database/migrations/2016_12_29_155956_AlterTableComponentsMakeLinkNullable.php new file mode 100644 index 00000000000..47cd317e809 --- /dev/null +++ b/database/migrations/2016_12_29_155956_AlterTableComponentsMakeLinkNullable.php @@ -0,0 +1,39 @@ +text('link')->nullable()->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // + } +} diff --git a/database/migrations/2017_01_03_143916_create_notifications_table.php b/database/migrations/2017_01_03_143916_create_notifications_table.php new file mode 100644 index 00000000000..d38e48c28db --- /dev/null +++ b/database/migrations/2017_01_03_143916_create_notifications_table.php @@ -0,0 +1,44 @@ +uuid('id')->primary(); + $table->string('type'); + $table->morphs('notifiable'); + $table->text('data'); + $table->timestamp('read_at')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('notifications'); + } +} diff --git a/database/migrations/2017_02_03_222218_CreateActionsTable.php b/database/migrations/2017_02_03_222218_CreateActionsTable.php new file mode 100644 index 00000000000..7c535b18475 --- /dev/null +++ b/database/migrations/2017_02_03_222218_CreateActionsTable.php @@ -0,0 +1,45 @@ +increments('id'); + $table->string('class_name'); + $table->bigInteger('user_id')->unsigned()->index(); + $table->string('username'); + $table->string('information')->nullable(); + $table->string('description'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('actions'); + } +} diff --git a/database/migrations/2017_06_13_181049_CreateMetaTable.php b/database/migrations/2017_06_13_181049_CreateMetaTable.php new file mode 100644 index 00000000000..30f73b14c76 --- /dev/null +++ b/database/migrations/2017_06_13_181049_CreateMetaTable.php @@ -0,0 +1,46 @@ +increments('id'); + $table->string('key')->index(); + $table->string('value'); + $table->integer('meta_id')->unsigned(); + $table->string('meta_type'); + $table->timestamps(); + + $table->index(['meta_id', 'meta_type']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('meta'); + } +} diff --git a/database/migrations/2017_07_18_214718_CreateIncidentComponents.php b/database/migrations/2017_07_18_214718_CreateIncidentComponents.php new file mode 100644 index 00000000000..f1926441c27 --- /dev/null +++ b/database/migrations/2017_07_18_214718_CreateIncidentComponents.php @@ -0,0 +1,43 @@ +increments('id'); + $table->integer('incident_id')->unsigned()->index(); + $table->integer('component_id')->unsigned()->index(); + $table->integer('status_id')->unsigned()->index(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('incident_components'); + } +} diff --git a/database/migrations/2017_09_14_180434_AlterIncidentsAddUserId.php b/database/migrations/2017_09_14_180434_AlterIncidentsAddUserId.php new file mode 100644 index 00000000000..55e42b6ae19 --- /dev/null +++ b/database/migrations/2017_09_14_180434_AlterIncidentsAddUserId.php @@ -0,0 +1,41 @@ +integer('user_id')->unsigned()->nullable()->default(null)->index()->after('id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('incidents', function (Blueprint $table) { + $table->dropColumn('user_id'); + }); + } +} diff --git a/database/migrations/2018_04_02_163328_CreateTaggablesTable.php b/database/migrations/2018_04_02_163328_CreateTaggablesTable.php new file mode 100644 index 00000000000..7a05ce3e68f --- /dev/null +++ b/database/migrations/2018_04_02_163328_CreateTaggablesTable.php @@ -0,0 +1,42 @@ +increments('id'); + $table->integer('tag_id')->unsigned()->index(); + $table->morphs('taggable'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('taggables'); + } +} diff --git a/database/migrations/2018_04_02_163658_MigrateComponentTagTable.php b/database/migrations/2018_04_02_163658_MigrateComponentTagTable.php new file mode 100644 index 00000000000..92690fb3c6b --- /dev/null +++ b/database/migrations/2018_04_02_163658_MigrateComponentTagTable.php @@ -0,0 +1,57 @@ +get()->map(function ($tag) { + return [ + 'tag_id' => $tag->tag_id, + 'taggable_type' => 'components', + 'taggable_id' => $tag->component_id, + ]; + }); + + DB::table('taggables')->insert($tags->toArray()); + + Schema::dropIfExists('component_tag'); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::create('component_tag', function (Blueprint $table) { + $table->engine = 'InnoDB'; + + $table->increments('id'); + $table->integer('component_id'); + $table->integer('tag_id'); + + $table->index('component_id'); + $table->index('tag_id'); + }); + } +} diff --git a/database/migrations/2018_06_14_201440_AlterSchedulesSoftDeletes.php b/database/migrations/2018_06_14_201440_AlterSchedulesSoftDeletes.php new file mode 100644 index 00000000000..fb802abaaaf --- /dev/null +++ b/database/migrations/2018_06_14_201440_AlterSchedulesSoftDeletes.php @@ -0,0 +1,41 @@ +softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('schedules', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + } +} diff --git a/database/migrations/2018_06_17_182507_AlterIncidentsAddNotifications.php b/database/migrations/2018_06_17_182507_AlterIncidentsAddNotifications.php new file mode 100644 index 00000000000..28388137886 --- /dev/null +++ b/database/migrations/2018_06_17_182507_AlterIncidentsAddNotifications.php @@ -0,0 +1,41 @@ +boolean('notifications')->default(false)->after('stickied'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('incidents', function (Blueprint $table) { + $table->dropColumn('notifications'); + }); + } +} diff --git a/database/migrations/2019_12_12_131400_AlterJobsDropReserved.php b/database/migrations/2019_12_12_131400_AlterJobsDropReserved.php new file mode 100644 index 00000000000..903d2df17b1 --- /dev/null +++ b/database/migrations/2019_12_12_131400_AlterJobsDropReserved.php @@ -0,0 +1,41 @@ +dropColumn('reserved'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('jobs', function (Blueprint $table) { + $table->tinyInteger('reserved')->unsigned()->default(0)->after('attempts'); + }); + } +} diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000000..1260e3ff142 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,3 @@ +# Documentation + +_We're in the process of migrating and updating our current [documentation](https://docs.cachethq.io)._ diff --git a/docs/administration-guide/README.md b/docs/administration-guide/README.md new file mode 100644 index 00000000000..aefd5be5209 --- /dev/null +++ b/docs/administration-guide/README.md @@ -0,0 +1 @@ +# Administration Guide diff --git a/docs/api/api-authentication.md b/docs/api/api-authentication.md new file mode 100644 index 00000000000..2499816fead --- /dev/null +++ b/docs/api/api-authentication.md @@ -0,0 +1,53 @@ +# API Authentication + +Authenticating your protected API requests. + +Cachet is built on the belief that your service status is open and transparent, +therefore all `GET` requests are public and require no authentication to access +the information. The following are exempt from this rule: + +- Disabled components will only return in the Component API if you provide a + valid API token. +- The Subscribers API will only work if you provide a valid API token, we + don't want to expose email addresses. + +All other requests require authentication, either with `Basic Auth` or the +preferred `API Token`. + +## Basic Auth + +When making any request to the API which is not a `GET`, you'll need to use +some kind of authentication. The simplest of the authorization methods offered +by Cachet is [BasicAuth][1]. + +> **This is not secure** +> For obvious reasons, sending your authentication details in plain text is not +> secure. We do advise that you add SSL to your Cachet installation for added +> security, but suggest using API tokens. + +To authenticate your requests you only need to provide your email and password. + +``` +$ curl -u username@example.com:password -H "Content-Type: application/json" \ + -d '{"name":"API","description":"An example description","status":1}' \ + http://status.cachethq.io/api/v1/components +``` + +## API Token + +The API Token is generated at installation time for the main user or when a +new team member is added to your status page and can be found on your profile +page (click your profile picture to get there). + +Once you have your token you'll need to add a new request header of +`X-Cachet-Token: TOKEN` + +``` +$ curl -H "Content-Type: application/json;" -H "X-Cachet-Token: YOUR_KEY_HERE" \ + -d '{"name":"API","description":"An example description","status":1}' \ + http://status.cachethq.io/api/v1/components +``` + + + +[1]: http://en.wikipedia.org/wiki/Basic_access_authentication diff --git a/docs/api/api-documentation.md b/docs/api/api-documentation.md new file mode 100644 index 00000000000..665cf883c1d --- /dev/null +++ b/docs/api/api-documentation.md @@ -0,0 +1,48 @@ +# API Documentation for Cachet + +## `GET /api/v1/ping` + +Ping the Cachet instance. + +## `GET /api/v1/version` + +Get the version of Cachet installed. + +## `GET /api/v1/status` + +Get the overall system status. + +## `GET /api/v1/components` + +Get all components. + +## `GET /api/v1/components/:id` + +Get a single component. + +### Params + +- `id` the ID of the component + +## `POST /api/v1/components` + +Create a new component. + +### Params + +- `name` the name of the component +- `description` may be left empty +- `status` +- `link` +- `order` +- `group_id` +- `enabled` +- `meta` + +## `DELETE /api/v1/components/:id` + +Delete a component. + +### Params + +- `id` diff --git a/docs/beacon.md b/docs/beacon.md new file mode 100644 index 00000000000..c4439e5f9c8 --- /dev/null +++ b/docs/beacon.md @@ -0,0 +1,19 @@ +# About Beacon and the information we collect + +To help us understand how Cachet is used, we collect anonymous usage data. + +If you'd prefer not to provide us with this anonymous usage data, please set `CACHET_BEACON` to `false` in your `.env` file. + +## Data collected by Beacon + +- `install_id` - a unique, anonymous installation ID +- `version` - the version of Cachet being used +- `docker` - whether Cachet is being ran from a Docker container +- `database` - the database driver being used +- `data.components` - the amount of configured Components +- `data.incidents` - the amount of reported Incidents +- `data.metrics` - the amount of configured Metrics +- `data.users` - the amount of users +- `data.actions` - the amount of actions performed +- `data.tags` - the amount of Tags created +- `data.schedules` - the amount of reported Schedules diff --git a/docs/component-statuses.md b/docs/component-statuses.md new file mode 100644 index 00000000000..f91ad30670a --- /dev/null +++ b/docs/component-statuses.md @@ -0,0 +1,13 @@ +# Component Statuses + +Unlike Incidents, Cachet starts listing Component statuses from 1. +When creating or updating a component, you'll need to specify a status for it. + +A status can be one of the following: + +Status|Name|Description +------|----|----------- +1|Operational|The component is working +2|Performance issues|The component is experiencing some slowness. +3|Partial Outage|The component may not be working for everybody. This could be a geographical issue for example. +4|Major outage|The component is not working for anybody. diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 00000000000..2ac2e314742 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,74 @@ +# Frequently Asked Questions + +## Logging In + +### I can't login to Cachet, can you reset my password? + +We don't have access to your installation, but you are able to reset your password manually: + +Follow the commands below, replacing `:userId` with the ID of your user. The initially created user will be `1`. + +```bash +$ cd /var/www/ # the root of your Cachet installation +$ php artisan tinker +Psy Shell v0.8.8 (PHP 7.1.6 — cli) by Justin Hileman +>>> $user = CachetHQ\Cachet\Models\User::find(:userId); +=> CachetHQ\Cachet\Models\User {#865 + id: 1, + username: "test", + email: "test@example.com", + api_key: "9yMHsdioQosnyVK4iCVR", + active: 1, + level: 1, + created_at: "2015-07-24 13:42:10", + updated_at: "2015-07-28 15:12:55", +} +>>> $user->update(['password' => 'New Password']); +>>> exit +``` + +## Databases + +### Does Cachet support database X? + +Cachet has built-in support for: + +- MySQL/MariaDB +- SQLite +- PostgreSQL +- SQL Server + +### Can Cachet support database X? + +Cachet is built on the [Laravel](https://laravel.com) framework. By default, +Laravel supports the databases listed above but can be extended to support +new drivers, so whilst technically possible, it's not within scope of the +core team to provide support. + +Each new driver requires additional support, testing and maintenance to +retain compatibility with the features we want to build into Cachet in the +future. + +## Support and troubleshooting + +### Do you offer paid support for Cachet? + +We have been experimenting with paid support for Cachet at a limited scale. +Cachet is not a full-time job, so our time is low and we cannot yet +promise that your support request will be dealt with immediately. + +## Cachet usage + +### Why isn't the _Subscribe_ button enabled? + +Cachet checks some informations before displaying the _Subscribe_ button, +because checking the "Enable subscribers" is not enough. +To see the _Subscribe_ button you need to: + +- Check the box "Enable subscribers" in the settings. +- Set the `MAIL_*` option in your `.env` file. + +The second item is important, because if your mail is not well configured you +won't be able to send mails to your subscribers. + +> Note: The MAIL\_NAME **is** mandatory too, it is the sender name. diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 00000000000..30786d01223 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1 @@ +# Getting started with Cachet diff --git a/docs/images/setup/enable-subscribers.png b/docs/images/setup/enable-subscribers.png new file mode 100644 index 00000000000..c088c39b633 Binary files /dev/null and b/docs/images/setup/enable-subscribers.png differ diff --git a/docs/images/sponsorships/exascale.jpg b/docs/images/sponsorships/exascale.jpg new file mode 100644 index 00000000000..52caa72d34c Binary files /dev/null and b/docs/images/sponsorships/exascale.jpg differ diff --git a/docs/incidents/index.md b/docs/incidents/index.md new file mode 100644 index 00000000000..ea5636c13a1 --- /dev/null +++ b/docs/incidents/index.md @@ -0,0 +1,41 @@ +# Incidents + +An incident is something that should not happen, but that happens anyway. + +## What is exactly an incident + +In your status page you are showing the state of some components. It may be a +server, a database, of whatever you want. +If your database server crashes, it is an incident. + +## Why should I create an incident + +Having a status page is a good thing, being honest with the state of your +components is better. +A status page is not only there to show a green light, it's also there to show +why something bad is happening, and when it will be fixed. + +So, when your component experiences a problem, it's a good practice to create an +incident. + +## How to use the incidents + +When experiencing an incident, it's good to keep being up-to-date with what +happens in the real world. That's why you can use _incident updates_. + +How you manage your incidents is up to you, but if you have no idea you can do +the following: + +1. An incident happens. While a team is working to fix it, a person is creating + an incident. Be clear about what happens. At the same time, set the concerned + component with the right status (_Major Outage_, _Performance issues_ or + other) +2. You identify the origin of the problem, add an _incident update_ to explain + what is the problem, if it's important or not. +3. You think the problem is fixed but are not sure, add an incident update to + explain that. Say it should be fixed, you are watching if everything keeps + being good. +4. If it's not fixed, add an _incident update_ as in the second point because + it's identified bt not fixed. If it's fixed, congratulation! Add an _incident + update_ to explain the details, and say it's definitely fixed. Do not forget + to set the component as _Operational_ again. diff --git a/docs/metrics/create-metric.md b/docs/metrics/create-metric.md new file mode 100644 index 00000000000..b0615a7beba --- /dev/null +++ b/docs/metrics/create-metric.md @@ -0,0 +1,54 @@ +# Create a metric + +This documentation will guide you through the metric creation. +You need to know [what is a metric][1]. + +## Filling the form + +Creating a metric is as simple as filling a form. You just need to know what do +the fields mean. + +To access to the metrics creation, follow these steps: + +- Log into your Cachet instance. +- Once on the Dashboard click `Metrics` in the sidebar. +- Click the `Create a metric` button. + +And you are there! You should be able to see the metric form. +Let's explain the fields: + +- `Name`: The name of the metric as it will be shown on the status page. + Example: "API response time". +- `Suffix`: The suffix that will be added in the tooltip when you put your mouse + over the point on the metric. Usually it's the unit of the raw data. Example: + "ms". If you send "42" to the metric, then "42ms" would be show in the + tooltip. +- `Description`: A description of the metric. What is the usage of the metric? + What does it measure? Example: "The average response time of our API". +- `Calculation of metrics`: What computation should be done on your data before + displaying them in the metric? It may be either _Sum_ or _Average_. Example: + _Average_ to compute the average reponse time for a given time. +- `Default view`: The default view of the metric. Viewing the datas of 1 year + ago is not useful, but it's about your preference to see datas of the last + hour, 12 hours, week or month. Example: _Last 12 hours_ because you want to + see the last 12 hours of data by default. It's only the default view, this can + be changed in a select box. +- `Decimal places` The number of decimal of the point that is displayed. If you + are computing the average of something it's almost sure that you'll get an + average with a coma, line 42,424242. Example: 2 to get 42,42 instead of a long + number. +- `How many minutes of threshold between metric points?`: The number of minutes + between the points in the metric. According to your needs it may be 1, 5 or + even 30. It's really up to you. Example: 60 to get one point every hour. +- `Display chart on the status page?`: If checked, this chart will be displayed + on the status page. But it's possible to create the metric and not showing it. +- `Visibility`: Who should be able to see the chart? You have three choices: + - `Visible to authenticated users`: It means that people won't be able to + see it except if they are authenticated. Useful if it's an internal metric. + - `Visible to everybody`: It means that every user, even not authenticated, + will be able to see the chart. + - `Always hidden`: It means that nobody will be able to see the chart. + + + +[1]: index.md diff --git a/docs/metrics/index.md b/docs/metrics/index.md new file mode 100644 index 00000000000..6efd67642e1 --- /dev/null +++ b/docs/metrics/index.md @@ -0,0 +1,32 @@ +# Metrics + +This guide aims to explain basics about metrics. + +## What are metrics + +When you do monitoring on your services, servers, APIs or others, you can get +raw data. These datas may be a response time to a request, the number of queries +handled in a minute, etc. + +The metrics are these raw datas. Using the [Cachet's API][1] you can send the datas +about what you are monitoring to Cachet. + + +## What can do metrics for you + +Having good metrics to show may be great for customers or partners. + +You have a big webservice that is under pressure? So it's important to have a +short response time. A metric could show to your users that the webservice is +responding fast! +Imagine, you have a metric named "Response time". Every 10 seconds you call your +webservice, and send the response time to the Cachet's API, in the metric. On +your status page you'll be able to see the average response time for a minute +for example. + +Doing so, your users would see that during the last 10 minutes your response +time was worst than previously, and it begins to being better. + + + +[1]: api-documentation.md diff --git a/docs/setup/beacons.md b/docs/setup/beacons.md new file mode 100644 index 00000000000..11c9a729964 --- /dev/null +++ b/docs/setup/beacons.md @@ -0,0 +1,30 @@ +# Beacons + +> **Version Support** +> +> Beacons will be introduced in v2.4.0 + +Cachet will periodically communicate with our remote server. This is done so +that we're able to gather information about the current version of Cachet +and will later be used for system announcements. + +## Disabling the beacon + +To disable the beacon, you can turn off the following setting in your .env file. + +``` +CACHET_BEACON=false +``` + +## What is reported? + +We report the following information to our server: + +- A unique installation ID +- The current version of Cachet +- A support contact email (the first enabled admin's email) +- Anonymous statistics (the number of users, incidents, components and metrics) + +> **Support Contact Email** +> The contact email is used for the sole purpose of security +> announcements and will never be used for anything else. diff --git a/docs/setup/configuring-mail.md b/docs/setup/configuring-mail.md new file mode 100644 index 00000000000..63d7349834c --- /dev/null +++ b/docs/setup/configuring-mail.md @@ -0,0 +1,66 @@ +# Configuring Mail + +Your `.env` file will need to include the following setting keys. + +``` +MAIL_DRIVER=smtp +MAIL_HOST=mailtrap.io +MAIL_PORT=587 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ADDRESS=null +MAIL_NAME=null +MAIL_ENCRYPTION=tls +``` + +After making changes to your mail configuration you'll need to run the +following command within your Cachet installation directory. + +```bash +$ php artisan config:cache + +# If you experience any issues after running this command, run this too: +$ rm -rf bootstrap/cache/* +``` + +## Cachet + Mailgun + +Create an account with [Mailgun][1]. + +MAIL\_USERNAME should be Mailgun domain. +MAIL\_PASSWORD should be Mailgun API Key. + +Edit your `.env` file with the following variables. + +``` +MAIL_DRIVER=mailgun +MAIL_HOST=smtp.mailgun.org +MAIL_PORT=587 +MAIL_USERNAME=alt-three.com +MAIL_PASSWORD=xxxx +MAIL_ADDRESS=support@alt-three.com +MAIL_NAME="Alt Three Services Limited" +MAIL_ENCRYPTION=tls +``` + +The tls encryption setting is required to have e-mails be properly delivered. + +## Cachet + Spark Post + +Create an account with [Spark Post][2]. + +Edit your `.env` file with the following variables. + +``` +MAIL_DRIVER=smtp +MAIL_HOST=smtp.sparkpostmail.com +MAIL_PORT=587 +MAIL_USERNAME=SMTP_Injection +MAIL_PASSWORD=API_TOKEN +MAIL_ADDRESS=support@alt-three.com +MAIL_NAME="Alt Three Services Limited" +MAIL_ENCRYPTION=tls +``` + +[1]: https://mailgun.com/ +[2]: https://www.sparkpost.com/ diff --git a/docs/setup/configuring-queue.md b/docs/setup/configuring-queue.md new file mode 100644 index 00000000000..2fe7d2f9895 --- /dev/null +++ b/docs/setup/configuring-queue.md @@ -0,0 +1,72 @@ +# Configuring the queue + +Cachet uses a queue to send Configuring Mail and Beacons without slowing down +the rest of the application. This can be setup in a variety of ways. + +## Supervisor + +The recommended setup for the queue is to use Supervisor. + +Supervisor is a process manager which makes managing a number of +long-running programs a trivial task by providing a consistent interface +through which they can be monitored and controlled. + +## Installations up to Cachet v2.3 + +`cachet.conf` + +``` +[program:cachet-queue] +command=php artisan queue:work --daemon --delay=2 --sleep=1 --tries=3 +directory=/var/www/cachet/ +redirect\_stderr=true +autostart=true +autorestart=true +user=cachet +``` + +## Installations from Cachet v2.4-dev onwards + +`cachet.conf` + +``` +[program:cachet-queue] +command=php artisan queue:work --delay=1 --sleep=1 --timeout=1800 --tries=3 +directory=/var/www/cachet/ +redirect\_stderr=true +autostart=true +autorestart=true +user=cachet +``` + +> **Update to your configuration!** +> Be sure to update the values in the example configuration above to match +> your installation setup. + +## Database Queue with Cron + +The default installation of Cachet sets the queue type to database which means +that all jobs are stored within your database and is then processed by a cron +job which calls an artisan command from within the project directory. + +You'll need to create a new cron job, in Ubuntu it's a case of running +crontab -e and adding this line: + +`* * * * * php /path/to/artisan schedule:run >> /dev/null 2>&1` + +Close the file and the cron job will now begin running, processing any +confirmation and incident emails. + +## Synchronous Queue (not recommended for larger installs) + +If you cannot add a queue job, another alternative is to process all of +the jobs immediately after they are created. + +> **Not suitable for larger installations!** +> This setup is not ideal for larger installs with hundreds of subscribers +> as each email can take a few seconds to send and would slow down your +> interaction with the system. + +To set this up change the .env file with the following setting: + +`QUEUE_DRIVER=sync` diff --git a/docs/setup/configuring-subscribers.md b/docs/setup/configuring-subscribers.md new file mode 100644 index 00000000000..3c1030a9bdf --- /dev/null +++ b/docs/setup/configuring-subscribers.md @@ -0,0 +1,24 @@ +# Configuring Subscribers + +Learn how to setup subscribers. + +One of the most powerful features of Cachet is the ability to automatically +send notification emails to anybody who has subscribed to your status +page whenever an incident is created. + +> **Hold up!** +> Before going any further, ensure that you've [configured +> the mail][1] and the [queue][2]. + +Once you've [Configuring Mail][1], you need to login to your Dashboard and enable +the Allow people to signup to email notifications? setting found in the +Application Setup panel. + +Once you've enabled this setting you'll see a Subscribe button in the footer +of your status page: + +![Enable subscribers][3] + +[1]: configuring-mail.md +[2]: configuring-queue.md +[3]: ../images/enable-subscribers.png diff --git a/docs/setup/cors.md b/docs/setup/cors.md new file mode 100644 index 00000000000..6e29dc8096f --- /dev/null +++ b/docs/setup/cors.md @@ -0,0 +1,18 @@ +# CORS + +Cross-original resource sharing + +> **External Access** +> By default Cachet can be accessed by any third-party server. + +You may configure your Cachet installation for CORS very easily. To blacklist everybody except one or more domains: + +- Login to your Dashboard +- Go to the Settings panel +- Click on Security +- You'll see a Allowed domains textarea, fill in any domains that you + want to access the API as a comma separated list: + +``` +https://demo.cachethq.io,https://status.cachethq.io +``` diff --git a/docs/setup/installation.md b/docs/setup/installation.md new file mode 100644 index 00000000000..154c2ca3578 --- /dev/null +++ b/docs/setup/installation.md @@ -0,0 +1,182 @@ +# Install Cachet + +This guide will detail how to install Cachet on your server. + +## Download the source code with Git + +> **Check out the latest version!** +> The tags below are examples of what will be shown. +> You should always run git checkout on the latest tag. + +``` +$ cd /var/www # Or wherever you chose to install web applications to +$ git clone https://github.com/CachetHQ/Cachet.git +$ cd Cachet +$ git tag -l + +v2.3.1 +v2.3.10 +v2.3.11 +v2.3.12 +v2.3.13 +v2.3.14 + +git checkout v2.3.14 +``` + +## Editing the configuration file + +By default Cachet comes with a `.env.example` file. You'll need to copy this +file to `.env` regardless of what environment you're working on. + +> On Windows you can use `copy .env.example .env` if you can't do it using the +> explorer. + +It's now just a case of editing this new .env file and setting the values of your setup. + +> **Environment Configuration Notice** +> Any values with spaces in them should be contained within double quotes. + +The `.env` file set environment variables that will be used by the application. + +> **SQLite hosts** +> If you're using SQLite then your .env file should not contain a +> `DB_HOST` key. You'll also need to touch ./database/database.sqlite +> and give it the required permissions. + +## Installing Composer + +Cachet uses dependencies, so it's required to have Composer installed. +Composer can be installed following the [official guide][1] + +## Installing dependencies + +```bash +composer install --no-dev -o +``` + +If you are installing Cachet as a contributor, you can forget the `--no-dev` +option. + +> **Tip for Windows users** +> If you're stuck at the Composer stage, you can run +> `composer install --no-dev -o --no-scripts` +> which usually fixes any issues on Windows servers. + +## Using the install command + +Cachet comes with an installation command that will: + +- Run migrations +- Run seeders (of which there are none) + +```bash +php artisan cachet:install +``` + +> Never change the `APP_KEY` after installation on production environment. +> This will result in all of your encrypted/hashed data being lost. + +> **Getting a 500 - Internal Server Error?** +> If you get a 500 error when visiting your status page, you may need to +> run `chmod -R 755 .env bootstrap/cache storage`. +> Also if you set value `file` for `CACHE_DRIVER` and `SESSION_DRIVER` parameters in `.env` file run `chmod -R 755 bootstrap/cachet`. +> Finally run `rm -rf bootstrap/cache/*` for delete old cache. + +## Running Cachet on Apache + +> **Required Apache Modules** +> You need to enable `mod_rewrite` for Apache. On Debian-based systems you can do this by +> +> `sudo a2enmod rewrite` + +Once Cachet is setup, the Apache installation is as simple as creating a +new Virtual Host entry in the httpd-vhosts.conf file. + +``` + + ServerName cachet.dev + # Or whatever you want to use + ServerAlias cachet.dev + # Make this the same as ServerName + DocumentRoot "/var/www/Cachet/public" + + Require all granted + # Used by Apache 2.4 + Options Indexes FollowSymLinks + AllowOverride All + Order allow,deny + Allow from all + + +``` + +Restart Apache by running the following: + +`sudo service apache2 restart` + + +If you also need HTTPS on apache you will need to get the ssl mod installed +and the default ssl conf file enabled. See DigitalOcean's [documentation][2]. + +## Running Cachet on nginx + +- You'll need to install php5-fpm - [DigitalOcean][3] has a nice LEMP installation tutorial +- Generate your SSL key+certificate +- Create a new vhost such as `/etc/nginx/sites-enabled/cachet.conf:` + +``` +# Upstream to abstract backend connection(s) for php +upstream php { + server unix:/tmp/php-cgi.socket; + server 127.0.0.1:9000; +} + +server { + server_name cachet.mycompany.com; # Or whatever you want to use + listen 80 default; + rewrite ^(.*) https://cachet.mycompany.com$1 permanent; +} + +# HTTPS server + +server { + listen 443; + server_name cachet.mycompany.com; + + root /var/vhost/cachet.mycompany.com/public; + index index.php; + + ssl on; + ssl_certificate /etc/ssl/crt/cachet.mycompany.com.crt; # Or wherever your crt is + ssl_certificate_key /etc/ssl/key/cachet.mycompany.com.key; # Or wherever your key is + ssl_session_timeout 5m; + + # Best practice as at March 2014 + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"; + ssl_buffer_size 1400; # 1400 bytes, within MTU - because we generally have small responses. Could increase to 4k, but default 16k is too big + + location / { + add_header Strict-Transport-Security max-age=15768000; + try_files $uri /index.php$is_args$args; + } + + location ~ \.php$ { + include fastcgi_params; + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_index index.php; + fastcgi_keep_conn on; + add_header Strict-Transport-Security max-age=15768000; + } +} +``` + +Start php5-fpm and nginx and you're done! + + +[1]: https://getcomposer.org/download/ +[2]: https://www.digitalocean.com/community/tutorials/how-to-create-a-ssl-certificate-on-apache-for-ubuntu-14-04 +[3]: https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mysql-php-lemp-stack-on-ubuntu-12-04 diff --git a/docs/setup/prerequisites.md b/docs/setup/prerequisites.md new file mode 100644 index 00000000000..d8d195bdc4c --- /dev/null +++ b/docs/setup/prerequisites.md @@ -0,0 +1,35 @@ +# Prerequisites + +To start using Cachet, you'll need some prerequisites. + +## Application Prerequisites + +You'll need at least the following installed on your server: + +- PHP 7.1.3, you'll also need `ext-gd`, `ext-simplexml`, `ext-xml`, `ext-mbstring` and `ext-tokenizer` installed. +- [Composer][1] +- APCu or Redis for caching. +- A database driver for your DB such as; MySQL, PostgreSQL or SQLite. +- Git + +> **SQLite** +> Whilst we support SQLite, we advise not using it for status pages +> with a high amount of traffic. + +> **MySQL Timezone Info** +> Ensure your MySQL database has been updated with the correct timezone +> information. This will ensure that metrics are shown +> correctly: [https://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html][2] + +## Developer prerequisites + +If you are looking to contribute to Cachet, thank you! Your help is really +appreciated! You may need some extra dependencies; depending on what you're looking for. + +Our CSS is compiled from SCSS, so to compile this you will need the following: + +- Node.js +- NPM or Yarn + +[1]: https://getcomposer.org/ +[2]: https://dev.mysql.com/doc/refman/5.7/en/time-zone-support.html diff --git a/docs/third-party-integrations.md b/docs/third-party-integrations.md new file mode 100644 index 00000000000..1e1f4371bdc --- /dev/null +++ b/docs/third-party-integrations.md @@ -0,0 +1,28 @@ +# Third-party Integrations + +Below is a list of known applications or services using the Cachet API. + +Name|Link|Description +----|----|----------- +Cachet Monitor|[https://github.com/castawaylabs/cachet-monitor][1]|For URL monitoring. Automatic incident updates +Sensu Cachet|[https://github.com/bimlendu/sensu-cachethq][2]|Sensu handler for updating Cachet +Hubot Cachet|[https://github.com/willdurand/hubot-cachet][3]|A hubot script to manage incidents/statuses with Cachet +Nagios Notification|[https://github.com/mpellegrin/nagios-eventhandler-cachet][4]|A Nagios event handler to push Nagios notifications to Cachet API +Salt Cachet|[https://github.com/alkivi-sas/salt-cachet][5]|Salt module to use with Cachet +Pingometer|[https://pingometer.com][6]|Website uptime monitoring +Cachet URL Monitor|[https://github.com/mtakaki/cachet-url-monitor][7]/|Monitors an URL using HTTP status code, latency, and/or payload regex +Zabbix-Cachet|[https://github.com/qk4l/zabbix-cachet][8]|Synhronise your Zabbix IT Services and Cachet +CheckItOn.Us|[https://checkiton.us][9]|Server monitoring tool +Cachet-Monitor|[https://github.com/gaz492/cachet-monitor][10]|Monitors URL status via checking status codes, supports all Cloudflare http codes and more. See README for more + + +[1]: https://github.com/castawaylabs/cachet-monitor +[2]: https://github.com/bimlendu/sensu-cachethq +[3]: https://github.com/willdurand/hubot-cachet +[4]: https://github.com/mpellegrin/nagios-eventhandler-cachet +[5]: https://github.com/alkivi-sas/salt-cachet +[6]: https://pingometer.com/ +[7]: https://github.com/mtakaki/cachet-url-monitor/ +[8]: https://github.com/qk4l/zabbix-cachet +[9]: https://checkiton.us/ +[10]: https://github.com/gaz492/cachet-monitor diff --git a/docs/upgrade/UPGRADE-2.4.md b/docs/upgrade/UPGRADE-2.4.md new file mode 100644 index 00000000000..555ac81da51 --- /dev/null +++ b/docs/upgrade/UPGRADE-2.4.md @@ -0,0 +1,10 @@ +# Upgrading cachet 2.3 to 2.4 + +# PHP 7 +Cachet 2.4 is build using the Laravel 5.6 which requires at least PHP 7.1.3 or higher. + +# Backups +In previous versions Cachet would ship with `backup-manager/laravel` to create database backups at certain points when +running the software. This is no longer provided by default in 2.4. You are free to implement your custom backup +solution when running cachet on your environments. If you do prefer a backup solution close to the pre 2.4 Cachet version: +Spatie has created [a backup manager](https://github.com/spatie/laravel-backup) that comes close to the original implementation. diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index b863c580979..00000000000 --- a/gulpfile.js +++ /dev/null @@ -1,36 +0,0 @@ -var elixir = require('laravel-elixir'); - -elixir.config.production = true; -elixir.config.sourcemaps = false; - -elixir(function (mix) { - mix - .sass('app.scss', 'public/dist/css/app.css') - .styles([ - 'node_modules/jquery-minicolors/jquery.minicolors.css', - 'node_modules/sweetalert/dist/sweetalert.css', - 'node_modules/github-markdown-css/github-markdown.css', - 'public/dist/css/app.css' - ], 'public/dist/css/all.css', './') - .scripts([ - 'node_modules/jquery/dist/jquery.js', - 'node_modules/bootstrap-sass/assets/javascripts/bootstrap.js', - 'node_modules/moment/min/moment-with-locales.js', - 'node_modules/eonasdan-bootstrap-datetimepicker/src/js/bootstrap-datetimepicker.js', - 'node_modules/lodash/lodash.js', - 'node_modules/autosize/dist/autosize.js', - 'node_modules/messenger/build/js/messenger.js', - 'node_modules/sortablejs/Sortable.js', - 'node_modules/livestamp/livestamp.js', - 'node_modules/jquery-minicolors/jquery.minicolors.js', - 'node_modules/jquery-serializeobject/jquery.serializeObject.js', - 'node_modules/chart.js/dist/Chart.js', - 'node_modules/jquery-sparkline/jquery.sparkline.js', - 'node_modules/sweetalert/dist/sweetalert.min.js', - 'resources/assets/js/password-strength.js', - 'resources/assets/js/app.js', - 'resources/assets/js/**/*.js' - ], 'public/dist/js/all.js', './') - .version(['public/dist/css/all.css', 'public/dist/js/all.js']) - .copy('node_modules/ionicons/fonts/', 'public/fonts/'); -}); diff --git a/package.json b/package.json index 8301ed607d9..4677d27360b 100644 --- a/package.json +++ b/package.json @@ -1,25 +1,41 @@ { "name": "cachet", + "scripts": { + "dev": "npm run development", + "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", + "watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", + "watch-poll": "npm run watch -- --watch-poll", + "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", + "prod": "npm run production", + "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" + }, "devDependencies": { - "gulp": "~3.9.1", - "laravel-elixir": "~6.0.0-9", - "animate-sass": "git+https://github.com/tgdev/animate-sass.git", - "autosize": "^3.0.15", - "bootstrap-sass": "^3.3.6", - "chart.js": "^2.1.2", - "eonasdan-bootstrap-datetimepicker": "~3.1", + "animate-sass": "^0.8.2", + "axios": "^0.19", + "bootstrap-sass": "^3.4.3", + "chart.js": "^2.9.4", + "cross-env": "^5.1", + "es5-shim": "^4.5.14", + "flatpickr": "^4.5.7", "github-markdown-css": "^2.3.0", "ionicons": "~2.0", + "jquery": "^3.4.0", "jquery-minicolors": "^2.1.10", "jquery-serializeobject": "^1.0.0", - "jquery-sparkline": "^2.3.2", - "jquery": "~2.2", + "jquery-sparkline": "^2.4.0", + "laravel-mix": "^5.0.9", + "laravel-mix-purgecss": "^4.2.0", "livestamp": "git+https://github.com/mattbradley/livestampjs.git#develop", - "lodash": "^4.12.0", + "lodash": "^4.17.13", "messenger": "git+https://github.com/HubSpot/messenger.git", - "moment": "^2.13.0", - "sortablejs": "^1.4.2", - "sweetalert": "^1.1.3" + "moment": "^2.24.0", + "promise": "^7.3.1", + "sass": "^1.69.5", + "sass-loader": "^8.0.2", + "sortablejs": "^1.8.4", + "sweetalert2": "^6.8.0", + "vue": "^2.7.15", + "vue-template-compiler": "^2.7.15" }, "private": true } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index b7d8cd89ce4..4612898794e 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -25,8 +25,12 @@ ./app + + + + diff --git a/public/build/dist/css/all-81fdbf996d.css b/public/build/dist/css/all-81fdbf996d.css deleted file mode 100644 index c36bea3c55e..00000000000 --- a/public/build/dist/css/all-81fdbf996d.css +++ /dev/null @@ -1,28 +0,0 @@ -@charset "UTF-8";.minicolors{position:relative}.minicolors-sprite{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA2YAAACWCAYAAAC1r5t6AAEuWklEQVR42uz9a8xt25YVhrU+1ner7qseLiEjhERwfkDFeWAEl6dCQcAUCBDCwUSJwg+jRPIzgGVZMcZ2DCKyIycxiSOi2JbMr8hBgFNVGKNAHgKCTBnbUYCYEsHYIoiKKuYW9zzu2XvP0fNjjUfrbfQx5/r23ufWPnX2PvrOWmvOueYc87HmHG201luzv/GzvstvVmG4/3N39H8GAwzAnASHw8zgDpjRdAcOFPz0v/J1mvrm/374h3+48Oevfe1rOh/PnF/xdv+5TvgLf+EvLAv9vJ/38/ATsdzP/bk/l9tZ6c/l/XEyr8/3B9ZT3X07r/1hM/04+U62XW1X2ka/X9Rn63l0e33fHmnLbtvhONOxqiffw9m+9HW4+9h+X87dR5vbv4M+11prHW/mP3/16lU9jqO+fPnSP/nkk/rxxx/XDz74oP7Yj/2Y/8iP/Ej9F/7l/8lLfAXAVwB8mV75L5v26LwvAh8X4EMAHwH40O9//P5Dm58/wn3ZD/pnu7//AMA3APw4gB9ty8GSX++Y9iXAfyqA7wbsOwH/jtYg/vvquiP+ZcC+StO+dJ+GrwDHF+4N+tCBj+3+NxrdduJjzJ3t0z+k6R+01w8B/B0AXwfwX2R3H6AA+J7291UAX4Xjq7DldH0Fjq/A8GV425v7+/s00PRxSnDDJ9TQj0ejDB/D23RrO+Ft+n3+R+F17tQ32s58HUCFHzWen7d9p7Zv0cre6rZ+QnbwJ6AZ9MVnrGMu2t+tX7bvKOnPNnz+0sl96er+9kWEX8ZH9P7Di/f9l6D3q/9ve3/+7zsB/FQA39Xef0f71ev9Sm/U8U4Qpr26xR3Iduijzfv++QO6Z32j3av+Nj3N6N+3Afi72x58B7X4q9JCPkVfkcOfff42AMCLTcO1wWdn7IPkfvW3743/o2/xB/cE4MmAL2D+PXl7tfv78NrmP9F3nxy4GQ5zvALwCoYDwCsAB7y9WpvnOML87LUv4+174/NT+/xLDthX27LffwD/JV0n/+n65zbw1w7Yn2yfv3HA/lzb5qtX67bHfvB613Va2O/dsXA8wfAExxOAG9A+zwP7BThusPYKfAEWTxIcX2jffUuXwk/HJ4DX/S3PLZ9mhMh6z8YNZvZWnwx//s//+bf9pHkHnlzfun+1VrRr8VFAspvn1Ol/k/U8GwwlgITbA26btNN3856zzBusiwYunHsOBsDatPQzvS9t/8PASfbq7n1Zb5/HX1/mOI7Spo1lGhDDcRx49eoVXr165S9fvsSLFy/w4sUL//jjj/HBBx/gx3/8x/G3/tbf8h/5kR95rLeU/HkG7elMO51Zr3rhbQ6uzRejASNr/7PWHitJG4v27qwt2E6LtVcvbXppG7f1z6gxTt+1Ns/ae8fcsOkdSXbGbV3Ozu9i/aKZLbOweAm7baMza2NJH9+6z3VaJ+9zRLVlLD2/c35hrONbDofXdujaOeFu9iP99dNlfF3Q274/H2P4g0N2vj56rnbkdcCNt2vmbQKr1wJZ/bo9+/JunofB3kfPtS/fr3Qtzp/uuJD1D8uPJv6Q9Admj/UoXL6S/Yz7342ac3u4m9c7j7dkB3jndjvzGsPPdvEH2oki72u+B9miu9XuDr8/66J+ZGcgF8kNsNs8O3Z8nrqSX76PVuL77jjafmMjb34RYF+6vy/hmVPGrzBekbW93h/5Tsv572xn5EMAf76dgz8K4McA/F/akORHn4eD/XQfV5VfS+/ZKC0We5qzwzGuewPwN98q8Pna175mb8iQfa6BGTOgz1yWAUJpAxHt8rC3ts0z4IJ9l9Toe/UChNtVm2jesm1337alzSsEVvV54SfgqzSGq7ehgypdDjTNGtgO66O/oy/XAJe5u7XXDsxqm4fjOFBrtfbeXr16Za9evSovX770Fy9e+CeffGLf/OY38eGHH9o3vvEN+/rXv24/+qM/ih/7sR8zz35JHVBhgiG+XVwCNY8Ard7HelB9351Huw110BZm2WwPdn1Wz3p5Gb52mZ5darxTm1uNKyponVjfdfapk+s21+2vdxuzDn7aJ0sOgtOrJ03vc9bT760rzHN17CTrLIn0wufjxNu+ejsvxnvRgLC5w3UPze64tnfPra+HwG77yfK6nbv5xmOTNpFCmN1b5APOTqjHx7kddeNz5+OaXLbL63I0lYrPdVGb5jctXHtm/Vje97t42HRsedj8fVvG5JVbU8vMTYz9Nx6c9fBrsAC6+8CHj9/tvP9mR65dTeZ0PzEB0u1Y+Bxc6Oc4rL8kIxY7sGXJz1e/43t87gkgQ7Jq7bDqwMrTQ7/mpw2oKEmDffcYze9VdoJfrnYo25myh5ZFxsjKCVQ6G5/yizvfeWOxOStlDtZZaeDsJ3038osAfjaA7wfwXwHs1wL2RYN9l4VBuzscm09GC5KhOI9BmY/391cf593hXynwX9GA269og3xftzsp/e8C+MsA/k8A/l+NEv3JCMy+C7B6/sMcd2JbAVlY9u0Ds0/hF/B5ZMweAUV6p/LnAK8N8HkEZIHATxhT6+vsQFAAFOi7fTmTZXwDNHcADFfATJfj7XFb5HvhcwNObmaF2KxKoCoFZg2QIQNpDYDd7pPqYMRqrf3vrmM8Dj+Ow2ut3hiy2l7tOA57+fIl2l/55JNP8PHHH/sHH3yAv/N3/g5+/Md/HF//+tf9gw8+CEM5jgmsLMMw9NkSMLaAMwJmFe2VcElt/TCvE7ghYdX4SnbIIL7vrhJPAFRNgJogSdR7Q8YOtmnmQOWdcfoqIcoOzsJ7BmXc+b1mRjJQtVLMVR6a1s7rBBQV3qZ7W+ZoU/qjtT+OK33LCbx56JjPLncEgsbAFkYsr7ULAksXv19vlad1YC1gbZDZnowYeNjyipEds9PvK4BFwMtzG3RnAN8exzbGaTUaW54jCR0c3XcnwuJ5Mce23MHs/cfhPNDQLruJeH2AngD4x2/Hm5CmL9v2k7oK7tbOu9GPOIP30pfwDjh9gfV92GACQKdDwmebAKj7OMbekLShtvtCO07KkFny2RJEgAQ1IQcndgF7rv60OSck04aWKgnytM10CPjwPclkZ0OeJ0RdETrwtoeWJVnMNntjD+DB65254jIZiLH6oRBr9uonW3fxSwD+mwB+PYBfDdjPLiioA3yZ3NXX1yqMGT8huYNnBNBW9iy+lvuT5rsNjgL/h+rc4n8C4E8A+CEAfxZ3bf1PEmBm38nDZ3l3vJjchHyzrH0WgNR7YLYCsvPBpmsQtrtX+gMMmm9A2hlQ8k27+Dm2kwyeMmEbIHYGzFy27y49DmLTOnM11snAirY/ANYdazqfS+/va63eARsDtVpr6V9qrBg6GOt/r1696sAMx3F4B2QvXryoL168wMuXL8vLly/x0Ucf+QcffIBvfOMb+MY3voEPPvjAP/roI0LPiKUhZ4jAG4hSfFMnGGNpY/UJyjrBUQnP9PkO6m9b7P+5EmGgJ0NKUFnojId7njPwYtAm83ln7ADqrTW2s2QdpNUVhDnp91xqbnB2711/UFcAbf3z8YD0AMYqFTs6jXdmpagd3jHn4QKpnDrWHrvZdc67E1Se7KqFNclNIDkez1ANnM7ziy9Zun09Ab5dIBvwum6pL8v7+Q65zs9Y2mQFvrK+ft7ITTv8ep927dqdFd+dKT8HD0qOnNE02yfcvnUZaDhTTKqU8RyYMZR5RL6oSNOxlfj5BRjDBshmgIx3Kvl3S1b1iKr0SmH6WBcF+ZZNQJkpWHt79UQ/wf++DcAvBPDfAezXGexn3ve0DPjTQdmUJzJL1sGYEdiyFJA5saGRQWP2LANnE6D5+OwowPdW1O8F8NsN/tcA/2MA/g8A/n0ALz/jwOyr8ZdoOx1u6GoDKmH47ACpt7q+d8noI1vuww8/3B6HM5DzpuxaIovc3R3LlRxRwNCWMRO2LZM92hVoOwNmm/cdBBmAgxiwsH7+LBLIgODa50qAC8SIjScJAbPBijUTDzQvjw7SrNZaGJQdxxGAGdeUvXz5Ep988ol/85vfrC9evLAXL17Yhx9+iP738ccf+4sXL6b6zqNsyXFJ06wyRtU6tPoyL+0VAtCYFevLYYK1paNqcewpkDPZVRoka77pyPKONGYMjR1j1sylWK4StbesypNiOpbe9fvu479aXawiShl9/FeI50JjyjLwVsNaLIV3SN531ikyXwtzlgIr2yADEh/aZIOss2BlldY1jiVI5Dy5DuL0uyzQCfXPzTk86AMn6zXWYSt5bwIhWPjY98PhKE3COOZ7Gyjtpd4ygGBc3hVFjunl7jyeOrZTSUcqkkUdw7V+zgpxXjlJYR7PAYg9DW02D4TwfT8jRF94D4vnK4COMzbsTerJNmVyV+Vn9uDfifqPAMXTBZQ52xHbt/xsv0sCZIFznablwOwm+M1OYKTCqOd16Naa2P2ZS+qCTWuPP/PA7O8B8NsB/BrAfrahNCBUiB3jv1mPXNoxqu39TsroWKWMJFcMIE2kjAGU9fkdwFmDg6UByPv0+l8uwD9RUf+JxqT9uwB+P4D//LMJzPAVqSPzeLfTIT7LLnRQjRnetitjWN9bcGX83NeYPQrImAzCXmF/xogtrNIDbVTQ5AlQc3lMVGH/kGyTvzeAUqvdGCDVzALLmEkK5b2Cq/A9BlZmZg04mZkNRqtJNcc8RMnjaB/Vinlr45je5+n74zisyxYbc1ZqrUO+2P7w8uVL60DsxYsX+Pjjj+2jjz6yFy9e+De/+U3rfw28WaV+TyWABsIkdlJDBsItOm1IGQmbBFxjMv2I8kVWBzKZtQU0JqArW9aUDpSdcmq4yhm5SK5mO+OJlJGli1V2Jlzpyy1XuqULZzUfnj64r7tEsT9YPcXLtQGzLmOcnFo8FixzNGLY4pq3IzoJsDxnWMJdwn0eqjqPoYvMjhR+6/PMV04quxX5jqEiBOJB/+crozMesQpqGkvuKzNoXdrosTbNWK64YdVCK8KF4qMd8zqjWj73nKwdk+vmfM4foidSx1G6N/alBnDpY7/8nDtz5VY9NrAkjM4ZUCs4N9zxcyLPHhyVzMimGx41APlCQlGdcU72jJ262AE8uDN8rG/rfZXLz3a+LHYC0kyua7sci39AFFmsbZiZM2phueU789n49/0Afitgv6GgfOcd7qBBISMDpxyYObFl+uoC0KqwY7HGLK0tWySMfZDQhDkrYyDIx+f7q6EA31tQv/eA/zbAfxDAHwTwpz5jjNlXhClrd0JQPRlffLb7CfjnkjF71/+plPFRYw4BOsH840FW7AyQGfZ1XX5iQmJYDT14B5l9S7fBJiMNIAV2q9WpqUlHPQFmvM7Ong3mi4EZyxW77LGfo2Zrv8gc24oK1Yvxd5xYsd6OWwNh3pm04ziGlPHVq1fHcRzWppXEhbEzZvjkk0/w4YcferPMxze/+U28ePHiDvIyXwthyHrJFTyZX3OWbPSlapQy9lqyGvt6iTUmqQGlP+w7m/yAYoQuGexZAsIyCnAsWyc4qzVT/LWdqrNgrsscO02o6DLrFW86B+fWG56aqXRGjBWlnO1QxzipD7FjZt5qtKOeyhiHrcPS9uJ+RkZgsVRHNAnO+pcuRiX500vZO0tHoyLTZcsajKwEPT0DlvxobJYN2vned7BmDAJ1t7PNJJd6IOhS1aDnYwHPHx7cn8WkdvARNWZs+IT8tvtGVo51pp87Q1TAtrjJkjP9CDTKJI2dNTsdV1+0gmfVbRmUOWHQrurLzgCtHtfbHpjdTr5q+0O9Zc4svVAcl1V/1kAZvw6mrESAZp85YParAfunDPb33yWJpd3NI0PGssVu7JHXmOV1ZqusMZc07pwZy6g5W6WMNcgYfXyuAULOPSjw7y6ov/WA/1bA/z0A/3MAf/IzAsy+eg5hgtEH2WWF9++B2WcAmPmGcUqPUQMOx4PATQZ7PXssVuTySce5MYera6LIFzOQZiplTEBVYLS6cUhntjrjVErBcRxWSkGt1XochDgldpnhIWxZqClz91H7lQCxwZi5+43BYJMm9m24uxeWLrLBR8sh6+sqDMxIwuivXr3qWWV2HId1UMbArAOxjz76qH7yySel1aH5y5cv76ALOYnDSj3bIQBmshSwHRNgdSKpNsliNzHobFlkHbA6dVcZb1p+IBmVIA31jdVkeOg3tiwAuP56TIBVM8MPp7bUiCC1/ox/duZSXOfSDVkL3Z1g2XycRQljtOxAUiVWlxoxPqC+HNy5M0ZCSm7j8ET0XSVXNOy4g7FuImHDyy+4J7aLYTCptMXq3VTIA8DzzGLP+jZ7WbsPfsgaOBikU5M2GuZrl9MxhLBFxCkAyWvb3uzAhFPeZJOsujWqMHAFWEZbdumqGqhVzeWyNcTNmjcYc3qWYmTmxYzRstEP2eQ69JaLOtq/gYByg7HmvBkB5J2XNcT1DF/hgnMDw3KCY4CHLQDtBCRcGYIohjwHZjeBNVcwcAfWtiMaj6Cex0Fad/Z/EfcgA2daxmcXOPn53T4x/xh0XQdmBMR6P3jEp3S7/PMKwHcHkOGfMdgvt8YnRSBWgAC+CgGtEhiyCNQQXlfDD9vWmJ2BMn2dIC2TMjKLVgNoK+0+bYNJq7/GUH8N4H8SwL/0rjNoTyhfiUXmqsNV0bjRxHCXiYr198Ds3fiXyeweAFu5M/nKZJ2ZezDQqifrGnc3XQ/Vbu3YNCfWiwFXb9eI1esmG02q2GWL1hmoBNChyQSHu+HGwr4AcF6PAjN67yR1LA2chfqzxnwNEKuSxQa2uvNisMTnurLOmjUpY7fE7+6LvbbMXr58aQ2sBSkjv+8SxlevXpVXr17VWqu5jmyLJ8ZigpdJFp1wTDK9lgbI+tdJFUiGcdHcEBO8YWOjv1BKi6RLUKQx2rz483p3uWUnk278EXSYmAjTFbCJEUgCTKKUMed2qgA1p2ynWVvGn7sI0ZHHzfWHY8U0+dibgOTHiC37l65+vF+d9c1rQDFY6tkI4HQAE1wXfQPCBAFVI9Nin0ctdPp5XR6h1oDAnngWbnLaVA5ZEyZvsm2rX4wtoxPRjdKVIwxmHr5KQxfHEqbFJwCrmGb2oQSCt+3MlsZj5zwQYSuTOL9r0XQkXkBTeskDNWdZZVks35XFIvaEiV10Oq6cGdk34+mUE39KYE2m2TyzxbjwNXxEf3n1WdnKhPMzrBYmWenfI+SlP+voNzBWmtFHlzCmUkZizsbrO/vv+wH7Jw32q0uDLROQFbK5LwvP1M0/dkxZEVOQgsyhESJltADE1Dqfa80mOJtM2Wz5lDJGpsxEfGkE0ipsQNL6qwz1VwH444D/L95VBu0J+BKNCGykELscSEtHmN92jlm4+t9Cjtlb5Z7fJaOPbLmf+TN/pjJLZzb4Z46H6SPppD7syjkxq9EyYcUCaOsyQ0zZYXH3w/uoq7gyErCDvA+DcSwzFEbOxMSjgylm77iubLgyErgKIK4DOAZlCs6ojoyBWVEb/OM4nNi0wiCySRdxHEcl6aJ1R8b2B2LB6nEcpYdKdyOQzpB9/PHH9eXLl3j16tWdhduwYZ5YABr3tTYh0+6IurnuMu9kmV8jCGMHele2zpJ2GXJNV5V5UIt6sr73BEX2HejzOzDrr0PKSH7/AcNYRJwBy1g0AFksMFfgNmOe14QyJ0ARxYZs62HD/EP/Vs/GrMaMoQRb64MsH5C+M2/jr078ls2TVjsbZTZc9I1gRjeKGEBg+s038DLjBmKG2MqUWlvWMZWmDCDv22Mj927VzkxSq91qpiQ1jGFOBqu2Hwrve8g5s3lNkkm9mHKQnb+RlSmxYib1ib5oCi068Te2zQbgkZjTxvC6cbs8wHBjhtOBap6w2BZjU+/2R3c21Jpb58iiq0AAbNbaNY/n/bDX1nYssVRbm/wzaSMuGDWVgCA1YN9ucleWlUtXdtVZZ6LJgtylMev0nYz7ZMjoEXmoADPDuYwx++pVAtu55Db5Vq8nKwBuvYZMZIxql9+ljP5OGoD8PQD+OUP5h6azYkmki4WcFudnFQUym1YDCMtkjcyinWWYxfoydWZUUKaujBZqy7TGrI7PnVlj0FaGSNN/LVB/LYB/HcDvA/CfvVvAzL4cLY2MmbKTgGmeHwvj3zNm79C/Z9SY2QVoKyfM184eP3M/VDt7BUoLOMJqBKL5YUAcXDYNZRagZhvXxPCeAVObXsXWfqyzyQ+HlFGAVmmvNZM50nwnaSRb6aNLFLPg6A7AiDHrLoxgS/wG1soGmOHly5f11atX5cWLF+zS6I1dQ5dB1lpn+VPiuOYEyAJ7tguVrjlz5uQsP9wZyXlxIZ8Q5YzBQ0OxDT/B2T6/GharSQjqWyzzJQ/AfAVmXCTHhXLV84K54PuPyUA4We4bdbyRktkLy7KKEI1U+pHR8QWcNXOGUImWGX9AODggqznLbEpKjUyajxNXhW3y4UpYOXC6ChO2s4Zn4wwjRotzwtXt0GMJIrs0pmwYnw+vi7zQ6buTlPUwxtmBH2pinNGBYaVlnbdP13KN28zMTgJoFmtTF4bOwL8vNg5ZTTgiq8iB4EaB0nX8Jrw5PTr9mJ3zzFyPs5M81RcDlPCEup3QMQXnQckP+rPbA6+6yZ3LfBcrrsDshuuiuUfYss2Y9XNK1XYOl1kGAFGABXf7kiyJDc/YC1yelqSBnYy4dXAmdWWFbfPJLt/ajrx7wOzbAPxjcPsX4eU7ipUFhOUAbfJLuRujETNmQ4RdBuSBhE1HN8Yql8SjUkaWMM5pHurMatpaBmF1QM/SFB4diHaQ5sD/sMJ+C4B/DsAfwDsSTvcE+9LU0Ya7tK3Twkgt1nyzeyfhbfO7bxtIvdP886cFzNRt8EFQlppsMChqTFUAZMRseRIS3X+HnkgXFeA5rYvrv1xZPq4N659l/xRIPReYQQ08ZFkk75kBUzDGn5k9c9zt8J2zypK6MhcgBgJjB08nYFa7C2ObXhoL1oFYB2gcND0A3CeffOKNpQsSxZATRrePusEuUEMQWaZjmlom2ZEK4/L+ZV5rlolzzz4PNk2rrZDoMzEpPjYBqYREfbcDSNgvJCwZyOWiJiDMaIpvhQG2GH9kDo0xoW3ubW3LHGIAklvlS/XUyc3cloEjX4AbwgBiAEc2qVSTGIeBixwbyhSD0VrOCX3ZLV7vwyY+tac34uEGl7ZeZm2bBkc1C5aKRmxbtJPPcWYoHAPXe8XwZ5MA7DBW0am+ujKwca9myLVReQMlfYSRGv5e8J/sTpA0KOxtBIaH9kzdIulqGldYZ9MoygDtmBp8BWRallUexC+WjCnILD/BdI9EpLG7fJf6IQVmTw+CMrtAVifdrKsStTNdYcZKCjC7bdiw8sCxe8TSZHuD70zZjRgzBmGFasqMQFp/9e7O+E78+37A/hV4+a+hltHmYoXkiUWkiwXRfbEkph+lAaQi7FiUMuZh0wzAbMkte46UkUFYXk8Wa8tKqKCrKAQ9p6zRxzEosO+qsP9VBf4HDvyTeAfqz+6ujCYCa0NODi99AK1He8+YvWv/2L79pBbsTL64mzaAV2LOsQVdZGoBRne97ktAZLnPqsuyVFeGVkjmtdZhnS+gzgVgMZC0zPpezT1onwJIo/U71ZQpEHPNMZNA6LGNnlXWjUDo1YUt6+Ct2+GzRX7peWW9xoxcGAfQauDMGjizxpbVly9f+nEcw0q/G4RwXVs9wzRdzefRcMNX7/VocqhlWUdTNyaOjFyGxaVaofsmtWeLoayyZoH6YyYIyKGhFsb1nAA2AhEp49h3tpuU+YttvglrBmx89kJLI6CyRb6IsAdqAsJeLNMc/35GJozb15lVccjTLXuKlmcWO6SWji4g70xSUj/liTff8iYLgd45B7rQrcziZFQstWW3LbqX0ihU3C47Dj5iibj1bZAIAIuFbQE41yjNhOyNY/VtcrbV54EBx8xfU9OckBOoO71Kdd186Y6EIzzMo31ky3HYd2DMdvpBnACKM4CSHPNHQVm5IJkS9Z+MLz/KlNkDO+Pn4CzrOT2KA7mpT3M9Gd93BSfLCTbc/xw8MmVjw8SYWUlqy9jwQ+vLDLCnd6GL978G7B9Bvd1GLZwXwK0Bs0KQJpMyFnFeLKlD47siZazUshLyzGpodf88TUBMuMHaLoPJqxnsv3EA/54D/xqA3/kTC8zKF9vJfADKcCKcLmB9xPit55iF+9JbyDH7zAVPvA3GbAe0TqYHwMZAqPeIhIXLTDyWmjPK7GIzDmd3xA4+GigzMvHoZh0DJPRssLkrk/nq3xVwOMDYBUu2LLcBXtm8fgy6MQgaumRgdrufnmF1z2YhLEvsDNpikd8BGwEvdmLswAwM1F69elVJmjjAWpMzllevXvmLFy/A+Wcd3L18+RLNVMSqb/pUwl7VBtKChBEx5ssoAmzUnB335wvXjw3cws6MZKW/GB2qY1xmJKh3K5YyUj3SliXj4DUjIMbzQo2ZIh8CaBo6rQqF9ReadqoyS3dLzOo5bJq5ryopZd34wwf3U2Xqmn/AAkkPIM2R2E+Ee9EEPDwGeH/GdAOIYQTBxnyDLqOiQTMJhG41SUO+aIv4jscmK9HBo8zLWqSBTUYMWEq1ePPj/jlPjlEdGFXJUYmAu4fAbWcKmOSXo+ZrOC5q6HbMS7eRy9bbOPfB6fp3R3J0JGG6H4t2BAzRGbG6C90nUd+LcUprCw/+pvar8QA7HWsNvr+sgboCGbhAWsmtxE9IJj9hgFTSd8Nd7rf++7YTaHPDuT7zTI94sq87kGa4rtvT+chVpWc5ZnYhedoDNQZlLF9EZMsYoAUARiBtcTP5Cfv3vQD+APz2y1Fbm0ppZjzTUbIYV2N1j0JLGDRDJnFcJY3RnfFKyvhcq/xcyuijbnq1y+8mIBbm9c+VZIsTgvW9tPZkmn8Ge6qw31Fh/3UA/zCAv/oTxJh9+d6okg2eWOwUFAFnOlBY3j4we9fX9y4ZfWTL/Y2/8TfOANjClnUExC6DZuaUk4UWjjymGT3Za60dfJUOMGi9gRnrjFGXIXYQQ2HMxd0rM2icE9amj2WScGfOKuuSQGXJdhLFDJgVrRPjZboRCS3rwpCVLkUU+WLpx5zAZK8z8437Iup95q0Bs9qAVKVlbsdx1JcvX9YuaWzThl3+ixcvagNyt2YUguM4/MWLF/XVq1d9WWusWT2OY+IXJZxcJI3c31KWzKeaqSbDne7RkbHSYPvO1Z7nszGbmsTl1vhyi2CHxjM3xmDNrrQg7UxIxLaYns37wRJG7tS6Wkyqa2PNJA2LE+PkOSzUBKkIEQTK+vSjPTQRYkRzjWrcEsisYuWj+Hv9tmOtZixk0bnLbtvAR73Wqn9vmFVU4oTMUCtgVuG1GVY0IDhMQvoYo0jU7peB3dmYyjJDD8fXQl0jsTa97dVmG6svlYCDGO0mH0OMQsoEYofYo6bXV1kDj1573pmpZ+XAP/fl+j161ox1y/vaK/gofqAD3TubVxdHxHm8WCxLMtyRNeghdWf8lMwD7o3lyTblmG05tONe23L9uN7Pb7/GSk+lvG+3nFBXu97+A3b5Vy77VzlmGUh74lHP8a2nE9YsA1sXdN+O/vMHG7sDdBnSfALwKko1d5wf8EZCzNh3HWV5dgdoIbeMN9J/dAlr1hkpuw4z+BT//SNNuvjlu3Sx/Q2AZujT7VaoziqCtDzHbNrnr5JGBWq4kDLas6zyVynjCsYcM0szt8d3AmIsZzR6X3AD2lKdNQNqe23s2a+ssP+oAr/DgH/zJwCYfZGoWhkRA/Y2stmv4n2N2Tv378ouP5EcZt8L5hsETDzbRgMW9WRZVyZNJIQd0LBrImidXMtViRnkGjMQc5a1YamDk5oyBVUQu3sGW5WW5ZoyF3aNrfd7cHWXKQZpYwdwAG6UTWYaKk1yxm6Jz3b5Y33EkFkHaR1wdSasSReN5oEZsw7E3b2oC6JtFGF+4pw+pI51lTN6yy1zAAcp/tjIsJuBOGGpkEklNWjmiQJgqw64CGBT4KWSRsukjIj0XhVNZgBnyM1AlDFY3UlCfpmJRJEZsg7cMvmiGt9zwLQPKxAn+OYLY7bajOwERzZrl5wgZGd/XAoJh5xNA4nb91suliohezBzNKyQCzeJV6hONhXi7KFyRZcE58VlXkw/+BpyKSPwtj8WDebX2sRRv8ubcYLrvv4mQ/gZr9aJqPLIBNLyMZrAw4CGJ0Ky/MBOt30nl8qllFN+e3z+xlXtzBN7aMu9avepIYB207F6H0jO6Jgr58WNN/surtkvNnEmaxT1H63hCtIoZbXjlB6QL/pJj+wR8w+K/uporBt/aDT2I06MWcbZvtPYGLKb5yHjxVZWrE8b4KyDMa07+5Z3Jb8M4J8Gyr8QAJkX5ABtlTRmtWaZ+UdupW8JQIugrI5BBAuALJcyxvqyWFMGAmMuEsc7lNJgaXZltMGUkVBx7CkGW5axZnSlfRWwf8OBnwbgXwHwzW8dMCtfphGBROLjUkUNMv7wtHr+XQdSnysp4xkwe4RBI7Cj5h/qwmjJOpZA6c4OKXBDdF4MdvmcedYZM/pu4TBmWq4KGFMmbLxm7NnZcgn4sgyY9XUmDotGNWlcb9bnFbLB7wCtyxkr1Z3daq1HB2QNjA3jkMaQlWaRrzlm1mvQ+rxeS8YgrbFyDATv+7Az8UC8E/smj9lJxhhAGc0/nNR/Hj0znGSNmmPGpFOlEiHzhC3LQJqptMrFfvwBKOMuwEyQpNvKpOmfajMD2sgaHvPLJgzY2+TXjeFHTf+mkb4t38yOwwRpnJyGNMJ6gic1tHDyaDfnzjmfn/6pIXhbD5f75Ld8SBynPbxhSggnM3Nn1hwWrOeHa2IHv2IB740GMq0d67wY6+w6w0cB2VH6OBksbv/gPAcrSNPIgKO7Vlrw8W/HkG7PPXDbg+GIzXDpdm5skTn29dN5GcYm87fnYcK8pscaeBDFVvdMo2tYBZZ9eXeL1H3HuuULDYh5Y83K/ebTQVpn0a6YoRNv9rIZyy649sjIXgnHiGX+mfFH5m14LvRbIM1VLRmw97YvF+iq7VQo73Lx36Bb8G6TO55gMYVipmwYfZjIF7M/zi1Lssy+9TlmXwTsj8LLr47SxXJ3iDSL4GwANIM9FZRQa1aSmjI1/yipnJEljVHKON0aHUiDph+pL+OaMk8Cpvf2+C6AzIIByJQ6TlGkhf9Ags44vcJ+b4X9IgC/CcDLbyFjRjVmhXQ/Zmvxdag3MxkmfPtSxq997WthfW8hx+xzZf7RpGdZhlkmY4QabXR5oSxjTc64A2n9dt6ljF1OaE12yOCLm7Y14aCFAoMl4BEJI2ZSG4ekLiyVMipAI9mhkxSRs8ucgFnpbezghuWNmPVl0M/t/eLCSKYfA7Q1KWOlejIA6BLEo4G1W6856w6MXb7YAFp98eJFbXJGa5b41iSQN2Lh7NWrV/dtWuIWx07yZ46MVaz1sfbtGYdAyKbK7IBNK/1ALvE2LGkXq6NOh25c7nHA3l5yYw7i5LXuyopJgdw6VJK3bxkwA7FkylnEsDZP+D89BSuIm+HTIDN9CzHViszzkbApbbQVWnZZHSwYecArpnGhRRt+sgB1cic0i46KdLuA0/lyH4btE8V38WXXUvbtu6XXg1OxFwcy97GmUP9EEssO7ypdpIaOLV3KDrmmykOGGQb/yZlqE7TctectaYyy3txYLjuvuTokgQyCuy19dFVkdmuYhzhdFR5ZSiPwN65YlXY619LRdONQbYs3AnUCdQJ2pSMCAmIDlB3tz5/nzW7724ZdkFA7FiiDWR2GvVyA2RkiOgNjV0YgmxsDTr6SoaRNcJs93XHyE/beK6GFCTewkJm+MpNwAE9+Z8tu4sI4ECCDT2bOINllQDQCsW8lY/bzAfxLqOVX3kFX4xfrbbaPwZjWmtUCK5NTipLFQnJFE6MQO6k3u3JljCL3sn3v29csYPrMHn81+eAcs/v0G26BJVNoNl9BnwHAfl2F/SCA3wXgP/wWMGZfwtBf48E7S/rePy0p43vG7C0wZkkQ9ILLuK4M0YnQmf3pQERYLgZR1pgulQUOEJSAxNF7VGv7zXY6+Dk2mWaLhT2iXb5fGH7wMbEzeSJviwOihSEbbetW9iTDHOtimSNJFwvlmHmttTQXxl5X1k0/vIM0ssuv3YmRHRtbJlmXKZbGktUudezs2atXr0CZaXMf6NdEg9PBIt+wL89i58aMaOlSxurRmRHKktmq/KtJ+VXFGi2V15nRmthcYyttFCmfH+27tHOLlBHR/MOji1yOkizea5c4k9Uy3ynamR+WEGgFWkY5wNnU6cTowoJhMdrP/yJzFnt8HNxMnE8AoAysKh2Gu9xvhow5AQgj7d5gWlqn3pklC515yeZsaKcy4Jvc/pDfuVUChK3GiZnAjrPNwN6RA2Txb8bqGJFWGWNIeqM6t+hYGJm2vmxtoMx7PVhleWKd7PICtWvr0GDESBtdtxyrZ+SaOEw5FiaJrV+IGWX7VGLrxhkM7qm0z+zmyeMQfYHydGfMCu6d1cKSxt757gDtAVnjA2rAK/bsjDnT90/SbYuavBv2scxnlF+5Bp56LM5w3SYlm3FDj//6wtM+WDud5hFLmc/LJPi4qOJLLfEL7sDFkDNlwMaV8YbFmfFbA8x+Gdx+CPX2HfNgdobsdiJlbNd0Y9XMCszWWrNZZcX2GnnA9L7GLANjlmaYecKcqayRWbO6tcXfMWdGe1bps7VfSfzPBZZFeSNGLV5b5vsP4Bc58GsB/LlPnzHrF5ixTXH2np6GkCHvmWP2uTL/eJeMPrLlvvu7v3snW1ymkXEHAxvOIBufWaLI4C8x4dBtmsodhTFTtswTyaPvgBczcB1IdPOPRJaodWSeMGqWgMoBsBJp4+79aCcZqRixZgPEkfNkB3BOWWXdJMQbGKudzaIcM3ZjRA+FJmljPY6jW+ZbA3ZduggGZn2e1JjlakB1RLsgk+rqsB4+e42GhZWkjUMdWFdn+dG/rgi1ZyUUHCG3zXeTnqSLtDFrtDJk5NDY883Gvqkzo0gcF3zDiJR73TWxaV/dCaJa0wO/xUzYrALzU4A2YVpt3z6EY6sngGyBx9RhH7+p0PZl91xkbL4GHXcq10OVVI0YnK3UQ/ZV+6wlUUQNh6gPn8lwg6zTejUtD3Snh75Y7IcEBE9j1aJTaN+GR8rYZB/FIWcp0wIoSNvuIFO/thi7MKMcWfDAhvkaHLBMMWGDez5djYMMcQUurLfnVLD5nTHrPfthANJvCk3WeLsB9qqBs3oOQB4Y+S0nmMZOoBRLGffAjAumdhpCPCAC3BTc2sX7CwyokWDlFkuinr7QWu8TOwVJIwg7YUNmekx6ckXCUFDWLfE9AWStoc7SRQmkhrozfuo5Zr8csB9ELV+NVvhllS1mAM0JpJWS1JqVxPRjdWUszfKpL7UCNQZjbJe/ZphZkCxG1mxXY1aDVUk0/1CmbEoYI1NWRh2zBclivbCbqWOAagC176rAHwfw6wD82U+fMeMR24I4+pQFSiPhkvGeMXvX/vWOzkV9WWaMEcAUMVbOwIa+E1wYQbVftD4eyxwsmTBrLFfMpIuBQRNghqQ2jA1ElD0zAYE7S3wos9bBFM7NP7JwabCNf/tcWwYbyxbZZn+AJQZjZPzR7fAHG0fgzGqtpTFkfhxH6c6LzWVxLNvAm3cgRyCw0DEIxvHsqhi6mZkujjptnjnPi/v8YvCB+Vn7YZ7Vusm40WWgdF9Sd8IvEqqdNJx9Q1Xrzfq+nUgaPcmM5HokF92O57c0D5lSCKALQ7Sn0i8Ek5D4WTPQ6pjawZotoMsFDLnILTngmqqj3FNj9azf3dc0pW4TlbuttWqGjTNncijXTl7Sqh6IjOw7FlwWzx5FtjuVfiEvyxEuVqONuKO+43RG3VxdHv3Pfshy3R72cedh29HSktiwuIbleGUndqklLdLL73+dPTukU/4Ko6rrmUO59uD7Mw+NTMp479CybYadwL7dVgoe4/fk+NoFq8ZRYPTXD2dhVeDTHQPvuD4wI4bIkvHt0abadX+KAnvXFuz92LFBouIKKxMElAW27FOXMn4fqv0Aavnqfbu3SDvaBqCF2rOVRSslZpuZSBhLYJHKhimbtvkqAiwhfPrK+AOSV4YkVBqBHavEktVQXzYN/CfEZKHmDQg2/9r2/TQA8g7fVWF/zD9FcPYEfPt9OMNt78ZYENmzba7Op5JjFtb3FnLMPlc1Zg8AM5U1MkCafdoVZLmwYEGGmAAuXb9mnGVBzxwY3T8fOyljAtI4HJpr1VIjj0eBWa+Vo3WXTY1ZJSCm0kUnJirMo8wyY4kizSttvU6ArNveFwqdPjoQ4xyzzqQ1IMbyRbScM6P5fhwH75e7Ow4e7BZMsozE7ySM5Mo45IvMqNlU/h2IIdMV2IvnEkdGNj5c9EXhaq7J6LF4/Af4QpJFa6nYs8WTMdPGpQ0m0BZSopNstaBciDszK51MYn8ZaNXAlu2dGGOMNJ+BOtwZIWtZDUBUtuj0HZbNHdXJMKLnlBntbqznAurM88Ls3HNm2TwKkqHVD+cw+2BGywjQ9XqsVmvWt1M5FU4Apq3Yesonc+bIuqSSc9eoHS6awJF+ZkZ1bdZvoON6scG+GV0JEJUMBL6T9NV8MQlh634+/gr6zFimGQOjQ4xbYx/J+3/uU+ubGNUD8vfmOEOSWm19/wt10p2kjE46OY9siVlee3YiY7QL0AVcG39kf19oIKYGA32Fb1dej1mCmt4UbQVkLp8Tk5RCqkFrbvSlROKJiZzb7dyJsQggMyRu9n5uEh7AVzHamDowItJ8ULasrNM+zRwzw/fB7Yfg5aur0UfGlN2aRvk2QdgAbrEGzUJNGQO03AxkDZi2jStjXluWWeYX0k+UDTizhTFzMftnMOZDtjgN/jGSytjS47y2DOnAhqfvOzjzTwWc3Rmz8esRuaI9OBQ0RrjeM2afUcZs9zkz9RiW92bWgY1LAHVg4RgkMeumjJ18N4A9coZktozr3LCztQ9Mj9SJyfJ2YnNvCvTUBl9YMGbNwmuTQIKki/dhjenKCMkuqxIqPcCUu3fZYZc8VmLAynEc9dWrVyNgun3m2rUOvlQqWZi9U2DmdO+qiBnMTCCFX1zPYSa1X83t/wZjlqn9mHCC1Jvdr/moFAzgUO9nVQEaXaYMyHYuJQw8erB0R559R2uNNWUHRNroecHcsBasdBAqjeL6jjZYbDUiG8agzANzdSA27/6dSpzY3F8jWSM2eWZRgBa3agtvdDf/6IYUk5qtA9SMvRmAy+J6SDbX66dqcjzudVEe3RUrj0+yVLAGRYkLNcsW/TZGHCzEaBt9p0o1wNicTUuUmdhTm9kJxA9/XjKdMRwBCAHDt+NcWzusW8hP18lZVxbdO9XZY8DPagScbZZIJlQLj+E5yTODPNEVTLr8cI1OB11PNSmzEObYKlCt1ZjdfGrnRpbZMfs7XeLG1TFWALzC4hJk66DOmZ3Gzkk+s4TXZdlp/iVuMDzBZygXcguRnc7whPLCBuXsdgiTGXtqXchbmQwZM2bWdqS/Pt1W1/ri58aPWmu2NCdjzgozZEYAnFEeyxoTdix1Y/zUGLPvQ7UfhHX5YgdbxJL5jUw+qOasTw/AzRZmrRuBIMAcBmjqyFgaoCpDH1E2wGxKGVdAxmzZapevDozqxohmkd/ZsGidP+GmB4BmsGb3sa8tA8kc75WmkS1DsAQxHv78rgr8sfopMGfTlbE7z6gkIou2Zx2BsYTk81dj9q7/E7C0AKYMiCUgzZltGv0eMgvh4OhkXQtrJo6Kah7iiRQx+x5b5ENqwaCgLTP7SGrAsnkM2kabEkniaHuvP2MWLKkrgxiNjJwxZtY0t6wzbWTyMRiv/plkjE5sGJrFfm3vQcuGzDNuW68zC3JMlROKQVyQGgkoqr4Y0wWWzVwUfjV29xi7VEjotOdjRruxpPWziR5LF8gBSEj6DVZ0VcCWx1oxtuobAMwTidlO47bKLG2BQ5llicteeHKqfBjkO5BkloFsKKpY4HMnmlk7xcQWmD6HUzDxVGk4MYo2zB5ATFZ77YYYZiELrSujLfBbGHpcc45aMDIT8XHRutk9nNrLffniwfLTauv/4B7uDHIorIFC64YlfMndGbgByti63vxuHkKRAB3kWO3xCJ2JsnlsGzBlS3t4Z+2auYhHB0/v7h3gEGm55oh98xZNMErSjMjcfu+1eU0PQNbG2azJQbtT5Ki+a+fTKKnF1dwmuDJS9EGHt60mFV6pUw5hy56iSyOk7mjYpb+axiAP1pjthIV+AdqUk2Hb/C8M7my1QZgdTFwIKHc1ZnY+bi0lVzeLoNFsVl2VhNhhzFjKdLAfOKlM8NWJLRCZmam5Lv0l00I+ofogLFqQMUrhHBuuvH27/O8D7Afh9h0DTJ0xZTs2LQCxWwRobjC/oVgEYlUAmQn/dAdKE6D5hnfqdWUrILPBgmXW+Vmo9GTO6sgem0yYD9MPriOblvl17BtCDMB9zkEXszUwBgKaO+7b19fvKrAfqnfm7P/+1oBZtW9HsSLi3QehTRyqRLXPH2P2Lhl9ZMv9xb/4F5/Flp1IHKHMEz+DEnZMpYxBP6HOi7Q+zSDLctF6O2/ufog8EfJ5YbuQ1Jdlhh/0uTCoam0cAKmtTy3xKwGZ0izzS2cxOw3V68jMrPTarnt/pzrLFRPjjw6qnOrUQMzXqCnrZh/dOr/P786MfX5rp27Tj+OoLJ909+GKxwaGjD3S2jJizIbDneSYOWWbDcYMksuMxB7fVyPDMd0TwmzXB2GdZSrFyyzzSYsZ6TAs5h8HMWGVZIzKnlVjxw0JoVZdprJjlgKtaMfhW4gJSirrHb06HpRz3ywIHaNDoxGbOC3164ZdI6Fkr1FlVlZC8qoC7aTAcLlvsbWJi+qt9m1RxhembJK3443BG3w+OQpao489eOXbErA83SFF7wj9Lr0NodVGgxkEkInZ0nFVU8uOvqytAyNZiDSLNb0hWNPvyu8dcn64jWNWB7BOuW3j/ORR1RlrOZhNNzmOhBQGLUPMWTcA6cjSpGDKlH16dR64/ECXKTM6xIkwkeWMji8AeKJKnCjuqoHlMOlkZo1dcxCvhrNDVrTUkxVVgpJBoBHSvN2ip+TNiMwELiwZkm6qyziaZ18gq/wMjC0gTICZgrO3C8x+8d19MWHKUFq5ETNkDNBue4CWGoUYzKKUsQSL/Chn3LsznoVNv76Uka3y7+/LaGWlbDJ+P1taydqk4iZ1ZTUMBEYHxv7+JnVmwFJjRq9AhX23A3/cgV8F4IffCjD7Jt0E9AbLkvZ4Q1x/09Qhep9j9o5JGZ9RX3YmaYSAr3ZvM3ZrXCzkZT4o18zVHbFPVFfGJO8MmfmHgLZl/SKD1PeB7ZL1q5yRpYoj6y1hz1TWyFJGD4HNbXn6rIwZqL7sIDMQZxv8O8aa71mSSDLHLm08GHCR6Ycfx1F7fRsde/YqXNgP86STJvVlSiSlMkYnYGb3oOmDlH8MwpyVgIhlWV4T7KXSRksYs9SNwR8DZ2Ck2Vq92OX7qoRElpK9YfTC8HHdjnxbMi223FKj+1lbBhxN3tghWEkCpjOw5Sn4WnFxlJJ4yFEMJI2JAfCGefBNnzJlcpEg+EdH83zdXjQcyeV1cX3+rGFCG2HL9fERR78Yjcx+IJvj4JYAxt3xT2u+ztq4cVQ8Qzr+jHHXchPP9U7T1OnYd+tmIJVs9GtEGYZmDLI/xlcc1VkG85xexC7fGjCb9WU+Rvk5OHiah9fW0azUeT5nzk7MPzBrx77QJIu3IkYfJGPcGhu2HerALHXb94mhiyX4KjmN2591QMEkfS0ZAEMOxhnoaJ3Zx2+jF25fws1+P6x8FeUm4EvqxnrewCJlPGHQmEVrGWd3+/wi9vkTlJXEobFIzVkGyN5UyqhW+XZqk1+pZVW4Ph9g0xMp4978I0oXLcnJ2AC076zAv+p4+hWO24s3B2bed0QeAA/eIPv1XKc72/sas3dTyujPYMgsW47AE8sZU2ljN7/oQEzBizBtRt/3JMfM1bCDvy82+OOWnDBfDPjAWWYEpNQeH4lF/gCC9LnUWg/6TnH3g5YDZ5V1ZrCDrc6S9eWIFesujFzz1d9Xmu/EiB1ijV/6+poT4wB5nQ3roG1XB9eDqxsTWJiVclX+CW7xiqD/P4sEcyagQHVlBLaCmM4jsRQ6jdKZt6xPu0NuS6B0oFjmipbluNfuK2XX2TAFWy6o1m3Ffqe3r9X1ECEtzJM+7ypnrCHrTO30Z8B0lVQ0u2QX4+vOINNrjUJNI3d4Jykfh+ch+lN4iD7wluM191F9rSoFVEc3i/t5KeM0TUOKYY5hCEycibR38SUcxh09o2s+3J1s8I22yetnrN1NP8zFEbJLEX1Wjblkg/E2gtGIMGtT1NiNNOaIbZdOYgzAYRqf9H3vcSu+AWgNwBml143Q654DR+fP6PcVTDd72zrQNx/rjTo5ljKyXk6zC5UxKfL+1eVQtJ3KG2Pnr1DX8EaSLRZi3VmqJ+ry3kTGuNb7eJNt9arQIwiOH/D/bw3uUsr+N+rCmC2j32xhnEM5yLir6UaUmJqcBJt834Cykg9alMzUaaknwww8C5iU6L1xAVtiAnKLiO/Ne5PfCccfhpevTXt7AlevI2XswdNFTEHMwnfu9vm5O2O00FcgVjaujDspo22t8lXKqO/vy9dtuDSHSM/6MmstRBtKnHx0HiC9M/uAyBtBdyB+wo4n4S85UP4dwH4LgA/eCJh97I4bae+1o5T9bsczkX4I3Qn6U2Ck3jYwq+8ZMz97rwYd7MpoFJ68ADuRObJLo4v5hy7rmlMmtWnKYHkiQXRpn+3YtBMHxstpCsxEuljIIKOyW2PPIwNZ4gNgsHV0wEXLsxGHqxNjB3CUPeYiRez1ZR2MdaYs1J61dXWpY5AxAuiAz/m81AwX1IRMYqDU8MzoSKqJX2L+4XteKvNH3Jra190zdBkk3i3pG+kPo8/c13AwZgexZgc2FpOWMy0MNqqfSs4zv5Mzri8Cs2jr4UGwGKWM7MQYhY+etkA5O2trCUd/uVdlR30tZuRDZh4ZKV/cIOdJbyMpMe/M48YrS+cMwYgCvsppx5qy8+hxH2yK8LAYjLRtMvEU6jiXZWO7Q53hGOOqW3KKoJGcralPjEHcs0HBxHe0mfItzwZvJLKBLf85W27HeHpoGzORXEd4o+Ill55+naDM1AhEa87Ype9F6E6cO8rPTqAPY3HuzkK6uRgyLJb8PbWpTlAmethx/tJ8f1C6UwdqB1a7IG24GfDkzRWyM2UdkIHYMRNikerKBjgr06PidiM1KcgsUVkyj0ANgqX0d2UZc6CgbDgv8jLCILKkNQPp/e/VG3TO7vVuvwe1/KoUdAXw1aWMtwekjBRAvQA3C+u92+eb5JvZImX0E/v8KGFUBu3RgGmtL8NJiLQTCGMDEA+DGJbUlk1JIys19tJFS5iyCMwWgPZrK+yfd5R/+o2A2SdCB4cHnNxE2S3fRP1h9qkxZu860PvJBswWkCbMVVZXNuzjsa8NCyIfMsdwAXDdZt5ovWemHmypr/b6ocZM6ssCkNuBtc74neSTOdeSiUNjYMX6MZrRZMMEhGu4+ufOXFVxZhwyR5Y3aj0Y1ZiBcstATBtLJhcXRq6Do2M0ATHfK3ZoaFPExFJGU0zDwKxI7rIl0V9IjAxp/mQXNoST7YbxLQlc29VGaRZAYj1ZaYSVacBqMQeAqYB6gizrKghkdi+PFp71YhvCkpiyKGms9ODE4NUmuqynNWSRWVPuzqjNtdZA/JCKWaRypknG4ZyxfUU396gbJq6S//zMU9vD3cFAeQR8JrI/9xVTQ1g/Y4rPGkx1ogGBod/t2w3GIcngwrT3V5MdclMgMw4gxogZeyYGa36bph6urAuGy6OHaAcPB9xMQJe4UPbrwU96AZZtg82HjBhU3rkQNuwxaLgQY1Yo48w4LP6YerzRmf8EGl4+u/eF0p1KMFSwYOJdiCGbLBkGILMGygzePjmJHyNrNmWOlRiA2wBrXaI8Qdqho9VtR25Aq2i7uy7e2iV505wyBWSIrvOBaCSsUPA8h8qrurNF3JAuaHmN2RIiXc4Z07cBzAr+YVj5xy+ZMduYeyxM2SZouu5qzrgaK0oaLbXQz+zzo0tjbddxBGQmUsZoANIDpvuV7ImUMYopK0Vf1xAwnRl+cB2ZXkUVbPbBYC2CMGHGzoAZHPidjvJXAPs334AxW40/PQ5SpSMTi3bdxwPgrQKfH/7hHw7rews5Zm9VyvguGX1kyz0IzE5rzbiejGtAtPaL82241iwBZmDZowAvT2SY2AReg4BbAHH6PZmWyRXBoK0Dw+6CyLI+YcwYlNVdsPTOPp9cFbucceSa9XPH2WVSF9ZryI7u5kiyxA7ImIUbksgeLq1mH622rLsx+ob+mIyZP04qjcFsrTsDgTSWNR4zx4x8FoITY7WVLBgyxooQ+3WpABReZfqO72R5NWovDdP/n3fMXTSZBMCEaVhQZXYGFlOM1egiAjQkIsasKsxG6CfXoMWH00GiRn4sOdhS/Ty7zJa2jLXUKZI0I7aF1IbWr8Aul+NM2EbF1m4H3002nDPG5sqMHB8NbSC5d/6DVNIo84wz0ppaqLFE04aepHycLGfzOqtO5vgeawKHDf6QPUocgE9Wa/x/ANDmXFnvYGkQfc3l0KmbUo2gEYMlbx0jM5KHdit+J8/GmTHgVc4tOzZXTGt9vpf3Npn0qAPmpmNobVRiSB1t5tAJPg965lHU5FPOCDIAMXk/nBoR0Ucz1L6vt2/oBdhk28d4/S0wY2id312NSxF3uwkBmDVj641pAALqwmLIyWxMr8Rk1NYyh+PVAGho7xtLBuALzJQ5SRfbMe7vGYyF2jJIBBgZgXRXxoK1XuwUoFnCoqnENwNigR1zLIYfCyMqYMw2QQfHa9MNPwcof2AwYrVxorsas/CqeWVqk3+7MP/gjLMbSjHc5BryNOMsC5qOgdMzYHoFZFPKmBuA2Ka2rG7qywrJGQs5M97GkNNjtWUQWWb2+aS2LKgN2+/vCcC/UWF/DrC//NrArDB1raMOu06NjNK5fTrmH++ljG/2T9gjKHOlgIdlgvKewZQlcsbSC8oyKSNiNhmE8eIaNbsAYqe5ZGw8koRUd/CExmb1mrDxnow/TC3iVcrIDo3kzsgZZIFVo7yy4fRIrJkRUwVh0IbrYmfD2vub1JkNi/xuf+/u3QykunvpwKvXl7m7dTaNgGJvF+9XqPOrGeNkp2TJUPyZ1pPVSTaxd0Ylw0IgD5NmcqNi7w7nZ3y8n1B97ok4sFIHkqaF5GzekbrKFY8MqHmkBSHzzXN6RmgFIyGaXShNJ1GpXopTxniQWNE2zJjTY9jTqrWzmjOVMrqcu1ij5Doi6Ht4auJcGAFtYnZ0RN7RR51YDZRIGwJq7owWJHguF2Go6QuFUSI3ZK1WjTI+iZUMvVBX6R9tx1stWm2gn9PlJvm10t0ql2SsVRdp4SzwG1CeXSv5xqDuDC1PzioWJnUd83EYZ7f5IoIMDJoHcrCQTBGrrLFrrPkHtnxOXPpGd/PlkBRiVIkxxOJ6FjUdiEKpDsRuoZqMgVmBGoAgGHyUYPah8rHb+D1be3//e9X+Cu5ui18w2ja9Z6zDqk/NaWYPDRN3k86YcTSA2bULo1E/ld/jpKsaLfE9MmbBjTwJ6g21Z1i5vZevLWH8g/fRJgZmze3KbAmGXqzvF83ojm2TerNRdxbZtLsRCDNlhZiwWGv2OkHTZfte2TJsAdmEi9EinxkzZsvq8rsD8gDpXf3Y5Lszxszp11yESbsDUfu3HPYLXgcS3YGZieEH6XkXiYbUlvH0T4Mx+wys7zMlZXxdtgyzvmsAHQV0O9OOjDGTZYO9fQM7rZ/mXQLYwVRNZIqFlu1tpVXP2q8OyEhqyOtY7PEZzG2kjKA/ljJ2R0Pr78kuP2PIhpwQsw6NGTOo1LCZdZSktmxIGfu2GdC15fk7at+fbTdwNpVGJz0vKVqwjteuY52gjKWMLs6MrPALJVhOTJrPsquxKVuNDU0Lwx1rwLRTz8IvdJlOtSmDYaNaFa/TPr8Wki0i9/1XKeMZlmF9WUDHHKXsK1hdxZdJbhkEnM05Rxt7zzwdJwtTAyCMDF5G/UkNGpl/TCljzfG0YSlaCtlgNRI3Z8ypoTuJ+WqsCHaFNJxlPoXtuzxLjZi3NgZlFmupgjuyYUowSY5oBMaWyzrkCbIziq/7u8gNsUbkZcdET59J2OByNJhFW7d3L4Mwwqsuwwx0zTSjxBD3B/5Q6fduqNa6UKydMzb/YNmiNUdGqTczz63Uu5NF8FPsY/aQ6V3aqIAsCh5NOntaY7ZjyyCgDNJxZvfGSiYNPkDaNPgwb1vxaGdvmKYdHAemNWYQR0aTvOYuZexZaAGzubhTEpum3epsbLAst0aPoMuyWChqvOtO9HNMIIdbfLxWD/R/Ays/JzBdnSXrdWF2S+SKdsKiscTxJjlmVG9WS9y3tu1yK8JTTV9QJ+EgAhN7DcoqON8sgjG1y58yRrXNn1duXRiz/t7IkgRBKtxh2/GQC2POju0kjHyf4ifb7f75awfsXwXsdzwbmH0ThiJBqiNjUhQzKuvXrsunBMze15i9fWC2BWM7uSLb3ieMWpAzkhNjBzdVzD8W+WJiZ8/zWDK5kzsOF0QGbZ3lEzYtZKVlmWe0XSeWjOvJXGrMVMrYmTAGdiFwGkBnuPp2CtWYBTdHDpLmeW3acRxHB3f8vrNpB7FpnT2zkEs2HTG7PFTBbH9/399CSj3VQCNSWCaSxS5THPglsc3vVvdjErNndsdAGgUW8EvC6FsW/bWANSMc4OsOBE1mgqycHU7ad2uNQWzDMt+k5iwLntbhYAsyvvygr7dQlyoeZiXqA6+UNDa6czVklEURpKeJaRB5IzNZDdZVj3JD6njP+JZWvF0jm3n/ChdFhcKkCWycQpwHeBK/RpOY7krHXh7Hg7FaUBmBmwG2ars0DFlmgxlImucLeLoDqulAqFflLGwnQBRq5xqzZdawlNb0ESLsPyxyHOmApx8/azLFXFQzeduwXwRGB5uHiJ6Nr5IR1G0jkmDWCBo936oAd7qGhg2gsmYeA7QgI06abzbon2OROCqsMuokqieckfyLeTVmyWZg7qwzY6bMQn3ZaqF/35NCvzY2F59HrAxhcutQ9uDoMgFYYLQoDoyZsSy7jDEAI8xyW2vLuPxvMHEZ0eUrybUEUCOh1xYgJp+BGD7dz3nJwg3ajrx6dm/21wPlH93WkmXmHyxL9JMasyu3xtNQamsujWdSxpLa5tfBKmmNmV3Y5fvCmlXhfSNzZiEC2wJ7ZkllWTT6yNmzrMZsBWH7GjOMp2JJnm4O/PYK++OA/YnnMWbVUfiqpzqPHQAzz9U0n4b5x9e+9rWwvreQY/Z5tcs/Y8NYqheADaZDo1HHHAS6mE1jkFNpfQsoZGljUg+mEkjf1Ix1pmwBXyQ3VAmkujIyg+aZAyO9hu+KMYhtsstYijncEPv7LiHEdGg0CqQecsW+/pZd1s07rNvhdzDXZYsdFLbvdsljCKbuckUAXdbY96OI/BIiMbUFN5zY/3GpVlZfpvVnHcvUMsEYG3xwuRYzdp453WPDlPhCl+RfBk4yzfQ9OZpUBmvsNEcADWIKAnExYYAWdg6XkkBsxGkqNlRw1pdaQVmHWB5kjPy+LhHWNZhzZy4xaiBRvSYaVJU2enoifcnD8vQcuo44eiKek3DjYFm/kdudWAYmysuzfaDvaCBz0rZchBiPxSIT9KTGb2nkqhGNx9hPJcL5s8bDJRyNTDw7IouT5f5awHKcZqeliOMiYg1cv0F190Yj63xrAixDdD8bpiBcpW8JU5aHPJcgYHSCcZp5NlkzD66MloIxEIPBHc8oLcvsFJxG/CcYy3LXmHgKSkFbSSj21RiMGbs6elQaopzIGHcybjtRdy8qNjX6gHzenMOOOp2A2/MYsy+i2P/2EpSlEsasxux2XmO2rUHLAJrBSmnB01mt2d6VcQI1UI2ZLYBsrTGL4dImsek1aYEtjow2hiluD9aV5QzZKinefeKho/4buwlQk9/b/85hPwt3p6AHgVkboeBngO14KicpI6Z6oP9gPo81Zu+S0Ue23J/+03/6UWCmYGwBS8jrzxT4ZIAqnSeSxi5dTCWQ7HLY69KI9SosWSRZ48HL0ntn2WGXNDZwxK/eJYcsVWwgrbAlfs8mwwypHutv6wjL+r34q0sbvW2vEgs2WCqpKxs5Zl2qSBJEZwasuzCSI6PLeoZlfjf70PUIGB946Nj1hjbyO08yzTwzN6xTBVilvmyR4NlqcOh+bhS55eSDZm2HND2FMSFA2ZMMgFpjQjZrMQfyNAmXtqnTVAbNH9mhxew83Zto/MhQatac1QDU4r5xXZnL59hxzuhJXw5/CJhOTxBwki4MSd5als9IrXWo/USieLrt69mnmhB/QAqYyTkRZZM+cszEuRFXhy05zhwQ99CuMtN4cRaW3bPckfHRg2u7cOxe1OSJXs6TmjNiykPOWX/fXYWMWL6QZEz7uXb+ovsiQp1MfI+w3JQyzqozl5qnKGcsAsoiA1ADa25L3lTHr8OBEYkLoyVM2c5Hg8ifW4ns241Ph+nRlAg66nOqIQgyIcHiwuirfLEIBAzSR/GPHEHPz3RlNPungPLTJ0DiVO4LV8bLP7tm0nzj2NgBms9ss7XWTAHaZGPPrPPP7fJjuPQqZawjx2wNlTayx3eUxjXXbU2Zui4qQ8YGJjvGLDJjCNMjGLX4+WdU2G932P/sYWD2oc+Ae76/MCum7ozO7H539J0Pgfc1Zu++lDGArUS+GEARYt1YkAGyXHGMgJqxkYe5+9iGmQW7fJYuJkYhyoxp+9gUxGV5ZyCWMGepM+NFbtm23kwAHIT1UtYMtdYOGrsTIog1q219IGki2+uPdZBU0dhAhECYcYbZq1evDqo700y1LmEMwKzLQTtYBZlhXXaZfNaVqbP8cJffSBmrzbIsxipVLPGdw4XpgeykdktNjbJGm9IDF24mC6oU8w9rNWbVYkHcAGIK1DCTtD2OeK1MnyUaUk+xcsZX5ZlwTnvkYS9njRlzaLz/kG/sECTXqU3rENsAs7Okg8ey6X4C/lnMHPtWbvfTsLd6/UN6fiCes94UOz66tsGYIUoXs5ozdmm0SuYgVBQ3Ppt0KyyMsBuxCWs2EgJYU67mRkzZbO7qDKjW+Wpo4MGx0Sh6l7OmfHSaB1NHwdEDRDHG6dMyZ/kSMQ3HgZVWBnXLgFck1sLv/5RBczLJPGPOMqZsC8zESlJbaM+qMfteFPsXT6WLS7A0uTQy2NqGT99Ocs2k5sw5fHqakJjF4GmuLXO5ltQ23xcLfVxIGdmZ0UOWWTfyiAYfXFN233JnzJ7akylGS9/ryu7CYzvNKcu8FtXoozNjJqwYxqCJLT0Fig74fQ77IwD+6kPA7JMx8vOAKkZrhP0zCaQ+V8DsESnjzpa+AakF+PB3yCI/GHnUWs3MmJGqUsu1fK/XWmXtfMACf2H3eFt93bp9/f7ZtN0fgb4A7joo1mU6K0YgDQLMBpAkMFYI0IGmOdnrO8kZ3d0P2u8h3ezgj7PcuqzRfVsxZnxd1Fvs7avCzpUVo0EeYwbNV8Bm7BrPBiCJrJGXy8qzTLGN0keL0Z0iN13e94DNiBL0Siwa7VDdNJytvQOaOrNhdDx24z6NlQvrj5ViSGzzVwhniSujukLueEwPDJ9K7HzU4niSRefpIZmSj3DU0kPoUofGIQOWXCjxa6ZLS5RBJaN8HsZfmiKDCbrkGAkRHM6B0GEHNiMQdyv/eCmLQ70IckzOkw+XR54WoYYeYY/1P9KBdjrP8AnQZwTC/IJjGgiB690t7n/aQQ+0Dw8hszkEs2I0vt/NQULtIjMvehwyawHQ1cBAzRczEK5UY5ByA0Z31xcgaKGWbAVnwGrYMA9DJjmz5P3CmiECtYB5Co0fiZlhB3nFyXYfdHq0rix7GLEnS2ZKl9WaQZk0QpvASvmFATDJOPPyqCtjgdnvxVMpC8VYGihqcsJYW0bujB1g+W1KGM9qyYzcF5klKwLIRmi1Ua3ZjUBWWYCY5pqdSRlLEjTN9WVXUsbSdBhlkTRWiZmY74/kd8AMtsuv0lPmLMK0GAxjgQXEqK3TZyZ4sOPJYb/HYf/9R4bOnj7yXBEwi3OTPLNdv+XTyTELW3kLOWbvGbMEmO3mJ4HOZ+DIlHFLllfHRk+YMFeTEg6e5to02fayTWHEQjA1m4WQg6JLPIARqHLNMaPjawLQvJtwkJlGJRBkxKwNySDb4Lf13xpg4qBqELjqNWfDiXFjrc8ujRX3ujKWNA62TM6NkyRzPM+r571/l3oyJ8zCpoXBhVH9M7opCNWYLVbvtgmWpuk8kprWzKbsgscnvwuwCEFrNTozeuLWWBMnE2bNAl2VJWhX2pErDMaxyty9942cMdp2VGiGWbTRP4Z4pblNtqVq8HaLVWx+4QOp0K/We0bUHQA0cBMwK+V9OSKqYFcIisOeN8PZe/PWezewEYWPbTOa8Jbd1cGQwUZ5oKlcNMj9nXwyJy9hhM0VD3TAN/LQGCo5tdsZ+HjLA/ORN2YM6zpS8XoPqJ4yh5Etxs/8iGYjMBsGHAFNzu2uHGePWWitaseW7aY5Fa3XkRn/duV36E2uOTNZJowP2InRZ+8EF84xAwVLYyYoG/3QTAZeGMiNwRSuklv5sNX9Lb6PEkcPNWWFKspKYp4PsUpYJY0lgLNYA2NDfAzKn1okhJRdZhuQBjUBKXGaEn2F68wyuWIDdmwGol3OwiIH26ghQq0gQbwFRWZsmQAxCCX4uCvjb8bNfnNqgV+TAOnUIj/Rje5qzcpJrlndWOtr8LSVwZSt4dN5rtnrShmruDDaYj8yKyEL2ZFM5mzCNLbInz7BNpgu/n8NSWTxXUW0xC9JkDR/LsuzdWXPDPjvOuzfBvB/vAZmYfMXA7GnRRtjhOZdZ7g+V+YfjwCzjXxRp9kGREFYrp4J5grGkjo129WwEbPVpZOZo2IhX/xeo8X1XAflpDHI4GXqxoUxzG/TeZ84fLpSzVkw/6DtGlnhd3fEe73WcYAll72OrIMhYs3AjBq9Z2ki15g517RxXRmxec6W+X0Zmeczos5Ht3fnheEJRdOxxsKWqSKQpYxYc5m1giutmaJO5lLyZids2SnHhFT4N3vY1HBGnpbkmLFtfsgvq1JTRu8rMkrl5Ca3VuucWeQrWKsEqRi03UUhdYx3GlWjVapKw4Xpx/5+xTlmBMP4+rIYCxD4Gnfqj/vKBrHjTBWxyMbwYswzJ9HXZGItYdWc6FufFoLhaARHRxfzLQpzjqt3YeNm22LzNWesL1wjHOr3szoBUwx3xhp9MMCnb56qWQIZsWcWp8/XGkD5BNzZb7a2WjqIt6dF05TuIHm7zQKmTtN0IFYIqA0pI8Q2n8FZ7/JUqVvCIl7cAbCVIbNFxmckX4x2+RHtrJb5FgCayzx+tYUNIGBGBGMh9iuAMTX4wGqPb2XRaM6870S+uEAhjxlnBTEjOlwXRW+L1Dil9VyljSWXMnZmyVRg+RAw+wLMftelhDGrOwugjI0/bteOjj27zAm4ZSDNiD3DrdWaRYfGFaBxRSSCpNG2UkYTMIZQX7aGSM/astWV8dzwQ4dEtMYTdN0XrBb4vgxk2KLwEMFQAG5n4MyB3+2wH8LFlfP0kY4k2wWMsc3A2ByX/VyZf7xLRh/ZcjspowIsrGYezFhlhh2egDdPMsY6AAs+01lYdRYeLbLDDBwuUkLMrDUOvWZJpYsDpEvtmYujoisr1kFZPzbiwtilipXkiK52+Y01q8y6UZ1YB2YH56KxsyJb5tN6BlAjeSO3O4BKtd/vwFVkjWkM8/ZekZAivV+65J8JSDMinjrRFOCQxb6zAg3D6jRvyA3z9gVKu4U9VtiF96LfZPTZAVeaSebiyOjJ/ZWDsB4BlWvHdz1FLg8PtenwDbxaPR1d8s4M0fTDwrwod9TjXr3eWZlN2HCoeW5Tj0UyWe4Pc3EYrkue1n1lhmnD3lUiJtli7sTMMDvlbDXiSx2UkX6P78PWnsyjbGljmLECoxkdUJnicpbTrec++mL0Xm2NZQluDXSr/f7swrOkhpTn59clbTyWQGSmLHysHOxYONg0MEHqIc/MNU/NOhhkS3RqYCGKn6k6Q2TLOhCD0pxVXhFkUxBft8ilMXvGXomWApUyukMlBWAIAA0PvG5H9gMQ6kaWGWOGJFjaLSnnKudSxhvl6WrQNM6MPdohKSrNXTSPiRbSLNEUI2fNQsEcVcddm3/8JtzKzwluKaUbcdgqYbQdSCPGrFyYfFjCwu2MQbJaszavmOaaxaDpaf5RAsh5rpTRwJll0/SjpBLGKWW8EVumYRSHCGB9Mf+414vVhQXLLfHFzGP5HH47IaOQ6+oMBfj5B+zXX7FmTx/Js/8SVV0zaO9rzD4DjNkzmbMAxDbr6wDsEACm29AaM2XPPAmfVpOQbrRxKCAjeeKuboyBl8oXNZtMl2PpIkiOmMkcPas3Y2DG4JXNSQhYoTk3cnB0ZbfGmQtde61YOY6DpYyB+eqySmLGKkMAcX7Umt0pZTy7B5CVopN0sdYN5UXLuZh/HNjnap3wWOkNMx1gMpz4/gNL8ZtaTJoETjubgHTGzCizDFHCuEgZfbWchK/azQsCynJYKQDLyHFxfl7jow1Hex+NO2pzaVwdGnnnfAMUPTk7flTUZCdm2LSsxVhu2ImnYygX95nQCiosoLgKJAaFRvlnLvUHPsHf1BlS9rIJWGhHa2R0LQKUthqVoq7Ih/NFXd27sOaog8Fj4sRovV3O0h4aP27yR664cELMsT1AtIP3ZT/nybcBtCLAbWlEradfnc+Bx4EitxUgO+vimCUTxkxdG4N0ka3zGagpUihBFhWZR0u6kBB3RoT6M7XLB3k0ukA3Bmseas8UrPlGTGyBMQvyRWXJkmlBzigmhhAjkHIT7xWbAHCpOWPmDLJ9KFCnAQhLWLOl1kyRY8KWITEG8bZjr057zDcU/DPRwrIAh9paZiDsxDa/s2yhxuy2D55mhm1nDOIlAjQrsFsZHFhJgqbrImlcg6YfkTJON8YO1NYwh0IJfEWSAbvJh9ZYWsKT7QKkM0OPvh83mRefpRkrptEU8dVgvxvAKWv29KE6LvrJILJvas7iSNi7nmP2eQdmGi5tauyxeT+MIkjaiKROrAA4EiOOyAG0XC4yCMky1DrT5lIr5pvaN1d5IrFkHTSaSCUZgFUk9WbEijGAc2LNWEJpBJYKyScruybSOirJGsFW9iInrMRwucgaRyYZuykmy6gdvsv1obVkru0dy5wN0tD9wkX9Eww/Epv8IWV0scLHao+vAdNp9ZJtchdtp7JjuiQBZ3obrixdpB3zYzoz1rIJlMbqzMh2+TztmQpsxiF7X8kqMiaVLzpVjzEwqzJ1BWfXfznQqDzwY4Hcubc11HXdL4gJBKyd7y6ME06OWLEV2cwY0kqMiC1ZXTZoXTu99G0rN+kALrJEkEKvvQshW/5z6HLtLJhnwQTRxt4totY7gTiPQzw8BlKzj+0OFlS+xkHV1hjGPrhgwTIkUShytnVVWJmA7KTu3dpPLeTClwSYBfBlIl+U94Epc2mkQykZI0Cw82mMVUtGAjkje/AoXsTIMWO2LMIY3+SbeWoUon6qHn0mbZNVlsgZszItNTPsMWDhdCDJgHaZT5b4wauFwaMj1F+GHyRnQA2tpbJjSMAYMU6DEiSw9Oo0OuMfAG5/3wKwLq3xiRlzk3BpNQSREOoqro2+C6G+YVhk1o2lfomSRpNaszVoOpMy2saV0ZdXW+SMHlwZSwNlGibdGbP5moVG5/b4q3QxZ5P3DJkt2WxZmqfM+/kH8BsA/DunjBnXOmePTJO7/NSgpYPm7xmzd+jfznHxhCVb3AuZaSIXRmyMPUJtFX3ubJYLa2Zq9HECwExYsgLgaO6RpbkQ9nM8wFNHfx2QUV1akCv2Y9DZJwFnIcCapIu6XmXJxva4dqwzexwbwI6L4trY59fjOHi6H8fRwSdnkjGAMwFpvaaN69eczq8lzCifowWThVB6Kb8KRgdZp9hz3MPqP3ZgRMaOec51hT4vTspgkO3MjkETPVbPApAaoOU12EqCgtcQU7R1/Z7U/z5DLG7yRSenPwQuhCVr0QSEO8ZOZ8AT38Y4LTJjhrxmiT8f9RBzDz4l91q9wAo1MGeNv7PazSlsyXXxagOoxw5+HXLACq6dqouchV0GK0krOXd4eaCGIX2uCWsza3Kxgo0t+FiZhFVXeG1HrLGzlbNFLabajfqtSnSeAdVNrFJmQ6Y7b6sBa3eAXgc2A+TbZ96mY2TxdMMOX8R/7RxaPwcOq0ZmKzzSKF/21bGzU/ox462sPfvgNEFdMDX/GPPrOtxhWCS7KlkEYj7S2gVh6aIRW4ABqScwM3C6GVsjcN1YJl9UhgxJ0LyP8Ot5DRUhmZQ5U2xjSSZzAGe3e4oIg64bJlvGbowsSCsl3nYXyaOthMEaIo5YmGY6QKNAjZ0bpR4LpwHTTzD7Z6McsghjtpEq2nMMQZLPmaFIrzMbxiBduqgMWlyP3aIzo4dMs52Ucb4vOLfK1/qyil7NhiZXZFfGQpVuIJhmwkJnIdJYZI2+NfTQejFLUk13rFiUbvKgRo0yx3/WgR/AprTq6YONw2J4eHo+HLspMXkPzN5RxszjibTMAj8BbsyS7Wq9tDasf88ae5bVpnWAETLOxA0QxGDptkCMmAsoGuxdNwBpr1o3xmYfAZidyRqljoylizzfhLkyBmwsQ8Q0BDGuU3N3a0BrMIwEqPo6CzFvI1ONzD8qZayNeySbkZBUkg98d2o0UQwWpOhMAs46oSQKQM/0iOSTEQKmbVksBiLb6jJfHzUwfBDObJGnk9Xk0Goe4tLY3AtrWWm/zgZUbJwZBai55S7oJ4xZbouvYkMXVWmXM87RvoN4MUOuR70vfYAzzirJGY1q0WyxG4n3q2gAn/ir2zSsmNbp3kBXXUfI22XfnQ67wYXTc2zWL02Gx7FheMjFsdd8+ahxSrz868r0DNOSDtDcqA+ZOfwRSCF2zZnV4+9m23GRIXqTh9o0H7HFmKOBqQFeazsdNs1ZQurA/UfvlpiJeSWrMY+doOB82Z0p23FZlDlUN9a530aRWYgvIGuYbpfPrBlbDi7sGBKHRiMJ48pJckWcA9JBjPJGWyBWlDOyRf6c5lDzj2mFcG4GkksblUnwhfsL9vgbcIYTSSM2n0tZ88oKyxn5mJhY6G+kzqlvTwbSgjtj4sSIjUNjb6mRXf6+xuy/jVv5OShGMkGpEcucFtP6sSuZ4yMyyDJt+ZF8j6cLSLNSxCa/pDVmuZyR6846eHECND4+FzL56IHNlWrLus7gNtQQtuFb43WNAK4yABaBWHkNYKZlE7v6szIfBz/fYb8RwB/NpYykpFmlCMkIxGbQliRLnytg9i4ZfWTL/cAP/MAOmJ0xX48wbEgcGlXGyGxLkDNq/ZhkmF3VmC3bJ8CYgUgGUcxwIVtOp0sWWSZPrLSsZfO4Hk3DoOn7XBMGmmcNePV6NG+ADSyHlHaBmDVuX6X6scJSSVmH1hQG2WO1hFByGaWm8HkTNixAvUwVWGNZVobnHol+VknjY6As2wqo8WKLz2FslWrL+rxau7t83KnDVzljcNwgkDYO0mOZk5vTsxyf1dVy1pyxfX4d/FE8E+zKyF36HHz5YOg2DlKoRx3Mydj9VnRkwlgOS3lyrxywzi0AmTuYqHCPlvUdjI3lJ4l07xKYR2liAwqDOeuSvm5TT3aLA08OW3pGgvdpRpHtVcLFpjU92dLjzjyh1iiPNAKb/XNgo1hBgXnczOHVSRYZAY3jfj7uTatd69mcMTHBbhs4sEmBtXo8YZAaSK6tY2EEBjpD6ExcWW3r7uAzrivsbwWq1Sga9XY9DeMFAlxq/bfMU8asg7IyGU5yibTBNuW1K7F2bHVrZAmhGoBwjtn92zeq0JksBndK7VTWiBOJo9SQuYAzySoLEsYiBodqm3+bff/gB2JTvmgUbF0YeGUAjQwWgXiqopSxSIdWs8kS0MZyRw2W7sDssN0N+B+DGXDQAegH56A9V4DU5x08/3ZSj5a4NAZWTJap6soo3+1mIOQUac0IpDZxLSeIFao12wVN50YY84rkYOkp4XX6rZQhY7xBHRfXAGlbfm8AlqoyBm0r5509xUASzV1dWSZpjHV24fv/6BaYfWPHiCWft+5m8TfwtnPMwvre55i9OWN2Arh2bosZyAo1ZiJD7OxTTRi0M/DVbepZZqhtV+Dksn4Gaks2GYO4DQAL0zdATf+ZyBLZdt4EmKmhSGkgq5tydEasOzreGKgRq2Vcd0bW+J5Y6oMYsVHDhhkBUMlQhaMFAjCL52MnnU1qypCUZ9VcxjiIKF8t8tXsQ7EdcOKL8Szq7CTMOXVidJHF1bjDVRKxq2zHMwklomU++CDaCU9mMn4PYclMY4dDRy1+RlIfoICrBrmiujUaIGtcH4G83GDMWH3kkWOBUX2TA9ERr+1h66h7K9TyxnZ2KDDd2C1kad0ltFRfxrLIBq7MQNVahRiz6dyIAZQa5OjAzModnHg3GbGkI1nbZXYHZrYkS9eYTTbwyrRC0EG4DraEdJzXVL0DvvvlPJ0n79LEe3uLSOAG2Ktt//j01Fk/ZyGzjH5KxkffB+MYro4GeEs7xkO2Wcj8tAEz72AXbM/f2LvbjTLMjMKlPQnm4rozzTS7YakzQ53StuX3aQvwYqHX3oXRQkrZLUgcNQltmjGYsGKcy8SANVaWqnA3ySnrv8UijosCnFji6DsfjTK9WKDgTE5DsMlXQEbjGJYNvPHpsIxB2+gvQ4NLhMycmu1bKePfi2I/P7BhVYBVsVgvZsn8yt+z83q0wIxFYHX65yeSSao167lmPoSEa61ZrDnjK31nhOH06kmOWa+mrAQEV2BWNwxZfP5pjRmWoPWYW5azYgWQMIzAgm3nq7yx/f0Sh/0sAD+yArMkLmRPi60SRjYC+TSA2Xsp45v92zFMOybMyfosAW11I380lR9KphkyS3w18MBa04YNA+a97oElgyJ7DLJAkiYyOBrgFdNFcsuYZW6LwqYtgdM7INjrvJhp6yCKgSrVhhViyBicOTOVnXmj0GiuYetSSmNDFDrnzKqxjNXuHVK79Wd8FaWYxXioRdIIBWcAMlWcujIqAKsk06oi0N7FFz8Pm+UByMEK33x9HbaTSepaPSRMOgmY3tGADN4MsSZq034SeCHWlcXOeR1OjFjkiytbZkOa6MHkY2UXuxhyhYJqSuIimOvZZU4RLInFhntyTlfBJgjU9evNTW3bfZW9NrBXR6bX/N2aDEp475mRpDYduRgSx0O241EsKTVlXY6Y6AKTQyJaV2bgkly3pQMbLO2pXe0YHlLj5k5R1uk5QWj/UuupICwTILdL/dDjJR3izvohmLVQVluw8vO1p58ZgjArtkzzpaPkCzu2djuiyBGUBbW6MTK7NnPMImTzEJ0bu4MebEdKEIVFB8cTHONi7oGNdBHIXeYn1RfMDztjdkOIN4um/7a63CsgU5XiSsZzLaBJ8ZqiNd2xfbLcYKJW8w+D2e+Cly8FkKN1ZVvWjOZ3kLUDVUP2eIvyx6xubJFIimNjZ8qWcOqZi1bKrDVDY85KiIPGEjZdEjapDkDGjoxsle8LY3avN0MwGdFqssmcAVpdpjb+KmHMP59LFjn8JZMu1gW0LUYoX3bgf+zAb8sZMwFY7vnYserslUL+jACp9zVmkdXyK2ljwphh4+TIDFgAYgLGAoOmUkfJDsvqymxjhe8iewxW91z/pcwa15slOWeXwCz5rMCscO1WX39juqyZl7iAvULbrGIE0gFWcHYkWWKXRlbeNtaMt76NSjVv3cmyf0/dbpeK1cWvgh7swzleneU3OKZjnGp76WLGkoXua+Iub1ckmWd3POQyRkDCpcU+n20muysjA7LMDMTVDKRTD7buNHyzQx4kVLNTXKnSCwLGWMao0yYUqzJl5TCnvJGPfBWVfhWwxqOYtdYc0NjJgKGyb77LJ0J0nFBAZDlL6tL5vuYsnzNyNjuQnSUbQda+lhE8vBEGYsFNRHBbsv95qYKTKYotjHj4wSszZ2qgSCxgYyJPx4L94UO4zunXQtnZ5SOvJdNOvTUZozF7hiQ8ywSgeRBYYQFhWEbXC9l83BYmbWoCTTgn17CwAbqiAUiULpLJi9wOLXt/AsZMLPEH0sKa0bxIGVfB4DIta5MhjwY5FUEsTJlFNiyzxWcrfaedXBmz74HZr7+zZFxXJp8vpzMos5wpqwLedp/9xMFxt85kfrTNL8SQldZBKEudWU2Yo2iXP4cPjSzxGZB1i/w7bMvOvsY97PP6FIBlNWVlYc6WLLIFdFnyuy4y0LH5+40O+y4APx6A2d8xw9G05eHZZ1gfDCagzCPaec+YfWaA2aMgzFm+qJJCljJyQDOSEOjGIC1SyY1sUmWMS82YSuwShkyXtwTI7QDWyA5rIAYMlogd3M0D2eeD2CoGbD0GwIhtG9b0zW2RA6W1/qzIvMrbkH1ydobsyzXWrksXSyZfpPkB/3imxoOofIRYWgKlue+dSBt3NWVVHsA1GWv357p+nLo0JiNVnGtWGygrvcaMdroDtkqmH+4rGANijRl3LIO7YNYLjRIqE+HSCjRMQMcKbrLaswmzeAx0lSjWRRzpxMclg3zEMtyvzW6sUZoJhDyHXAgg7v13844zqa0lnXcQAui1Vog1Ynz8LBWQ2gISVikiBlgY+2ATTM96sPv1U82wNteHXT2HYme0pHpwqouhz6hrYfCCjQY5ViIRykaVpZkwZO5hfVGYSvvCYx1APAeKwHx2src4ldPFC6UQF0lKLj6nF6kxWygY1V5bdHTEGibNAkJmxWIQrS1gJP7dq8qiwHECMgsGHwrCSuDqdm50KsRkW/r+3pFY5xfBNWh9e5AzfVvG206OrDITKGlklLkBZyW5ZZ+O2/B905NTE9iyIlQcIVAngw7fBEwbfjWKfee99owAXmDICIAdGzbsIDnlYhJiF2za7TwHbWHKdt/tLNoEaVbKgGIeDEEsrf1SSWCXw8daM7XJ75VsPjLLtLastBBpC3LdXUoZUlmj+gfvsshWUGkLyMwGjk2Ysppc0xX4uwD8SsD+SABm32w6eutOVUQXu20GHmw+X5JBic9Vjtm7ZPSRLXdll/+IzDGROypLZtSBV5ZskS4y+9UkckMKuGHkMsC1yBP5+xLg3GWODFj9pG4NynzpPJY9nvyZArNMpkhyxXDsyOAD4ugIZddkfQyylLkLEQUCGpd5O6fO6tha3RtyEJbWmVUsGWZGjJnnisfwunI2ebjy86SMG0sRlwYzDXhUogIPov9KRJoHIiNWbU8BuiEGTBOb5nn3hKOdI3xygU6W5Jft/7wJ/LzthInQEQOCVWSeVszZGcG/GW3NgfR3vVoE2paKF12Ow8we0xDpHWj3yPBSx9/D6IGFa4KbxGEEznyJO9YktC5RtCEbZLBTRQuY1YDrOl3DwDyRj1IwWnYM9Og6M7PLsbMU1JMdZFTjsjSS68G8Magm4xFA7rKX1WEijzSLB6BIorF4s3cQViyyYTxfpZBoodQh2tY2jFiR7qsvAdP9mtnlexWqOCtLlpkF2/y1NVhMQWyx17eFMOqHhF3jUxkj9a46QOv4JYRONxqwVMLEapZZJFTa4mdAfFxsDaJe9Y1Z2BrbRq58ZgRqTebnbJ+fuDKa/YP3C3vDiPXP3J5qFzVmGwlj3Tkz2gMgbVdP1g1CLFrqN6bQ/G4E0gcDSnBktETKaIu0j50ZpyujfjuKb28SJl0DC6yREDt2zODAkuG3N/awk1rrWFdWNwz41d89xMN+iwMRmOEpFe3owJuOFy3ZEfQse8+YfQYZsx3oQjTr8GSZxSxkV8PGwEg7/yKDzBi5DJiZ1Kp5Vh8mQJAt8ndGIWdsmiswo+Oc1rFJHRq7MkJAn++AILNkHB9A4dNFWLEuaWQwxxED1cwKh02TjLHXrS1s2QC5yNEOBzqzlJEJJMYyDEhckABLGc+cGP1k9NTf6NeTeRsy7QCynESsN1sK5iCFeSBTEF+ljGyVm6UMp6I6z5U7gS2LgCziQAoglnDpmXM2a8w4XDpCPJdtzjNRNYtL2c9a05HvrRTuUaVfJtUTJ/6H5HJXjXs2TWvLPl3t35ttaSP1e9P172SXKpk8bdEDORAne5XLWDFRQrf5KxZDo03ki+w2ob953rYpZ182YsD1rrJmL2Wh07P26jY6tSxqZPZsXYNLN9CFFY8eqh6NQTwyY5BDg0zaWOiMlMSJvkwV4EgusHmYDRI3J4YeJqct66QujvgL8JKanUIsQ7iAVdpYprQRWynjT4XZrwgFdoewZAdRiN3Y47C8xgwllzl2p8d6BshkWmrDnzBltbFqvgGFWLPNVoAWpYwawBxrzTjLrAbWzIYT47y2q4hZbeOAupMyZmYfoUZD5JeZTDFjywqQyjajK6PtWLW/34GfAuDHBjCr34Y0GyfLAQryI0tVBe+B2WcAmCXgC8Jq7ZY3qedCwoxldWbptgRwLSBKAVzGAAr4shNWzSW/bGGROmjaMGcLS8bLZUyVODhWAWaF3RE7GGJ7/QYgK9W9sXSykCxxAVhtmRvVjvVcs26QMtZJAdxIHCfTqI6adDaCqzsHSnOeWc3VfiasGqv97ITL2hl+eNoZehSMcXKtUH+6o+6rFtMR680qOZW42E0edMP1GqzfJyircacs4wbWGG2TEFkWFk4vxUIyRZUtzi5cHaCtBmlihHTKhiH4PNqQsHgiorRl8GaYyBh3JS24Se467J6d7SUj3EfocUo/2Qo8BshwCzJCd2BbKRVs8LPpUULauwcZPDuV7VkGuJLap6VY/EEIdIa+sM871Rak0s8rhLfgusa8LfYwdUgjw6pKIQs/EEhDYpcPYc0IqRgSJh0poHTpMFp4jyUAd0oanTLNPIA0H8LGQs6LKmnUHLN+9Dk1bJU0Qm4xbAASFIFZZplNQLbklxE2cnJ0Z8YryDZZbUogTTtwzK4FdjUzAeEiOd7JYht+kpmz20oj9p2LjNl/C8W+G4XA007KWKW2rSbOKUWA3ABZnI12lWNGgAuUVzYMQ3bW+jaljlJvZm4oVkbUMwM0HnAom6DpQs+BaJPfhxWmjPHW1lJFyggZ3EAC0OwCmO2s7zNHRgWYdctoIw2YPpEywoDvAez7APzhyZh9yeD+ekNm/tkEUp9bYLZhxbJ5iykIyQ0ViOHE8KM7OXYHRWXESg+Y1uws7O3ylSFLLfwV8G3qz7IMNBMgBrXP3wE3ZroIwIVw6waerNs70/pLrfXgjDMyAHEGfg3hOeWRVXFdVIMSE9arM2l1I4EMDBmxaf14jgin0SllkEXYhYFXFTfGAcIOCpc+yTF7lD2ruQgxgS4XDNniKqC+/uJgYj7TsXv49HAywbozIHqR7fS3riYWQYMBaXrxTKAKojSEzzYgWl5Tth7rA2yXXxMBpEoTV+g8hZTcEnqA1rqqN1Tal543f+zplKAJT9ZjidzPPW+FL5I73zws/eGHaD9D9dHnbssX27k2xh/mZGOjy6RthjSiW+PZr2dRnHrebl/+z/cNP+1wGAFFT8/8em5iOBZiQJZ5DOzCBqDxceTfmiEFZ4ZY56LiQf0WW4GzbX4Ebh2UIRVCuljm89ZXPt3kPFiKZaAZZkJEmZBKC64RTAI6FWZrDRmvd5EpYoODs7LSnUW+FmQakIdKU3fRLOEvpcbM7DdPVgwiVUSUKB4kieTPnZWrxJoVkTseHBqXWe030Na/V55hEFIKsWW3rbW+3WLaWC5pzFmiPozAUsYaotKN5Iy7AOl4lWZ1k3lYdAy8Bh4z9tjVmJ2za+eGNTJA8w86A7P67b6U8rKxx+798huY897nmL1D/wSI2QUrpmHQDGz8pC6NjT8qfVkliFpfxpK8fu34xm1R1+HCzhlizdmSY5Y5OirzlgE4kRZe1ZUFRkvNOHidCbBj044eKj3aTN8pidyS930AOMonY6DJ+8rAD2fMJP/cKxE7aVSwi9urn2SZIcoYXezydwYgmfv+FXPml0NNvDc1CW4U6/wB0AiY4Zjve8FcQDzivpgiTUt2xuNB98AtRVABF2/GmReVyxl9G+Yd6/n23v4ZGFvZs0qQkbd8b89R63O0eO/ynRePU1Gf8hbfgtTy8XnfqhP1+Ha8M2aF6spgxJiZgDAa9NB5/fe20DQRrGWui9zRtwC8pj1+QW56cWvmH5Mt6wChg65bukVHWbqAbHhgw73RF+HUEiZteTazJaSTCRAbmKZNv5XciN4Cp3fd0V2BLZJBNQk/66MHHYQg0VwyK8ao0qX+bAKzn4Jiv2IJbgvyRQJVYJOPJGA6yCFFPmn6XZVBWmTH6oOZZgzU7DaNQVT+2ADa3T5/Xr3RPl+ljPNKU+MPC/JFbxLG2tiylYmzZchjD8yujD3WbLU0CDplwnaSRZN9tg3LJtN+pcO+G8DXAeDJv7TSvi56fFV4LL0cC4FunyvG7F0y+siW+0t/6S8F9mcEceKy5izUfHVw0pkzft2s34C7HfyGnTOp9xqD6QxC2naMWDcGGOOKFHneTgI5ls3y2zqbtWHpgolIBrIShs2J+TJmEPuxEvaNgVK37r91lktAYogCqLWO5ToT2TPJyGCkh34bHY/7WDudN8ox0/NF18YmqkkUgC6SRq+CgSrhmQfs8s/Ysh3wUqexc3BGI+ZuORxki/xQLFenZrPSjlWRMyKxv1/8/Y1qzXgvyEJ/AzmnwYetmU4CxEBwinPNZsVYrCbbhReo+yLCexXq7aWIdWTBJd7t/liXfCOSe7yjHzp1j1WgLTyISvJ0P05SGdhePq4mt6s/tblHbiWf1bEp53p60Bcfe9lBz9iktYXpYg/DL3/8G1aiRq44OU94dKHg8C6OpTDfxDDYCX/IkMy2NSvK0RQBZQyfolzxjnh8gSfTLt/INh+be6Und0ZOBhhMl0+lhAmFZZl8kerKmE1Tu/zV6B/LcUl4rAck6hogDXIzQeJgEvnJmHWWOJnMcaRfDODvmvViENMPTFvT8ZkNQBATvYNpSJFAarLU9wuDkAC27HGAFsBaGwCQjDMTKWPBNAWZAlvb1GM5CXC9pUZOUWRZ5JEAC3/99NVDrVtXjzAYKu25t5MtZvb3O4BlzxhIsP01/VMA/EIAfwIAnvAl5Jrcs9pc7eEY34zfSxnfpX/N2c+YBtvJFTPwBAl9pmUyBi2wVyAL+1bHpAHVCqqYMXNtZ6+7YiDTAaKajBCoc5ZWMmPE39U/lhrS94pa5J/9YRppOGWY3epEhsOkA1OaGGSJuFvnB7fE4zgqgHIcB9p3bwTASqslA/ZmJrcGEG8EAFmyeDMzP+4rKmYzrKfWWs3sVlWd5augLrBm2ocjKaPVlU0bJoa+xnhd1ZllQO2xLrbUdxnVjLF8ycmvndEnW1U6yRxdA6Yx682GIyPXl2GVpA23u/ZYsLrR9LDZeRXeikOmOwirMqLY8vUCOEPwXIzWkuz/6ALAomgye2xo13bKpXWk8BHmUy3tayrMi9+38DgHWN4XhZfps+8Marrnsj4jgJ51iYWI0d03AdnmtoY4swPjZjTCE/lraKrhvIzRdSzD5dx6liqdYqnQtaABuG1brjmyVdITZIold1rUwqZFyggyhWCufv0tWgh4BnUtXUb/PQVptoCUnhgVu4sOjbRWM5BdC/i0WgBuJcE0vUbsRj1KZtU4tmFEgAnj5iUaDwbwxSptX0vDIMaZZitDlo+nyJ0mHJKzbnVCG7rs3GTMvg83E6lhpufM0KutTNmRsW4WWTNdxoRlM3F/fKge7bZ5b2lwdSnWas2upIxG2WWrlFEt8vuAAteWMQDbmeKfGXu4gMQ8Z+yaKXuA/UqNfK5kjwC+LwIzbJ7xV8Nwed3re2D2Lglq8jqtS8bsikFjsEOZXFvHRg131rbR91N5ogC4lKHCDIjmeSp9HEyaMl3cJrWQJ3ZsW2O2+yPTj0U2SXVeY19528R2jWw1Ng4hMMv75GStr+BQXRdTZsxpkIVBdH96HFj9AxiEjXl1pbqsin9GQokFu3w/D5l+xBBkd9tal9jU6HiyNaUIO5NWpZVexPSDdaAmQC3bCYsshIYuJyPdvsQiY2HLNHRac+Ky2r48tGC+t1QsGVkzTwSnw1J/J2V8u+q29//e/MnyGgf7gt77NP+V25QuFqy9f/OIEtzjMoM6ot+Tab0Zw7E1uwwpVIoGH2yhn5l/LJrAYJtfkunq0ohlmm/umKHeS7CKI063JB26EzqMSQoFTI+Sv0Zk3rCqTcepkVJA1TEGVrjIQIBhQ+1ZwpKJfNHZ3aSZYfQdwK27MhaY/cIlVJoZsqpsGCLo2tnrH4krY919LhJQrYyZyhJ3dWq3mXVQk+VqlFUWK1QRNiOiy5AymljL+yJltMAFT2mk1k9WAnusCGEjD/2cie7P7O/P/55viZ9Bf+Tvf2G7C9XImF0PSe4lGJ8S8HnXc8x+sgIzlSuqbDFhzjo7FrRIx3F4Y8ugDB2zUwR4ujmGib19Z8hcGDGVPLowZ31VHfCM9iizxu6ECTBzZQ2fCc4WqaXUoHXrewaByKz6Gbw2Ns8FULEb42ltW3KNBMmiMKxA5JKiqknzyqqQ6QmyMo+GH6AosJRkwmPSRlwwaNfSF0ijgZOwsTsYKxQ2DZI71ioIh3esCjizaJcf6s1onM+v9sFh2Fd7oQEzLFBqfR+P9xkcrgLGcr6uAOTiGLu1kTF7jZ67YD52T3fl1Nro9yP29HmgsmNraWxvHy1emCJu23rqgojompgfCT+R1ehWPAlYRqqpHOMZllv5D+73stQtrqTf00NbC1E0xYGb5SHSw4ExQQe8v6bBbr7tCtnCpEGCpT3IHKNIsQxL8YIV/dwlZLfgxKh2+bbJddK2+RJUn8sVLSGEINM9A2ukBBx535jZaGlOGaajvVlU+6Ws2tJPtc17Zr4Q2SqH1JvRDhQBa3dg9jNg9gtXluyB99ixbBuL/cz84xAR6LYujdwimQljxqwbhXDwdXdm5DBqYs7KrYSgaU7tO5cy6l+0tbFEyggBZP16vglTdqMndkmA2t7YAwMAZrVkFedOi2/494sd+GkA/j9P+CLWKHW7eOil5k29MPI9Y/Yu/eshxdLB9iYZYet0dNCDKVvLWKkzoOfKrrH8sG1vyFWo/oxdAzXYOTgvJoxY2sZs3gU7FmSOGfjS7zDYudomyzSP4yiIjodOWWO1g62eV9bnAbiR9PFGGWZDHtm22XPNBpqgurpKMtHKGWi11qPf0/i9u/f33amx1KtxnIx4qgnhVFdjEK/RF4MZM85W3skXe4f8Eoh58hBHpk5SazlxYuSA6cCUdTcTWxvddwoWHVTSFGTStvmBXBC4c9RjpmxlxTIRInsurnKOGCitxXIunpgsqOytO2S/2JlxArONjPA1gJrvcRsFFPsl0F2U/J6uMbnwXj9Nb4E/frGQ5bg9VPdtpY1nR0L3fu8X6bZpaLJhljznzfKRGHH+O/Ygp/Ylc4xiMFibVyD2f1SH5lU69ezUmP3u7HSwJxc5IrBqE25x7HMRxowN9UtYY2yZBV5uzXeyU2BuSjoJizYOS+LIESSMiT7TyiZE2yCm/htXRl/7rTuAH1GbDFmU5LwV5TTE898IBN0dGL+Kgi/cgQ9dT+zGuLxP5hWZt9SoXTBnow4Nm7q0Mpmwbrev+WbdjdHLNscsBk/f11XMyD6/14hBcs0wBuamlLFKqDSCzQeWgYMcmO1cF3PZor0WsFKWC5fL2kProfffbsBXAeAJX35bA3qfzxqzd8noI1vuijHLQIiAJWa71CJ/AKZHt7Vx+uvMWNm5P77Oe8kxg+5Px6cikSxkkMGZYMEU47mM2Q7kEcDr7eQ6O9MaNXZ87ICPpYts1d8ZMAbnnMPW89Tkt6HrXcQhY/zYVyfGVBVTAxJY4sFqXRk0LbnKHOW5U1cViPkkns46umEDtkGWFUmINDXe6upewlCyFkKX1nauzT7sRJNpYqHfd7ImWWYuu8PWG5PNAHFYEWL51omRpxcJkt47NHZ+LYI0bZUe79ocLF8n9/g5wcwPsU9qxIFn5kpfJV0/52uPsoV2tZ5rO41HLUEszWdbP+9tRp6zs8L47WLhdissPdU4kTPyZ74qQ/JxBsJd2DQ7qSXbmwnMm++ET/cMp5WzAVkmLNrBB6SMluabgZaJcktlwhicoawgLXhkqIV+icQTSxS13myx0NeOrNSYGXbWCJYwosJWecZobar9TCSjrxwAfiNuZKt/JLb7Z+zZcUFBak1a9j2uU7NyXZeGjXPjIl3UWrPOnFmw0++h01hqzaJ0sNLVWwnC9VS0mwxLxKw/E955X1PWt1voiXNmg39eR2bLtMelj4+ZhHRevwK/AcBfecKX7DF9xOMSkveM2Tv07wws9Y47AwECSmffUQDHGWBVQFzmnAhiXxiYbHPWLqR3zu+1rozAWWDyFLglgAgZW7dj7BKwtdSaXbB9pkCQGEyVPuo+L+8b02ZZrpvW3zFbSLJOPsfhaVcVkCXduBAiLQjLNz1/F1fGIwEJSr5VAmiesWeP/1jWjteQSpFjiXbS3MUuX3imkWNmQv9Rzz/VYrIZCTNrLo4Iq1jPJH/Kg7RRrSJAzozneWZ1GH/sks+iINJpTNMDJxMr4Poj96h1BDh7BoUaYptyRAuj5R5cBPt6WvfTIsqKYbTe1mHxcjD1u1j5BQZ5Cwzx+a05vcLdCFtz0LXPsQBTVBi3zV2VeZMlEOFYg7bjQiv6DGfNh4nMXVLoAYj5CNq+d7HupFLflxhy7eMjDxK08/cAuvVgaiODPHRu72MZdR6ZfhJHjZlJz97FYcNj7djiROGTdTNPTU2Y7QqywHQUfc1u4vk3+psisQnKPHVitAH0/NQghM+1Ul7RcGPMLSveYGXfkmVWckyzuDJ6lC8G4MWnDSe2+SmBqVpM+THYLlRavSELuZe0zz4yy75nrSWD1JjZxXSpO7usUSsP1Jxt6tYCu9YDr5/r2miRVStntWarXb6RhNHa3M791sCQ8WCQpQHQAEIt21UA9DpM8XqM2aOACxfT5f7wPXfG7Et0sz2TKmaDECoHqm8f+LzPMXuzf2rtzmBsx2zR62LEQbVm/bNTDZrvvkcGEkMuyQYUx3F097+HGDFm7s6yzRLL+y3jdcaEMeh6E9asn5Os1oscEnuTC7k3DgOQbuLR1YvN4KMQKC4zxsxT84/O8GugdCCm6Dsyb0oZ+WGYeGH4piSrZzCruSGDuZ3Rx6GrlNuXb/rz18SBRX//LCk7UH41qUNDLLID0X/BAETBoNjjc85ZKiXLKudU8xW9EFdzTBuclnJvGVs2GTPQmVgT5bLYX5dkmSiupFNSD/EpVNTvgTBk57+qBI5PEBKCiwObS51w57o7xjce5DPthtayO+/fr4E99tRy3ynmwC1K7+6OhpHz6ZnuXm0GudO2xz3I4pk3j9JE2wE32vYAsQNkirDRK6q1ei8Cv269y1UHCIZPWG4c9TDKKZ0h6n2UZ/m9MpSt8/xYFlM9DXHc56BEANNLYZKtEkYkskatkOlujkHj5xlEbnBrhztZcBjtwAs0dWwCvZJUqCHY59vCK8TWxZozI6bsrJu3SBgRa7syg0NjPWJC+ATsdvZ5h6uwloytC/m0KdUiuHSFyRa47ozZNCvA4U+A/cbo3ph02UMq96ZLf1a0d+h0rDVoyGrSsrwzqkszrmfbgDOVOwY2bZqEGIEzb0+KKW3kGjMngDY9HQGkBvkqX8wYsilZXGva/LVYstcz/HguEEuGDn6TA//8vcbsTBrtz5j+KQCz94zZpwLMUkbq0ddHgQwDPGbM+qwux2PGjCSEof6M2Z5HpJivM+/RfXuk7mxjtGEU/NzBZG1/RjVmHYjVzu61Y1U7C9YPGdWiuWSgjftPqx3sdWYL8NJ/BP7SeQOYcXg0EivyjeFHL93ojvLGbNlx//P27Ah1ZpZbb9yPEbnKI8lg9lOWPxlxNWLCVAMnjoyBGkxkjV3KeCAvlOOdWxouoK3faNlCP4AyG8ktToDAqfNVA/to23qy+eojPjqP/FbYHEOnp2GIyaOVub0+OOErmzLYrXkMrAZCJrA9fXR5b3rRoIEDFvLqIsit49ruQIhgAp8Ozhw3Hx1fC0jRA5/J7KwteXPjxjfO6x3X2+wj1vgsnkDIQrtgLcPHeynLZBEhYw+DZVM5ZNs5dwvsRAc8RnWRLh34CdRa2+vs57rL+7FtMr9pE00BvDnc70DLAuPXrp52cYzvMUUzcswQa8Yyp0Z9v9zpHFe1ZcAaKJ119m7gwOnpUFdI2liXxC+GcAWZyb4nXUQPXSEPzCqXbwXbe+xxRIYp1JERXKJUz3PLAijzfB7yjq3cOi3uUCZnHA0mwKXHcph+CEX4yl6hoOBVO0CvmNrrrorozNp8z8t0NqyKu0m1k5o0ZcEwmTFIjVrfvyp2/WMdZb4qIOOctFqilLFQTZrdpY1m1ozvC4VNrw6IhTLLejw6xLPU5d7odF8uyITzj8sNVyb79Rgxe0MglixbDHj1hC9aHJLQDsqVqN7pB1Dfm398loDZIwANFzVmmHb5Z8AsZcyIvWFzjFBvtpEaBsAmoE0t9VWSqCzbWwNmmUX+Zp6J46MRi2bEnjFDFqzvef18nplF7Hb8IpVkYJgyZAkQ07/iIAUUGRNmffVg7gEsFvkZGdXNDbW2rG6ggdac+YNYbF3AogYyuDNSL3wANrWTpGK5Pm9IGdvDsssZQ32Zb6SM1EkNAM3lvl2RO+V5AG0uTEMloeOZnPGA42lIGdcIaiS1ZFjqyaInXISLbV+Og0bwyRlvMFTtUeMiu6oeuCFrF14lnaM1dmkhGZ1laRbA3JCtVQ9zKpi1a+0bHYca2mhWB6ipZN/d2SRvmjHvAMQojc5rzCaroi/zicxGdl2SkT5JwfsyXQJaLWp9wxGUy6ntWQNF2SDtNNewcW9q763C6pTNziM9daC1rdRsgrI+iFMDa2KolbTSlD/YgelgIPsl1F0ZjXRzA6AlgVq2Ccg2YBfRHDltTTHjWg9LgRmCvNEobBeL+YeRGMzEpdFCDVmBujTO5Wb9jWVW+fzzIEJIy7IGAVXWsqhOqKgysJRo+n/W6S2Gy070jlELctNMIREarNOoqziSsrsMsLX88K/By08FGih7aq+BLSOGa1t/lnTZLalPw4O2mLVElo0/FwJkwaVRJZHq6lhCXdnMNZs1Z2ZlgDNcSBm1ljI6ifanmpHjIgL7luX9xey0PRv2Jq6KjwCtR7+XTPvpFfa1u5SxvA1L394ze+vA5/a2scrbXNm7ZPSRLfdn/syfeTYrlr3fySElMHpxRryax+CNHSEzKaSAqQDAtOaKlmOZY7C/17osRGMQexSg6TK70GoJeR7HUYHa7hgy4NsxdT1kWsCwfsfOWE49V9lQcM3GZs7AkOdALCvL6rinIjH8sBV0qRpwKbnakf3LsqtsLjgmqkX2oP6QaDgFeTI7lh2gRY9J4BCJdMpkx5ejYtDcslxeGIOlVx7MA7NWyCbElnDpullrFj6dXzte6wBg401nVmp2rc0qKEjZjw3AI9+xPLTazMjWX8PGQeGyxH21nmsEkj5+IE4j9BzAHDuHdQBxg6/HZOwXCRbDKZ8sKWR0WT+xiJBBBMxnXWiH1OKuaIGkzY5ha2g1OoYVCPVqvohubbGDIYDqlpvFGB+vyY4NIL6ctxvVk9n6Hpxa3Mbeg7yR6848iUpIe/4jKNfkjGhENHdHJ1gpkmMWHTQsMGURDsbAaE5SQ+ALLMjELIsIixnbCXtmEglmhHO8j/sT+uLg6UBKmsTKESNuJT507KQ00fxsKN42kkUBQ6rBHNkBhD69AIf9NLh9eXyvZLaUkknGktkOlJgvUcMQrZVbvncB2IoJKJNw68VGv7FlXRJZL2rParTVL2aDDzuTMpYG1250vdZl+M7eWhaZzsczgRgeAmX2LNYs2cZXDP7TZo7Zjhl7tHL+U6oxe59j9q1jzDYsmQKxh6SOyro1VqjuAABL78SdUGvIljaqzPGZro0aqgw1+biqN1OnSZ+uHZaRUH3fqKaM68A6Y8ZmKZ35Gp8flR92lo1kjGhsJPr5YPasyyo3TNmsb/MV/1QPvgOnqc9qlW9UjoV6d4WvRRgyj9lmQx2oKkCP9Wa+Y/yXz5YM4Yglvpp8GDFIgznjIrqa5JiRnLEHS3djkODI6JvjZxdjTbaMgLvIFTVEerXw4KZ6CJjuLJk3js3Sb63paUjirLn6bdRPeWOPrA7QY9RJHyYdbJoRTCcItBmbYHgCYgniGTM61JElzZ2ZT4MPvzNOs6arS+smsJx1VtbqwawxWS5AD7EcxiebdJf/eWTmBm6cAJGNT4JM1KY0cqybatzutWOT0xzL1egxM5tq7Zx34nhCp8GmWQSaDAqdj5EMJBgfM+s1Yyy4m4DR2v4PsGee5gp775B2dwmopZ/UnZUbGYEgYclsw57Z8hs06qrFKrBVzrgK6Ew8GA3suGhpwPSePVvjrnMwpv0+Y3MPUOxXSQgdUQOamgq2XOZghknv2S5/KU27rVln4FO3TQ2xDSjLXBdjnHewKBlU4Q3Aq8Y44cN5AHuuGdnmh/c8rU14MuAV7kybyftD5JBqBHIgAr+6Wf5Qxo5AKMske4aZMns1C6E+/zNjKaNJTZeHBL4qTqFrePS1sccjQGsVSz4uMTyTKb6mZHHPUAMfxhyzM8liNrypnZr7E+BtM1zvOgP3kwGYpQHQiCYej64jlTISI5ZJHEH1ZvagrX9m8JFJGU/ZLUQ7/T6/ZC6RO+MPBp30t6zjgm0bNWeUOcY1ZIWkiCMEO2HUTIBYkCRKrRnb4/cNl8DjJMAPQOmYgsmbkTfkOMsgDstwnRm/dtJpAQ6emLT7dvWr6MivtI2+T8zW+rIA1iotQ8HSEGDGNWbdejLbCT1uJj0OP8tP0pqx6KRXESVl2Wb3wd61cWezYM63qXIMhxzTWiODSG28sWfBDf1aTdga3ud6Xgv9XH2EKgW367GcKzZVUMnDsg/717lehS8PtxONRmTmK/hvrs01jc2LosLnHyRcN9uGZPax5c/bNGFgXbjTk9UGG0CpL7PS5I0CwhTIQTMWPFA0WsMSOStLZI55rdlaKcbMWRFwFp0Ye3fJN+wZs2OWsqs5ecSDAUtGM0TWmFnkW3Rl5JKpktWQEYE5MLLN02VZf5WWSUGZZfdSy9moIGWUWjNQPdor/2X3HuVVF3wz3/Rg29rmR0V0mWRSmbdjZ7kv0kcT8xCzjUHIjYKpp8yx3LqUsSxSxvslUClM2hYGF8iMPRYrHlrv49JECMC7YrOuWK7XPPPbaQ77ZU/4dtJe+7LE+tmwr/T/dKSM72vM3uDfVbZYAsRwxYypVX43rLiSMnY2am4y9LJ6Ntejzowm0zIr+ey7dgKQ/ATEXX0vMHhn39nlmLEdfgerBPy2ksakvmwBrXw+mqtmBpAtO/aJ1NGq4hYFOX4GflZJYzfQG68+GbIlj1nUf4ynsJO4qDPjjj0bujFLBqTYatJj/dmQPiZOjSnz5atGU/Od4g95vd8Oy26/7sMHO2/fOjHqaauLSLFS19+X+jLdUV8kjJ5W6Ixt1uMt3wBxotK/0rpeff98fWuC1wl0EDv55+3Tm5YiULuuVnVKr2y+6NJbPkNQnpu6ZBltEfBcNNwEmGmIFpt7FELXsChpJCA23SJd2mWLVT6ILZtLlcxVnt5bqMO5swtcM6aixzKkkwjWCmt3UtmyjEemdIbgwIhEtrg4LlJ5kpNJoFO/vlirM/MclI4sZzLVhNjoBwkkFR8FKxMT+g+ONBlbZYyab+Y2A5q7McaBXzBBD+YrT2NQlM1/5Du79wcxXv39gdws5CjRLITNQw6cW+7vzEG6CcihxiDTCESljBwmzRyW0/Wo5h6PAq7nmnm8DZYLb/87v2Da5ZdNh8AumDJ9ir8HZp8VxswShuxKomgJ47UDUpxXNqSMBLwUjHGNWZAobkCWJ/vzWk6Mj057pOaMWS0GmUkd2K7urJISMYDVLn1s2+CMM2W0WOoYctKwkTxq37wrIbGY4Ue7fFPckvX2gSDhG4o/UCnWQcNY3TMjIZWqusqTIYjWoWW46pQtCz2TukIXLWwzBWGZwfzRdiRFOlHCWMkJEhsLSsuO71lP1wQi7WMI9FR1GDaDqD0ETE/jj7rhK+ODYQfegvCy1jjmZ4/s457qMkSjiunxYWLqIh03V8fCx9qi9VCuRheJyQILh9XifnAsbLiByBxaUru3Vj/ZdIz0s2Wphq7LHU3jBjTDKybS+fbYIHrqYCnZCyfel9+csGgGWcb3XKbZ6u8+SBGiZjjLbAoKom4uiG98X6+EWMUVTfFXedW0w2eAZmLb3ZPPbosQUtkzE/85D/AwZkJlHUmz/FK3E0CWucRnGWedwGRgdUs6z2CGrL13IcOUI/BQa2w504wHEeaSmC3o87BPtl3tjGa0ZH6YlpiCpEHVu/lnTBuurTRPw6sTsMY1aCx5rLdmnx/ljP0ZchtXN3AM4BaZsszYIwI0e22zjh1QegS0PceA5jUB2ydRymgno8nZGvT++znMMXuXjD6y5S7s8k8Zsnteji0Oh2fr4mUJgC3AqwMN+i7XlCkIPK0j41cOsb6SQl5Y8LOD4RW442DoS9DW67ja9MrgqFnjd9BcEWvKjOWEoMgBAnvb+rOEzUsBGteipT1poFR9KCau8uk3mUiqcRlVASr4UqIJGQll67wHxvRXdFaxBq1lhXKe1JmZ1JstUkaiAZ0GxAKztrGXrNkTYZU4GGZdWdwzWzisXY3ZMbueA6CtcdOVxjQj3DMy5fcErWuemQHwo1IP3jbsjJ1McuFRyE49uwBCuPMDLBFjZo8D8HP+nuoJgwT2CAN2tb95Yzn0mvdxCQ9Y2qv7GaOxL1p2QYMJz+UXg726nd0l8chhHAHTIGdGkAGIUDBB6ijIMozy+MKV5WM/Je3cZeljha7gG5EqLGW0ZpvgYou/5pqVhSmb9X6G1Y9RWLKN/4TiGTvLaNYyriJ1ZRDZok5XXI3IjPFv0T2pNzOIvaQAFbc46GJlPUMcKs10INd5HVhrvyCDAWqbrwjzQHyfTTudn6zTLC6r01J7fkTDkiyo+igrINvUmkUpo4dBAn0yFBruex1G7BFQdAWUXld38FxwtvvOzDErF9Kjs1agdzbe2+V/hhgz9GDoDeO1Xa5L4UQqt8gHSW6XMWbAlOilwE1rwHbgiBFjUi+WAjIGflntGLOEG+nhmdNi6tBI+6WujMwMVgKNNwFU3RyEAZ66U2qbnJbN2MzMIr9uuBkKphYAhtVVPsMxo4Ml3hkaCxaYMKxW+YxvXAaHGNClHepdr9JF0uKeM2VKe41OQMWaBVBn/e0OdFUPtueB9qsXDN8yxthB16wyySJ5ccph3e3xbwmYq0PZ70lIdE24ol21X8xOsvbwnnJbMsdA7MVP0GEUzty6suaUkNZxx+yQcTj1vCgNLmBEXR8DgGbTP4sxBtNUYw/Mhvej0xlLEtBNKNLATNvaSY3o3ebvsUluncBNCG1Wpq9LKlsHbZwpDvLmLdExNAXDRllo1OBKz5FhcR9OC2fH9Sw2MnjpQIOla92MhSFoD5zudvlDyljoPaJqCFitAY16/wGg4YQ9XUf2CyACQ6P6Mdvmet3aXx1ruCVm+jGmN8s5y1g0NijJBFOaazwAlgA0N/HOKOvnUapFh/1ma10d9PAbkK1qwcuWgX1lk0q8txSLoC1FmQTKuFju2PW0LXm/6YbbSXdewV2KiIFtbdprf8cu0HdJwq2p7qzc7qHTdg+dLsKYYYlBf07g8zkoe4T5et3vvE1m7OzfE75drvJHAFlaHODA8b7G7F37d8EuXTFpkKyw1LJ9A+z6dd3dBLP6sykci66M2hZ/wG0xyy47zTjbZKPhxO3Rs9oxiIFIZoAix49rubiejNdvuh+ScdYfPbeMFdNrgNQA7NgItdSXZbd3gYoLwJDFaWldWSUHelHDeQuZDmHILnb5ntvpJ+qmGEd2KslWm21EOs89UleDHWN+SeSMPWA6IE2LRXRMCy4FcTsVwwq7LIjmqAObMGRbdSUQwFUdvosOwzH2ywJzdmA1MXacFxuuy7gfs8MNkNUnIftx2BhA1REaDTKHGK6PWeoBgQpt4gofqe11fsc9oA/6vgsrNwOzoxkL/98ChBtx4VpfFaO71prIcTz65WuBOYOvdYdsEtNDtTsKC6DJ18uz9qDuBJbDF0JzfXbI+eH9XJK23EOtSgDbPQg78KXtqDKDwLllejMo0st3TzrGO6t8D+YfDhYNMhyKMkNbrEEwQnePRbC4Jn8pzFsHAmyxH8mqGUMOM+82vy85YxbwDBLjQ3VrbAHTRoedr5FiUXF61tHtwE1Ur+eEgsmgXVE3RssRp4K2Q0DYo7SJMl04qT9bgB414SE27XVr4JLpWY1aQXtYSwZalzTeJjAr4Zn0Znlhb8t047mM2Nti287Wd2fMblitsrC99+zDp4/PBJD6XDNmD4ZKb+vSZD1+IWV0BWFk/gFQiPSJK+NDjBmBHtd1KMjKGC+dtvlcEklgB5b1GcHUwR5/V2PWjxeBNOs1Z2ZmHaAJixdcGTfsmW+ojMWJccuYYVNPVjcEygakmd9BGAphm27+Ucn4g3GMz7KtxcBQalgqVs06tHIukwTOar3InqmscQlhS3zxMyljbY3oOxkYNYjnv/6ZdB4hUMqDQ5+PGOlzs0y17agNht1GnZlWC9SEJTvbCoI9vpyVdr9iS30OKp77bWTIMG5LNlmzzuoPJsoioDHq4Pd8tLvSKZo2DHUAhT8zM6dHHdWX0OneNqsWrPXhtQVLj6Ub40YAg2zvwUxcywrrh8QcQUs83f09Joh5iw+Ao5LNPgNhM2bWfLCFTsyeCZfu8JAZ148ZdLuOEaaNMU3Zsgh0ozgXNN0Cl2jtd6FtGZEJXNTEjNgiXYSEa9G0YP8njhSLjca0APFNoHQma7y131yh41cGm3Y3/zCSLk4ObjWY9+B4N2HjWglYlqETzSLjCDfNItuRSyjRNt+lPKvYavyhsBPJaTDLsZX5CuZyDbMnTBFyVoiljZwb4CJlfFYvPHNmfHQdiTXmzunxoXU8WAN3JJrWs6Drgy6AWlBKGXb32l04D1t/ffD1XID0rVrfY4zZF5Nfgj/AkEk/5tMy//ja174W7O3fQo7ZWw2Y/qwAs2eAr9N5z8hCC1LGBi4qom0+A6ZQY0YL2Bm79Qj42r1/5PMzpi+gDZscsy5d3NWYSW6bE+OY5pjdywA9GHecASwFZwKkdZkUmB0X9/+AxaTXz47zXqV1DZzV2gbhPKr9nIwRucjbyZWRQeO2jamXPgMdJ5t0dWDcHZaaw5yqVvh1Ik2w4YeCQ1PcE5FlqA0ascAySu9b7ir3T4ywa743kkhmWWU1VK/ZBo1XYkAskU7VeoyTaFZJ8ucDhNTQCYksTwddtYOClu8zTmvPBGNHfl87Ll02hw4UW/7XOJ4W+3hD9t2vQaftOyb6Q1zP7AVPsOLB/vt+EfpQO09nVcDJLd9Cl3tmsqFlfvkarr2YelImWmt/HXlkiGCL2t6lpD1vrrYfppk1wrOOiKXpzFOpHrTnrfk49mjHHIj710Gek5ebixFKNTF9gQFfKEnPn0Kmi6+5ZsygBStAtYKNLFRCFKV5SkgBmonw0Al6+SJd5PwnpPJFSzm6aNS/OqaGfnlmnY+VWFpIprICtm7cFw499lluZyDWZLTdLpVeOxv6nRlIRvlZtJZ8daEtyVr1cC5F0q335/YAE5jgj7bFnjct1KUhuDkaboM1c+yzwb6VYOltsVxvckb2wOzpAG47Z6EH/gW7/Ap8znLM3iWjj2y5H/iBHwggR5gonLBUCxOG1fzDkhqvnZQxZcx2rowMuHR7CUhT+/ytY6POy763MRrZ2uCfzEuliBAESvNG9ADJFTsjNxhGZsloXgfhaVvIij/cH3o7xSnydB/uf9gWjSvo6R1icE5ZGrgciSc29AAI33iUq3giXfTsHnXpVqB2+ELtjY3tXBg3zoxjZxBRIyA2ky6Wkp7XwS3BtgqBfLEkYHnfmS9L5MEqRULbCAeNhh1OgA0EzHxDmRoJED0B8fP4encSdB9RCTbYnQY+mtQx4GcjoNIukl7qZ+4ExmY0wmBvWpe1Uui0O/F3rG6zSc9yIPQd7NQBWuaJmFI7dxdA1fbDZ8DzHaRUcimsA9x4uz47g+Vdc9jsTs1tyiw7ZBjHa7poODFitNcw83Zo2ScScKtUb2bwSoME41i0fWkOmx2cOrT+j8BkZwGtjlH0AXbd7tul/Q6/hVHTV8modI7aGIdfpUwZuYr0lGP1i1d3xkVCpFe5Xd5yitSXqa1+DJnujNkKTyzhmnzrXXdmrG1rx1N+ptpNVPxi5CrPiMlk8F+DpJc/mwYh9syOsC8NVJaJGyvLBIhXkJp/FAJqVUwx9LU8OK0mVvUlWf+j382Wf+76TtveKM9a5jS2469lCae2K5Olb/G/d6ktKzDDxzMsTy9o98fljHVQZu+ljO8YY/a6DNlzGbQE6FUCOW+VMVPr/rfFmL2u1FFcDhd7+o0rYmDMfPakuCaOAdww/8CUfw5ZY1+EpiOTLrKZCLaeiYsFP88r9UobtykzGiuX/lUmqmQpYwqFalKqdfX3nBFCBkhLw+saOK3h04oyMzf9ETbtpNlE7jrPnL+/zuhpjlX3F4ALJ+YoQ9RYG1SYtWZOO+UbCGhhHhuJeB/FGZ14mA13zPsFb2AHx9plgg64RwkZrI5SMC7DMk+UoJKzNUvaLMgqp/DGSV5oZPzSWThbahUj50QttXoHY8wQ0VcruHqJpYZsZ99pujo61zUEb3f5ZRX3VCNjkMmyuVcBjRHgj32xFCOhHX7K8u0mHLvEBxsWH1n3o9LR83VrIHzeQKCYtxjIldHuA9HdTWNgHEUBLh16zwvlUjgw9zSXZcXw6ZKwZyX9y+dEjjzCutV50Siuer8Xph8SBqz3pDIlW7eBG9llBVOmTqeiH/YbNiHTZ8yZXH/p2ViyKjVwWi0ksXJyHMAWjv3t3oUeF9PTOs1P5p1O4+/envnd567j0bbzX5HXGx2Xp/vx8tsAZqyzWB739rxnFt7s0Xeao/la4P9T+O4T8E0ZFcBa36B3y+zKNwfu4aDvgdlPXmD2UI0Z8lyyysxWa1uhZT1hchS8nbYzM/ggQJOxYM/NO7NdjVnCLKXrSOzs0xozki+qXf4Au2YWmDWdflFjtgVt2ptOJJG3LS646vGT0+BQeGUMGuEUd5DlxJzGLJrip37DdzEfSO3NkWlzMBsx5IMEzsJ7djAhm8luOclg64CALz93bOScM096ea7j9EvXnzq0NuDTVZ3ZQcG2UcpY298EWWXwa1XG5Xc1Z/HZ0f9fARzHsaFgz6YaVKE++lzqL7ouGqaRWLBDPwElCpZOVnayye3GPXnWhu15DAGD5ys3Eyo5C6SKDQtmpA+MNU+OKtnGgtIezKELL2temi7Hfe+6vQAAlKdWZyYJxMO3vYcIkx3+UmOGlXVLuluGGB6tnQ9NH0NgxnJp37Sl2C/lKQcFYdFc8ArLHj0cFheGzHz5ylbKyLimiLTRKcesM2e8WgZsC2BNiIKdo154EJkGRvPK2WAnEU0aBUzzNLfHQRb/+W7eBij5bQO0rrYl8z1Zh+/ax+9L/K6+X/6svZZhCjK8r3w+Ah8Zy72ykPIHQdtzgZQ/8P7TBIERmPkzWgtmysJd/nOVY/au/3uwpsxPgqT9ikGjzLNTV0YFigy62nXjJ1JDz4BTstxYsdS47bLLtvJFBnkM8M5cGYXF24Gz7C9zZcyy0UoHXaM/1RgzdWXUc0bdpaqgTXtdZlZ930OzajgvXJLPnqGASvOEJRou80mG2SCZeNO6PPegEc39FuafJ3Z6pVIHzT3Seur5zz0Z3kGnULZqubEHLNdiIkvetYs7/YRfDI0gDBiyUUt4kC0C0x6fa88OOnkdrh3oMjgnCAeCW7vHp0MtuqvXWc5HdXNZftaEnnVWPzUG7a6Ka3K9unbkfZEzJkCBpmu29H1b3FYsIG7IGk1KCLXGi5DFYPDOSqHp2h3yvgwexR3tN4twr14AK+GeylWAo5YMKRMIMTBUkGmUoN0BlwkIZJNEF1wFBctBPTmvVx6MiOeS/N0L6+Skk16yURxoxgJyKVG0/4hjKUa1lfsam5WQMqkY00o0rSGLIzd+UdXmoe0W8Mnirs6HMylr2xmBhLGurmyT2Ioi+Lf7AocMs36+ixCbWFMMPLvHa8yBWxLSfII6h2U+7cgO3FyyWwKCAhjKlsvWVyJ4WoBUoe8Kw8XT+rp5G/5E63qS1zIZMZfP9RazzFDg1e6zOzCj8un+rH5AbJOO+z4Cop4D5PyZIOtNQODZ+iYw0zj1vJcfh9VMh23fSxk/o4yZJRLCR15P67NwLmVk0PPGjBnnmEHs6xOglGZ/Jdu1Z7Bp24yzPu0kAy2TNt6ZqU2OWT9mHtH1wvAhCZcGuWGCDEME2JWT+2SpWS8ku/OoPX6l2wfHfmEFbAcxZSpHZJzTR+KqRX8Mp07momzZOjOyi4iLXb7WlxFwsx3SFMRYIZ8NadKz1wjaWIep4S5+etiXB5l+5hjoDrk8nBIfgkWVIk6rkOjneM2Y5ZRlPXK2ifvoe9him07za/7jOiUx588InGpn6GTP9XnK9JyzS0P66Ltag3PW8dEj5MrWJetwXJCGlkhJ6yMM4XVjc87Slry+SdF0lixLOSYmrPTEY09s4ujXYednKcKf6JK4ly7aECgW4cRAAdO9Y+20lplVpgYgOSgrgAx70HlnctKScq0da8Y5Zrj32Uv7zFFgRbPJfJYxFSIzx6ZKJC4DICPhVigDLDzgRqjSyaACyqYlyLI/EsvtbiNsmjCnQKqs76+YqkUmuJl2tb4F7JXzaR1sgQBWkGsSCKsto2yAsj69nVCnwOl2XLsJ8XhOs2LfEsssy59PV0DrTZm0T5Npe+767jVmg65FktshY5WOGMO+FD98voDZu2T0kS13BswYGO0YMZybf5wt5wzIBDjdO/ezcYZoBJKafQiYymzxGbzgBLCE5U6kjbsMNbXwf0jKSEDprM7MeHo/hhQD0MOiTYDXIlmkE5bWuGHjysjMInKZY6m4BmJBScK+GpUyzGoC0jqewVqOlbFnoNH1gGEs4q6lE7ncRWWCMS2n1vggkNasJK1GpuzOLbbCaCbTuDCuRvfFnfd/Nljvj4/G7SSL+XvH0WSMkR8DMNwXGa5VYGsAYids2fr4HIMXwRriEeiwQxQ9lFiX5jAwpOWFttvEdaPCPuRfnGyhPbrC013Pgqx1WaqJe/ZOncz32PfNWzKjC86tzHdHLgZH50vRT1VdyHswVqEgaROTj160ZALCxjLc+z+7kVjitGiBvyohdNqE+4qWHt2RsQxxsdaXZRLGErLNeAvREmZjU7IxLjQGWBlrJpEEdqM4FPLNYLv8UV9WWtlfx8aFmEMiOBkwKkBz5QzUDp9HUjSAzZFQf7QjOKYrIzNmqUzwKX9/BqBOl8/Wl0zzZP52WiJNVIlivc3A6CFN7NNKBGLd8MNnpEB/zA0A1gQkXc54mJQo5KKafayL5V2QM3btkUHL1wF1b5O5e4In5h/hwb/S9fvR8feM2WeIMTOsEsZlejIvrd1KwF0PQ+bx/SrgqwhbxnVVg7ViQIR9+HXatjPwlQCnR80+svDnnUX+rg4tgC/k9vmFTUEIuN0EyCndta2Fw2omwqYjWb1ZpswpwQsjI9Y9lmtUDXrm20tdLfUH40UdLbbGD6o+ka84kVwcSGx531hG7akTVs/G6WQnOyoMO3G0B5wmYZvUk3mshOblYRFpPkr2PPBQyaHSZIZibZk18w9v5ueryb4TWzbT0yqZJGtgs6f3q3la6tr1ZkdEKxRhEM+rdcdC3M0snC4YL3RBke285geHJx8rVQVrOuF4bWhleEm5eMMe3tkvsz2e3BfAFe3qEQ1AGHhRe+uaOS2yTRfS2AVe+OmVFL7rM5OMSd1wzpvbpJ11cch1NPHsHM6gMxGvSqd6SiQDE2StvqyUyIQZ1ZwZRL4ICaHuv8OCswwhl2OmXodRXOgBuu2s4csiRSxQx0UP/BKIb+PYa8t6dMiOuF7ORvf2XYTVwDFlxT2MH0s7hKVIx0wMNCGnhTkBnsaXkZVn3CQX7aayamU+iCxxO/HbU5QRirTw1CgjYcWYrfKTaYHlus33gVHTaSQ7RCZFLOtyfpPP7Xh4dFxM/9xSdcsAZ0ZlCSYDsfZ43dlVjdrrgKs3rWl7nTE2ev80GTPGK1ltwzLClRacvXXg8z7H7A1P+Ik8UYFI79DLdD/5jglA20kZFbAZuwf26WwGssles41kUuvHmF1bbPwz1m1Tb5bWnyUsnOux2NjjW1b3JTgp2Oar+QfLIbskVAO4M1ko78+oL4kd4jj+vrYztLnubkzaqZXSq1oF0/BnzWXm0bTOkJETI05IJqdts3TKru66mjoMUAKxhrGRM+PQatJrX/aoot/wqNkYO2eJ+YcnCFQMDB686e8KqVdMrMJEzjSrix0+uzFa8i3toHsQJcYu4D22gevx/aSc7lgIoYDkuTPNo+bHPCo8y/MSuJycUmTfQEk0l+e8sgZv3S4IqSOKU5YzaK9FgIVtW6LeNeHveo5byL2wTW0myTx9bTXD8bufznSA3Dy0Fr408ou6c74nZgcbRuFZIXDao45uMfbwyKSVx0RL0XlxH5hcEvhURMLYuJoGB22wZGqJ74OLK0G+6GRHEvk8LL/DhcOU813UO2NTa+bsm8E70P4GU+YiXRSMXOh0dCmjWcTTer1b1l1dRuOMKDzeiRJ3pAMyIx2mU3I2bj96WhPmSQ2Xy/ts2tV3eL7f1vfIDDqeTgw7brFGrIhM0QqxZm25UiI4A6eJF9SWQxokiz4dlavfwZk35uwQUJaxZcu0ndgEjxmL4IQ9O3uP11jX2TS5k/zoE/DJHAG6rDPjB1G23HvG7DPEmJ0yZQJ82F59t47MMKRg1pWFmrIEDNQMAAkIYgC0s8j3MyC1W2fGLGk4dwLIkLFTF9O0Jq8Qa9YZM7j7DdP+vksab2zJ39nFzJWR2r/cK8goxCRoemHIkmlAlzLuevxs4kG2+Py59nqzW2L+USmDmUfZ6Ob+SLHwkm32cFWuShWxhkpz2LSxdT5rMv2u4xlPEU+eNJYwaSd9Pn/eON3OK4SFiNmDr/ejqkRKTwDGzowI4dK65bXmDNsdvNeY9dwyCnpuFujsbOEz3XmaEBoiM+Ctiz/IpRrqmZzlaRJifG+Q0UBDAzeDbBO7ierkEGgRQthk0NAZprEPbR39klqMMYxyz+uwx69wCtzmzLT7znqV0OnO3zQkN+6+Pq34OV5vGovM4zUrHiY1zQM91qIDVu+/+3HvYeEVXdboZPTCfeh7jMA4ku2AWMuBm+2Z7evxBuA2NjOYkGRcqFCKM8sUCTB9AwmgXgZGPOyDC0RPVIEJiHOROEZ+7O6Q2t/N6OkM4mWWIdHAH1BZYzbIZr7ilADCgDT52QiUeRWr/QbMOundwRlj3/FZsbIlgFBxegrMPLJheiYc5wYgISGbpz39IaD8tusarl1dF9ejleR9Mi1l0kpk1XYsGMrKgJ2xZ/xX6cT2jDLWtw6wW2YteI1GH+P57Sto29WdnTFoV4zaMs8e6C/g9WSOb0vKaMAfeoJ/NAXDpnoki3JGKoZORPtdyvi5Cpj+yQDMlClLmDCVEwagsWPSMJSMCCxQBxQMqJQtU8YLibOitMkUBOk+Pypf3ACwHZhLt02MluabLbb1ZnarEy1ZYlRStOZMLfexkSjKspkpSFAlEVh2YS+jlDHJJjMdiSejDy67YkyzG+7y2p4FvnGSt7WeDB5vvjqOlKqyDHmgsz7UnWRgph79hDZ3tpO7sDUkFB94J30jpvfUeix30s8ioaNtpbozYhEpogkLuZ5shksjZEzV7WPNwEzY3FJv81Hr6FwPrNs78S7MycgwQwxejnijMUU+8rDuGVytwz6Ckzlo+p6H5T6dFYcMzynAuoMr/mlY314dIGyELvMR6I6G5s3nRVwPQ24Z1Tr2fQ7mNA1y+WSnBqQyznibpiEDSCFguQgG23Fi98U6os8IhLR8tOX3FE4C9cioHXOfbSE37uy+U86cofoKFJ0BNYvy+Jj2zuTwaPdofV9KrDWDogGh3G29ibBrIgsp2TMxZ84sVHspKDO6brnGzII+MEdIemcwAWSr7FLUfYjqbliuAFTvjCUirL8n74wBvoq4L4pUkbPRrKUvQCWNZ3JFCKKjsPexE24rcPPN+5BndrvlUsYLO/qrWrAzS3pcWdaX/fTMvKNSvZgyZ4EpK3E6a1M7RdrWO8y4bGPUxbVmkHozYc/UHKSeMGX1GUDtTYDe6zJmV5LK9np7gn1M3LPcNVQ8fz7Y+blkzN4lo49suT/4B//gFphlQE0B1xW7dlJjdrktWTbknu0AGtvnZ6zeRoLoJ+DMNtt6OPNMgdoO3CbzrQMyBq+y3kLHw5LjG6FFziraDoDuZIzyaNNul9XkjlKrsGa3eHcyNf5QcFaJqrnNgOmEUJuSCJe4L4vW+QPT8DjT9h5G7FVvYBVnRudcMwma5h1ibSZLFrch05DaM1uL8dIYsPgYcOKuGHTNB1YNDntOqWSZfLHCSEaFAdEgfJuCNkg0tdH2YmtBfBvgfrRg6PuxqASMjRR1jg7KJuDxlpdlbX4vsvKedtzA3B1MjZvdvc/VtLEuAWjMAM4wagyYClQ4DdF3oDDqrroBiRNkGOyPNZVsBylGdWTeM6MHYHCqnXMjkGOzSs1aL7qOR/ccrehMHPpxG3jnfq3VBmI7YKrB7N0HCzeZLg+q32lvbwTEJkAbLOCIGbAgP2UCj8/1PMb9eiFGboQhWmPi+JzarEkbAdOqk8OsmDWLWjlOOO634dMRHgQIZHLrtAB8bAmdLiJEvMFGnmD3W/TUy1HfszQxzzXjyjfPtK+ZVBEiaUQEYraJ/wIZfnT2rCSGmJrZNvCygtlbJoLeM5Kpf4LJsRpg64g2lCxhtKSVfnsBLzXafiZ1Yb6rBdswWYvl/YbtSr97O6kZ29SLBWdF2zBlJTKHpsYfZdxbh3Jf2TAuqyZwFurMbAVgV8xZAGT2GFDDA6zY1fTn1qVdsWa4m1G/aOYfRr80SKG5R27YLFrf8Mitvc8x+ywxZlmOWQsn3tWdaabY+NyytOLK7kxPzaSN3ZKdnBk1x8w2dvmPADQ7scbPAqi3rNoGkCl4DcdICbGTz96kjKDjVLqksTNlZItfOpCSPLgswDowYeLCGD7TOfcmS7oaHCrVHpDbybdc5I2uaEveqw3+aWa1C5GkZrG2kTKm9nWIK3EJZLPMqURsJTk12y0HZGr0EaSMnt/1DQ9lmWEjHARyE/tYRwaJkEaQMnZhYw2yxhqg3aw/4273KiBx6ZQfR407qnljsDuIMjSpG3IreyI9Zoe/nYcB1KKczMMXJmWnMWerQT1JEuucVofO0GCdVeogxe/sUwxHs6E8Ccb/SZhy1CVgOWbmMgvrWIt1yWIlvsQcVj1Ea6/fIiap+owKqJPR6+ubjFxdc+OyLLkBqAgIuy+7uh4XTrNjANzObA+X1oBopmrCdEtKjzwJ0NobgTDbVahmrhA0KicM2XRjBAoKyrjOs4DpmGtmxJhl6WhsUmK73A07AWe2yhNDfZmtpAqIaLFKYdK7vfGIn/nUZEDMtSY0y6lk+s03DoyKKoeEkYDJKKK7/Wmg/A347WfMGq4nLI6HanPvJzVguF3Xgp3WiRVixfRzWef3ZYxcGHeGHnwSwQ6V7fqrhlqo9MDW8UdmzbzO8UquN+ufFZApSFsGbK/6CXbh8vhMFu057/EY0/bXDfjTzfzDNmEkYjXlnhTXUoKrv/sMFz6/NWapvE/nKSiRz2dh075xZFzaQiCuCrhzlv8p4CLgk9rln0gbnw3CHpE8Xljqb9m7xNbezYwBGqierNq9Uv7W57VDeCZXdJJPmk7vAExy0JaaspN5peoAJN0i1JExgLFBj57f/fyIBFIaRJkkeSjxNQAZd2w17oq/aOL2sCTg9s62ujLqDgiVOCg9rK6MQ38pVN9yFydnPx7VV91mkkmUw7YVaqynZQoPK0kQ1ccxCiFdxJNI88wsEVzGBI2kw2u2LRbMM8F2pO/Ft3dg6JHt4g2S1N5SBNu35B9fbjWHrGc7swRyP3f/r+PeJnorlqAAF7qGHBdVNweVMJL0MWOaUkanJJxWr+XEprbMQr5ZpSmG0uS5bAgS3Ro91JnFoIKySBlz09pUFUg5y7voL8vtJUccWOGMb58qU0i5Hyw6QUIAWpCICo+wWuUj+n8AYhuZ7Mxio992ABXA00s4bov74sJeab7ZA/VfZ+/PWDCUa8ZsGHp0oNaYsVLOHRehr72u7L5Pvfwg+Fkp60XzOzA7NNvsqu5sA8oUwL2pqyOwr0v7lJi2GxwvJzDb/fPMXNVjq8G9rffA7F1nzHASKK2gSBkrxDyxpf6rgQZw1pYANDuOIzBqND2V010ALBf2jOvZHpL07UKoeXlpixP4TEGgBktvDESM6sY6kGXGzDqjpvPErTFY5GMNoF7OKdeS8Xs6bk6MWgfudYh/HEt5lPnGjV7c5dn0wyh4ehiCeMxjXsw/kGAc5ERXas+9Y5zUppxkZOtOkB4DYvxhhC5xm4L6xSYfAtjoPlulMI6LeNRqf7tjsX6nLvCJfRXvwKsAwyK/eypWmm8y/skVaGwKEiSAEvfbAVlNnjw9XcNQowmgR1EYzINoYzImhFUDWOgmFTVHXr5jvsTIY8GFK0vlCyicvwbr7SZQYqEuTOAKM3/Gx4EYRF+NzqPdxwOZ1YlxRdzZWJHkpJbh0vM4yFEXZiy4bO6wcHLsbJhfTgaNTS1ANYOehYwrs1WUeiGwVdjq8iZUDYOyVTagNYJZ1hqnioE4vg7Epnwxqxq7BcB1w42WBpBEWMekshiCkEHpFIRJzFfq/bbJaB6A7JhqQKuRqCx0ny625pOZrQTn9kqW0OllRwvowZAxZoI+xw53kHNQbdqtwvB/ht9+61oL9ki92NNrMGK36JAYasvKWjO21IvdVoAWXm+TIawJMAMxhiSJdLdZG14jKFMD4iF3bI/NwwWU2cw6W+rONgAsc3Pc1qX5SXzoW2TUHmHawjKGP+VAfQI+XB/+dmXpm8hr5oT3wOwd+rer6dq4MS61Ytl3ugvXBry5hDwHx0FWHlDGmS73qF3+IrXU942dW/LPkNeTndWaXQKwMzOR5P0i5zSz0mrOhuyz1rtokCiyhTXkfVJQ+YzrhOvcAMmFk2FH633examasEpQ+HX8Utu9vk2viekHDgmlRDQtrCJh3GUzG3Kjw/MDIR9G4Yy4MdYuWeRatNa62ovl7P4ahgoxw6b5qQKuQ0tusq5OJmfjaTGFyoNlu0kCGQYg0xozD8JFBGBmwzxfQRqgxvu2JKR5CiVNBpKeTSB9mmzTybr1BuaB3avp8vV1N5mAmfr2duXND/jFJFvAi7/eyVPW+/KpnxU2EWMG28sag+mHgjJfuL8IZAuQcFbW7OttALIyXBknqeeLxUclqaKNgOmV7fHAmsX8Mkt5O1vYMzXiCKHSHH1LLGTwyihCPBE1ONIKiKxk48wTqLQ+jORzOiCn2uCClUHLrCXv4KtpRBrqKLzDN4fjr186H57VkZ2xXHiQATutIdN6MVut7sefUYq3WGwyFVpLZBC93MFWwRIqvbBbvrozutjnZ8xZypbZWq4dKgVeE1xlQhU8CK4eBmFI1/uf2l3U+tG8QJ/TlcukQPb2gZnWhL2FHLO32r53yegjW+4MmNVaR55Mf891U6CAZ1DtltR5Oa+H16tGFcdx0I3emJEKepHEmTAFhDsAxyBKGC3fMX/UlgxoPvoezd4+AKRNGzlgujBQ4xq9TlY1aePROq5l3OOIedP3zEIog0dt4b6d9jaqLDOGZae5gCicsxFwj14AgYyvEZRxJNgyKubpCFPKoEHaZNktzh/p6HnSU9FsMQFtqcWkMF2L2N3XfCwn1MkUoEabuCeaBo4M9sBT5ZINNby3YetRw7JOfFe0ZvETiWLPLtsd8j5PgdnzH0jZCCKaq6KdLXE+CPnM9eQJXA+Pktyt5S+/mfExeAvH7y0smy6yhKu93mr0CEgvPB0/VmDWTT8GXeNagoXo3Ifo0LoJjbPAi50BDBP4dIdZR5juZAqCZghy/+TBmXFFSNF4XyvakEIdHYJbCCffMFGSX2aszyzSv2/4IDP/sJQh3GfApQyfYMbQt9Vcs97gYidbKkA5JGy6s0ed9cL/Fbj9bvjNFhYLVzVj5QF2rCQ1ZJozJm6Lo1aMc8mK1JQRK7YDanVXU8YA0YbwozNltQiLZXFskvPMOkA7xAjkEGB3JEAvlTRe5KDpd05z0t4A1F1Z8yfzDgD/NwdwN//IHgzMnGUjtJZ05fw9Y/au/WMwxPVJnaThMOJpEBhYMFeTEDIKAa0HBOSGfLEzPw1U9dt1t8cfy7R2VGXIQG6N3L62DyZgBxuwhM1yp1b5ff/O3iMJeE4cIblmi8O1O2PGbFeXKXYjFg7pvrFMtNehtX83Cuy+IRqpBNt7NvtoC9x276ndN7oT3NLMYye1DyvtetTXrSG6Shb6ZQVnfWBSMcsYOZM8ZsYxbpG9A8msXKaHf+omx7dMQ3RbREINQnSYnKCd2lLZJmCFCuo0rZtZM5WNpTIGrgpjg3qE92zdwW6MHW7dEsZs9+iyBuW4Fm2KDJ2Yhe7kGGV4CzDbkirZcfBzHomt2bst/hlT5Jvtu4uzJUJJdjDTTGRuWzlk8gz2tcucgrO8Hm/tbVsIJ7i0WT5hqzY1YRtzmnC0wkG6qvlTjnVdxOHpKkL9WtDEqcGHr2YfQTnkkTqyZNoWoGWX8ZREruAsGoaoa6GTlUif6onZhwnMscSz0E/YXwh26QHP4WdlAuDUM0Nt9Mknoh/GYH4i+HgHzrABZ1uDJ1i0xl8SsjdrH/RfZ8mOdXn7AgD8p/dbWcFdmvhA3VdgtG4ny902nxXcGQG2jCm7MPWoBLisrGdAWbx+HNo2/UauyEYDq7aRFvr6p6zZIazZAtQgBiEZg2bnBmKpcYjta9Sem532yHfp+zcD/jruV9GH+8FGLZLcSQfsMwWkPvdSxgup4iQ6TqSEAuoCEDGzADSImarKrHWA189NUie1DK5LOPJDzBpy18blPda8sQUUCpBaHBvp+HnmkijultaNOFrH1Aj0cs0epG1BvohZC3ZqWrK5Rp41oA/yJbTNmM4AO4XIHtLMWQNfA7+wJ3t3ZaSbapA0IrJiISLME8d5T/p/dsJWcNioC0CrPtGlmn2Egrlj+kOPHcG6I6q7GHEDZDLCyJJdI5mS3HRLI8OlNhy9rowzy6Klx6wts2GJH70aszqzGCod44adWuML8Hh9xuzz8e/d8gb5VrfmDbbHjJmRCUihmrL0T2zzh/lO7sYYmep4q5kGHi5SRlvASFZfdt9iWXg0DwBsl2u23h1KAtBODT8ylgzkwggsqMrYEKTSdN9Y5ZN5JjZMmZ3cxotlfj+cPG+b4E1xLuEQ6ZK4lwRJIn4UsP8Yfvv7Amg6Y8qCO2NZma4AuLhmbAfWblITdovGHp2GKicMGeSzE2BbzD66i4vN8cYSa8QelTKydX5Vq/0zI5AHbPVT02c7AWVYUzjPXB35+8DjcsbN+n/Ygf9fA2YfrCDMN1qTXecmMmrvgdlnAJgpoEIMEl7AFlbb/EXm2NdBnauxTK21sqU+AT0GDlXXL7JD38xXqd4AYgJq7Io9e2QaSzUT6/zQwTwzMUmYQVeQRHb6zuyabpP/1PBFgGrW+V3A+CUw82SMnTFMJm/k2rNMASj1aJVKvBbgpTlllVzO9Y448qBwYTUvrJn7BnUmNvpwKaij+V3KCKxIEgniVHvJ4PIoidkWg6Z3DwEAi1SRGZdeMVYW/ovBmwXIBqlWm3Ozre8/BZ6r1nP52mtpEHOnytnP9qSueuccc7ZNFTA+50aN11QSJvs28svszbbzVhq7/9ZiaS4T4vI72aZOd6S65JLQNAv4ctHRcfqxJwDFl/NgGxCx2n9MBrPIfm1gAAGzWXl23/cbog4TG3A2a84KCg3a5G6ufDOxbCCeQNZCPJU5+BZAWonAzCjrmyPmtjiZmDXttqaurByiOZyCWNfOlKCtDoxDvpg4mwyHRXwEt798B2aPGHiUE3v7kgdBd8BWNq6K3dijUiB0ZuhRNwyZZpQtJh+0z8LIDWOuVj+eZpLtpIwUNj1yzTwHZUdb10Fs2nECzLKY0AyMqUEIcC1zvJQ92mvJIP8S7m6MeIJ9OG+GS6C0Cz/MTla0jIEDUd/nmL1D/5hxEvCQTVtqrBh0NUCSfo8ZN3YbtJFwisKyPAZmmM76Z2CKQZ5TO+wMUHUgk9TQvY6JxwCHmZRxU0cWHBOVQfMVCd3a/oHkiRnoC2CamUaqSwtSSgXQSOSO3KOR6USu3Y2lw4CkxzoEF9yyRBdpKEnvJzTmrGOZKkpAfgio+g88CmfxlfGLuuDHQSiPyG50Fjk8usyCOHZiHGMLWcC0R0CmriUVD1YU26bYI0OcLFuM9+/VBMQCeOvcVwk5ZiZSxvXRw/HWGPYhbAYSu4LTjzCaf5zaz7tkai3LZdKOdVqwInEXoEuU7BmDQ9dLZmzymDn/DmzveSILtuDJ89m3AsCH0wL65bYoRmkl5x4ctkhVU/Ekn0/3FLQzH4UNT7UeIJb+ao4ZorxNZY6e0ESho68j05aMZkdpownktADRMut8Bm6cOja5pm4uEpeyAM5sYfAyO43V+CM1LlTHQzUD4ZzmrO7MJ8YpctghKtNCtvkaXQHBy0ooOMvqR7gaJBkbskPCjjFgG5/J2cSadPH+7weA8t8bQOZZdva3Z0gfhTULtWLW2LasXszW9535qpZb4BshagZvdP1VFwmj56AsPOZcasb72KXP9x2cuQC0nalIahKCE3OQkwy05amWDArjARYMz2DN5jV0//cE/4A6H9mz3TbF8Nq6cRP6XDFm75LRR7bcWcD0FYsm9VEAyRczkwwCBZml/qgJI9DDdvvBgl6B4Q5wSRsVCJmaYBAasWz/MxmgsmRyHHYMmSWSy7T/wkCu57tNo0Ybph7dxbKHQG9kkgvg4kBpPV4KxpJ7hiXTymGEVyDujHK34UxmrivzWzIExQyZrcYf4b1v8Ixm2fDIao031qVfpX77WVaZyzyTojnzu5RxdLgrPRFq8qRi0JXdvZMdujCFmNHLs+PKFvl1CBMnG5a7M7LCtJKUMSJrtQrRyjYFjnW00+L5q/UzE+P1xv8esrD353zhU2vPZyleLX/ql2j9V1xMQGwTPu0rEOc0Y0d6jkygF4sGS+OrDqhc0ci6A8N3sVJCmadxzOtnF+dF23obYgA7PcNFUPoCyLJCur5smSoFa0WqoWSLcsuMTkcp8ZQAed63ZSSflpJBqLTUuSRZeJAOzJrVKREcN+3BmAHA/wNePoLfvpzb2Yt9fbCzL7nBhxp6uLBfQarYv28RrGXZZcyKHe2EWEJrMjgsbI9/34aX5nXCDBfZ3vuFlHGwZZgyxiFprK1+jNi3Y2elj6QO7YQ5qxdujVvGLRlPZuBWpQ9S7QLwxb8PAPw/JzDDB1grOi/ECNnw5fxJvJcyvkP/BHAFtktZIVBdl7oq7uqVlJURIMid/6W+igOnxWBEa6g8Ya4gEktj8Kd1Y5Bas0R+aFlotW5HwN8pyGXHx4St6yD0ANWrsalJaz/nmJkwk2koOAO11s560s7hvqg1hrvrCNECQwhznFbIcm2YiV97IKdqtN5lpV/l0fwq5Vk2F/ISsYzZqkZcB6MSOY+RvpIHsWpt8hEQk6bujFW0l62B6R3bozlIAIojyEkQMBKRlG/5hhV5O71OgFZHLcy07yhhLbtUNCxrzQMLXMRo93/Ha9SYbSHqG+sJ6fPWZRDYBXu/7k64KrHs9XfMRdHllkRwPbC/ezHo83dypxydh/KMEbbXO81m0Y990DWdTcNqCrLYA9KWWP64ESqCasgcuetgjSTTAGgVGjBtAszWCi0Xsw+T+rMMlDi1d7HL3xR0LaYemsdcCIj1aJSOYXwuB5psFvcGto18XjPOLkcbQBbwPtmvsJPMoLHfP+2MtQyzkGM3gNl/Arf/CH77pXu26/Y8a/v+OYCvQqOW4pxotjf4wKwJm1b3G/OPpaZMXBkbUBsgq07CznVQ1VYwk0kZncw/+P221uwsgNrOa81U0qgg7jLXzF7PFORMDOOG/wDAX53AzH68m18/LntwofbHlst7YPaO/dN6oiswwWDrBJgp2FoARwKOkMj2ilje1xPWKV0nojzPHjQ42QKpDXumeWhbYJbJJXeGHA2U3ogh7L+uQnLGvl4+Vp44UPpu3/t3Ie6QYGliwjyqEQu9lnDDEbYsSAVdlEXMiglF4930qsrNkPwz+q0nlGn5avZxp2hjz825LbsOIXfzTKjAwV6RdPFQLabspPnUY/IwH7CpIDbaIbnpcmK3m+h4xi+edsuIL1tv4dMf0YPYsCxNm5JGyxNjgtnHypIxk1epKsiCM+Mdm1ZsxgZOU68864i7qypwXduSM33iVLhtly8Szdehp8LvhgfG4u02aee5K6PLiEpdBiJm/Y219+7rgfPlsPlDx3VCFAld8JPGuh5b5Bpko306vWCK9Ow9FjhxPRk0UDphXewsTNCFoTojmBgWMZSyBRdyjllWxWbbaZOry2WN999reeCKZWYq7JjIHE3RpiDSKzt8xsKKkyGnMeuOLvfvfs9O6T+s6DKkaEsdWmjNE5/2PwIvv3SpD9uxZkZW+OqaWMTWnk09TOvNEgZtZ32vACyrJ0tryuKfu42asmDSlWWPJbE3y6tH6/zOoAVnRg2bThwbj4xFSxiwnZzxSgKZ1qUlgO3Z1vuGP8y/tSf41+89mCLWzNtRKk/u1AHzfK5yzH4SADOVtZ0yMBvW7XJea4uCtirtVHmhJ9u1HZDi74h8L3t9jn1+odBn/qzHNZUvJu6RYRoDWgJsAXC1+TVzzsykjBBpJzY1YwnAXpbziNLvUka5M1RP+mPdebHdwEMSGiJb1rEMl2UddQ2SXgAZonwxzGc2rW6ex9zpdtJnjtBoSM1Zdpslu3yvVNNA1F3lRoKqlumAVaz1ZEoZ9qec5bAk2ib4ZrTOEwjlweyj0qh9N8C3wac5OTM6SRvncVnBSrfSBwG4CNIcwHHUpdN9CXTO0NDACbavudoVSj2AslJj/gfR2c7g2C+adbWSLFUgg0ixY65GMsBZ+HNmuL8cPrEvt5Ox3pX39ctw7ecNxxZx1PATpwlPLPNB+rrEvCfpK2Xwaa0h676Kpc1zYsqixPgeXcFixwhjPFStlQTu9XatAdPqJem4Bl+yM0EFGJrm8trNP2xzSpAnGZi875dssQ27zIVyrhTgzu9RmLNQe1YQrYNLBGbAD8DtXwbK00NM2PYz1X2VE1aNmTJ2UMyMPVJmzFaApvVomVeot9qysj53U1Zr9+eROfMaGTSWNPozmbOFAbsAZqeyROSujM8299gzbS8B/FAEZvjb13fLx++o7xmzzxgwOwE4wOrImNWV4UQaGTLPpN4rVPYI0+YPbD9towRFY8O0DUMQnoc8/0xZOB/uGsm8pB2nDo8JEC2ItvhV5kFYLCQsmDHbJSAVm+OpNWVZbdl0hzzpJzGpFD7T/AWUFWHXapQcKJbjuC+XzDTuMyExU9vmVcHWyl4Tu0gTgGaSW9ZrEQbLVQV0bbSZTAUuO8Y5A74Rb1ngyUwMP9jGe9pzWBAiqgNjxMyV4NMK9Rio7WrMMiOH2CpLHEMTNz5xJRzzHXC7ilxe17daNazbSeV3J06BW0mkrEydBx+SB75JMPN5aWJUyuJaTBiMFB07p+YYzL0xADTsDCf3UdsexHjANvunlAi62Je9YJ1nnigAOUoDa/B0GAwxMqHZQwCWK/ow++gsdQbUOFg6lzPaeOVw6VXOaCGA/uK3kPQJLcM2RW5Vm+Roy5wYXZSmTmaaiZkin4PtgBsDwrRje8KajTyXDlpkFDHWmAHAX4Pbv49afmlgvZj5Mq4/S9wW1b0xY8p2WWTW3DkXYGbCjBVqu7BjMKwB0iSf9DKzRJkxq6vs0M9YqUTKWMU6P4ROo20LFD59xpg1Vu1I3mc1Z1cGIaeWV7apPTthzzyCwT8L4D8XYIZzm3x/9ijV5wqYvUtGH9lyGQg7A2bPAG2prBHR6n2ACAJiaviBrA5M2a8M8GxYtS17psxaYvt/KXU8ywg7CZxeJJAZKJPj0MFraTlvdRMdoJJG2+WSnZ3fZ/6zrYzM423DqKzKE4ZM71Z+zIFOLiQOeKWu2IY70FArf6nRt0yVloUJZ3DVtWhOXE7GK0kcvYqHbo20HxiBeo4o/YiyNt+HSnoidXMCZx0SxLqxtfYMyHTz2WOqLkb9vqwFoRtoFIbrVBlXa012y9ewZm/7YZOz6sQxk7ujH+0W2lGD4q51osnNzTtItsiqenD7a9ugdXUZYGSlGBp3JsnHYEWF3e3tfUKQMdjvK86psLvF/wlDZq35DGtGxVNtbYbJiMl9g7HdJufWFsFMkAjzcSagF3LrPLrmWTuuw5kz1FQWAvdxDIc9Rp1sKvvxBW9zFDEJvWJC8aXaPYh7owKyiBQ01nlHxUZI6Zi1YXFt83Y5HRmdQqY9kTMya7YbOpitjm3HZtgnHagvsxIm2L8dCXNG9/6RXMBOjDeqqjEx/LB4yJd5vrmP4wyUCSCzrKAOs+jNLaECAzCrcPvD8PJLn11jFurEkryxQjlkrvPKrBsbrJg4LgY7fCNWTti2DshKmcoPjzb5ztJFck/Uv0wWONJiELPMsrDpUGuGx+rNwmN2l3N24tyY1aE9WqP2GkxZ//tDbRxUgNlOVu8PSgneB0x/1hmzEKyM1azjSrqowGoBbrJeILo07taVsl1qwKHLZ4CJQqzZ6n73qmDw4XnCLPVlOYsMyfdNXBQ7y+jdJKXLKMk+P8gLxdBk+/rovOROEKSM/WbKd66eueqJ6i/MOxIpDNUi9OJxdZZncMaOTmw8smSdQSLCPFFgsxyJGTEGYZYxRQS8RrV7pQd412UWeoKxjkPe645ADENgkolWF3bAAxiKNWa5hHE6M7LhQKXPs1PoiV1+DQLItcYsL6Feubr7fykwU00c79VZjdFYMgoOd/g7fb5t1Xyrn/0jSkitFAs/rqQmTAV+deE4NtuSCU4gZSnV8tPdkrFaj8d6x5Ql6zs7tOt+T31vlDXOY1CXS4QjD2RrQcroK2OmrJmVxKFRkIEMUaU1UAtIw+C0mBlTxd9NOntlTCvj2xYcGJk521dtrdLGlfZyYcMWy/suC+9mhSAipt9CdYdkmk2+ZjBjhXxY2KfFFIiR7wq735sTMQoebMh0l8m+G4Ovfg34vMdbR6E3uv896c/0B+Hlfwq/fTFmjWkG2S0JgS4rwzZeJYfsNJOs7e8hBh8QeaInrBgiOzbb1dgyzSyrJDMsK2DahjyDABmiVb4LQKt1X2uWujRe5ZxZrCTYZaClbX4gC83tsbq0Nv1DGP6YXkRPZ1R1/vTayCP80wE+73PM3j4wUykbAxmzKCeiz4v8rc/j72zMMExABZg1m94aww0yMx+x7lhoZpIP6yqBPAVRmHlprEzcvQLimsjLKHjsJiG7OrYzR8y2f8r2GYMxAczsMKnCwNpq4ap+py/D32nLjvVkElIGZovgzESChKj2q6z+APaWRzb3oHpuXOhSCsvZZUxccclspkpa72M6aiq2+YvuK9FjWo0jquNJwxTgRhPBQGwMLZIBRG/H0kYXCCXsUoBJFhwY47xZCTZrzFzKSHbl0CCA5inwsmD+4EKz22TMviX/NCkie/ZtBF3PqXW6WPYzZUNPFN6zyvEerRX81NrdgNkAZWTkoA4URXLKdpLGE8FfFBUj8Fpq9sHsH8Mm0DwPdxjOMbuNtdim7owloJqelmfTqUHGRtIoVvYQTAPFQ1Rb5lRjVgDcOGwaa6Rcodo2ttEfA3nyhDJkrp+alr2pLRuUnxbPlTjCmEsZAeD/Dbf/EF5+SWDDygVT5hvjDmXDQh6ZgC79rjJxEDdGzS3L7PIxbfIHYOoEGht+lFXO6Dug40mdmTJmkm3Wwdlprdmu3mxTd7bILDMm7KxO7oxV2zBnybz/AMB/tgCz78G98ixT9QAXgIzUOAXAFwD8F+8Zs3frWXohTdwAhUwqtwAJlSkmboVaI8XrLQlT1jtmTuBpTEvMNXZsHDKwubHkv/yT9Wk79Hg+ZFByEhHA7CAvG0Ki2/6zO2Mhdq7b7DtWx8XBvvF3nvn7WH1cPRmF7zImzzk45+ccEVVG0V8HchPDtFxLwJmST7uR/EW2OFKxxb882EoywiSBFadn99A0L2IbaclOMHOW0TRC+23FSZnxR9zBeDoUtNXBoGXH/Kz0OZMzulS1YQGNcUoYFAKCRG2AP6rzmRiqyQHRZY4+v0bAwIkvWGKMlzQYLpIha087cYhMQIiRVBK9bb5RVFFtjg9qq4iFvC+RxkjtMiJE8M28rb9g8JmZ+7/W6DVFgk/wFocJ+MA6qeBODFnGgMg8zxVZCZvTbesk4lqljIs9vs9O+QLObMqRO5OS1LJFAW1kyWKemJPIsV+P3gAWyxcj3JrTMufFLGA6WoxYwhLxNBdhZdHr2sh8u65ElOUp2fN7hC3KbZNQILh54fOKADACbvAkNiWAMUfqj8lATW30mUXzLiVkqPyEhMr/vfDyx1MGbNSZCWDrtWaaQbZ8vuWui9hY3iNzXzxxXsRaU9YllJUGQIMjo9jku+1rtwKA4TxSrTEjZ8YuZzw6u1YSxsySPLOEMTt2LNoDn3d2+XUDwHZDmGK9/3uzW9/TT8NGBvLI8JbIHsp7YPZZYcy2NvnMoCUs2ZV0Uc05dt/FZpoaWwzQR+BPl9P3gcFCrG/rx6QzWwvrl7CAanJS+PVMytgNT9gsBDObjBksZsoCIwmRRkJCpJNeeSppjIc3dV5U7vvstfhO2aV3npLMp/qyBet4lEewkaG6MgbDQnFqXPwWalJXFnrXicsDm3lUX+WMI0EVUlfW9XWUYxbE7XV1XGRWrAoarYnEEZ6ye9xJj6DHZFw8ExtaSCljAhPEmDkOYr/WkGlvRiEubBoCo5Zb+dc67a25Gi6CNYwCqmm4ZvDa68RmL41rtbrz4P0U+wB0DBhGGgGy7HWm+ud267hupM5q4Dhr4KXtucc957xi8wYkWt3Vfd4RqYFRjza3M77XrwCbmWFJQhWdoxWGjm+QxlDhPvH8ML/XePV9xZ2CH9JLo6Q6I1ElXyUsV2Xo4u33Y5h1aP2HHAWqFZrKhV4r6KJxy4Kki2aXqVtjod+bE9rg397cR4WuMerZBL/YNtus0rL3rdxIwti9HE2gYAmQL88xW45WaLeTZJC/ZiY4BohOjZtsszEQR9lmWmNWIIkFJqfJpA0yqGBZ7l5wBSlINRThi2UaPnUFhUldGbNKlorO/gQq/hJK+a+mjovbDDI7MfYok9EKNWTquChOi9k8tyhz5HaZrc6PpUQb+yKPr5O6r8xCviagjGM8lTGrNbJmAwzSKwMz39SchbozO5EuZs6M7Dz5AKN2lX3WlvmPDfhTKTD7bqwOuSzpt8zhzPJBW/tsAKm3ur53yegjW+45wOwN5qskUuvSMunkmZV95sRYBESUDmguQrSXejS2u7/6I3C1gKxEOsnyzLMMs0CFtFq7Zd/V1GNzvIaU0cwKMY5BY0fTPQoGA0izM0BGy5WqKj/yEXABaMa5YsQKuIK0GmUxXCMW3ObpZs7gDcjt9JXVy80/6NCo9786MQZ6j3bMTSQwZNihGo5+vbBeU9MoKzbFT5IBkI6XWTCd4M6whVqzCaUKuTJiFfNQjllf65HWk92XrdTFm915E34hdvj7/Uo63QysVEbG9BRhqXGO+47wGs1GmNd9uQl6OksXgU6NDnY7P3rj6KRWq+ORoeQ6sWiuJQI4A7zOOqa+/2Y1P+3GBWphxyOiHWCPxx8iRPNw9UzeqbbjfScxKZNCTcKs7SdnVCx9h3ZcrTOcNVj2W7iauktKN3yp6r9C4LTm/ZIgZSTw1YubFFhwg5HlX/k6T+SNfOxWWWMEXJmtRCzL6tdjGXb33qq0LAmYZnAGCZCewNekxbbEtQUm1SKjbHzpauB0WcUEpUzGjRMJuNxvQJ6SYGghX1m3EKYr9gqWqgmrHCi9voMkSzdxLuGte9ndgv9t1NvviS6Kt9WVcYAfcWLcZZJVZchsY32fJIA71ZbdCnBQ6HTfn1dSV1ZaZbETMPH53K0goEZg7EzK6H5imU9qGWXMHgqdTtwZA1NmiTujJtg8Ar4sly/WjWwxBW6G//0OVzx9Z6Jh4A5WpgCynQzoUwA+73PMPh3GDGvd1Q6QmSyU1WsttWedDarUAK7Xiiq9FYxdbGMJPL4P0nrGbgU53+u8qoQyMR/Bc9dLDN/RjwOzfnJerAEv7gFU6QkUknwCs/sBVaeQfNF2rBvWAhx+zAYpI3Ny7qs+zRPgwcYgXvL5FWuMV3Bi7Ou3eTNXiaPSgJA++tqLc5EueuKWKGNf2Q6EnSHDjiqgawfKFtCYSXOwo//Qve2iZDHueOQ+fHmIWNq8mV0WvzUfSx7YMSxCSBUy8mh/rccCyuIJTKyCE6AUgJln6ABIA6HZzjA9rll4smwiV+/tV7lRqFjoTO9zvSzdkyQcmdG254VfIfLJz5LMdu3YDN72Tn6V3e0yweTUhnXYxfTdsR7AzEjO6PHuGOSN3Kn3FfgiYawNNOxQhRuLlV2bxKxQg1ZWEUH7xdUmWMzNPMoCznZbK4Exc5LrMrsZTm+JjokggkdliwtjZtNXYtSY1Xv//4ZZN1YA3GzNK+tKUy75W0SZnFASrgsnosyTLLNNw0121IUtGw+wrU3DvwYv/zhq+btHiPTiwEiArW7yxtJMMsuli4eAr2CNX9ZpplJGW2WMXu6PryKAzEj4UaMzY30NKaO6M3pinR8kjXYO0C6BGTah1Lg2B8nq0TLjj9QgZM7/mwD+wBaYfcfKbUdg5uvNlkdTmFkLHq3vpYzvxL8ze3StGcvA0Y4VS+Yv03U4sdebKWOm8kXefsJQFWHEuE4qKzjQdZUGHJd1v8krSRwDo8fSRwFHxrVgxAgG6WWXRDY2rJK7ZOmSzCyHLLBbUgPYz0dSG3gGDvm3c6uWdNiUZNoRTjU5Q4RxhjN8kRu3RVdFflCk0kpPamctkmOLFNM2VNvo1ZY9gzbowRqtldn7fzzVkFcOnwG17H2iWTDElDnOVFJ+K2PG+BQdYZ4T73Yl3lgbahsTELbvd2+VabGkimpIiMux1vGt1HPrliXtUp74o8blmb8z44wPyeYiy/1+9NxEjhkvE68+mKAh3wsBYSQzDJPFPdZJ/thb7LSvztNqIwbmdIzaL88f2HUSuvOI2CByJ+BpZ01UvkYSGz5mjlleaTJ64yEDoDFcY5e6KqGxaOZD+ukkz6yVCJBKV5H1Y93ZRXrmWTmRKSJxZQTVnpXoPKGgjdhQNoOw5J1+mg+FQr8eH86oUeZ4CwYfsyqtkEQyC47WWlMsDF4EKvFS7bseDAv5NaP9NLOMnR2tEUdYM75dPputr+DfZ3ILXI+2rRSg28o4jwt2k5wddqDPu+26Xn8b1X4/rPy+Yd7B7FdgxBJrewVoWV1ZTQw9bGcwYsKuiY1+kok37PELMVuJhHFryPGolBGr+cfOOj8YgZQLA5ALS/2lJszWsOnwhMsy2R4wB9kAtf8lDN84B2ZZTWSWMplE9vAN8vMoZfwMMmap7PBBOeNpzdmu9ozaYnEz5/LFDiq0Fk2MRYKJRsKOFQYymMHSpdvQN6B2+opZU8bGGeO1sVnKpmXW+eoeqXVjC19CMsSiodhsjILXqDXL2DKRPWb1Z8GVkUuvqkeVzxaM1fz5B3IjrlUCKW19n4Gv4JFh0k4TuWW48OUB7tJDGR1RlTNyAVslFoCL5uSphAdAmVqOBWomuznbUi1kgZlabfMrYs5WrDMz3IRJM2HFdp5Ulvo+zrPEN4JKnFmXJt9/e3TS6tTY18GOTFDX57sT0PLaTulEE+NSNgKFtd6leQROfHRKPQISGKxpbiuZhrA8dpiWMNfV5X9h36eZRgBjzFrUKWUE5XN5oy+GNHKU5lUCJj7kkG6V+Jv7D4iZsXF4mcV0xm9TAgkqiQSdhwoPNKW5ickJf7GDtA6cO8Du95Aajnm/Fnrm2QBrI1vOWlt9SvWcZGxdysh0TOEwtX5ns03usO9zrpJuU5a9zKuNt74IkgoKgbMobXQkxg6LONKIac24ury1c9DExmkqBasPkhoZkj+G7QwNZSyrK0q7H8tNiMyAi22VNUJq0YKydFFAJGnYZvmOsJ1kv7d3Vqm0IAMn5syezrpffwBe/kfw8lODAYiXxA7/BIBlzBlOXsHW90VklyaMmbJlZTH8GEYfNDi6hEknwdKeSf98fRSGWrPsr04zEGXNfMOcHQLGjhMr/WMjazxeQ9KYZZclj/e/aYZ//ezCefqKbeQUj2gYpAiz3YTfNvCx98Ds7QEztbZXe/wELKTsGK+LpItO61LAtLRLtp0xN57Y5C+sVMKenQVjP0uuqLLFk6DtABxPDEkeCXkeElAzKxLEDdlHtoiyxqKVxD4/83h2YdEUNu0+F9+wUqMcxDfSIj9RBXqM5hryCJEx8khuTciltFLuSsIYQqRYAuZCifhaROcnOk1YzChjg4/OpLFLIzIJo0gZHwih8k3eVTwVmfOiy8g997Pi2KeT4YfugAcwuJvvQfAFOI5aW1/KxRGQk8rvjAozWeOCaZ2xyn2y4OeHCYaMuqSd3XIfIC1sko0wKEQ6cIGV1skOn2Pw0olFooBhLtQcAwrOaddJTRWnihn9Dqfm647R6jToIF7Mvd236RI1j9eGwYYK1/gYwBZWfJJnnJV2B7y20Iq0IxWo3YLfjWSBgNVugGJ0KL0B7MaGNlTpYx+xckTOAVmYtWZdP1fIvx2eFDbxSPTmfmYeGKps0TORYcF0DC2NQcMIgLfxW2RgxuJHDpzua/RLSePazfKkvaG/p5b4LcuqZGpJ/tmz23wlv4uVpwnOjIql///tfVvILVt61fjmv4PdURpiDFHwQfFBEPGSFx+8gdgm4kMSFTUqiCI+eCGtpsVoI4jp0w+dGIwk5KEDQZvGoN3BFyEXY3xQsQ9oR4OJIPGWRKOJ3VHsPjG95ufDqjnn+Mb8ZlWt/3LOf87eC/b+16VWrapZVbPmmGN8Y0QxppSQWTJY7FZVWFNsKVgDWVBuAK2zZoVWtQvMPg3Ht6CWDx4ae/Rw6O33W6C0ieFHxqbZqtbM4msIQ1YobDrJL+vSwkKyQpYwboqWhuM03HmXNfL5by9fkBqzysYjlG02gcMNTPkec4bzdvqZ0cdRMPXePhOL+DcB/Ow+MFswZpM8H6uh3TQseO45Zo8ap/KcjD6y5TIQkNjfp/VmC0A2SRxbzlYiZbSdPKxJspeBJZAlfLL+FCgxICG7/n5ururXdiR9rmBztWwzCQGkiI40Si0PjTPZeH95AoHkhiZAql+1jRkUB0u1xDcGxALIAo2ZXMNlAo4KaWjcUl1mTbOcMlKGuNot19w5yV202gzU1ChEiCclvVJbrz5CJRamL1RHIcPkYlLjDdxt3tGgx4wzWcPbn/SZWKgDg0zBBY1KiDCQmnwEsw2sasniz8YcswzGMYaP8kYTuLeIV270cKxZhOpP4wC/sTVuM4D1LpdjFoqsUDxCxWbzEdw1sgkG9wkG899JhKA1l0HcWYPUb0gHGtPmOxi8OTLGAOaG5EgaIdtKE0Q0WaGgxqkhPdNs7s0lYISgJ3eVdD7hKstE5Hg9OneGZ06VdxMoc4QWNWXCbGFWmOnoIM4T2ay1HQz9s3QzF97KxNmxiPlHvBJHnhm6IUj8fAZlHiZC1LSkTAb/nvHzC6IpU/wxWeUlsl0ahx2aGnMJYAoWkWSWLaf1/XjBoKdMkKYiU39xNET8dtTytbCt1ixY5N+DIasWwZVnbFhSY+ayLDNkhaMAxj++bXVARhb5HRzVHSkj5F6uUZ4iZXSpN2Pr/FBzVndqzWyYklTMDNrl6C8WVvtIjENwm0FIBX7SDR85OmlevJvdcqS4lv/qdexyjrrv9k3PieF6sxJMnyVjtscmJcBsj3nCChytWKVbQSMDKgpKBgclU22Wi9wx1HQpawakk5v6tyRsEZ+XLn+rgEPXbDHeZpYZ+kCLtsMxgZg73xjHrH7Mk6mULlEkqeJy2XTEyVLGSATMS7m4yNsOQyY2+QYpy7K1GUjlmwZi6UD/mboYZaQTTJwl5vPONOtITywnbev9QzV8pslEbtXEDVkTSWN4rrrMKuBsNitQsrLScNGnIOnZYWZIGS/IVfUXrIvksqnseXhbaw3Szc7UuEUDDPausA0Pi+RzkhfuMKW9HdT1gvm8yWhCXUBsk/RXcv1cmHfYJkL0eXDYebDE/XhTTC9NLnx34FnjknZlpUD7Zwx2onn+nIPGdqxy7o02IGDk6heKybjF0vcFxpBLJbYYgolI7ru4rbHcRf1coYRj09e+r0MUZhI2d9S5lNEmWNXaupDMtNBEygAwJlLGwZQNM4/xC2w54lI7ZiR1zJ1oMJtQsmEhBKMog0Z9aymxq2yyxsCUyaG4SwAbWMZoc9tmQq9BqcttndFjsJXcNrawy65a5OvN7u5oCPa/rqzZ3TcEQ4/MwCMFZsSSXUSyuAqtdgZwEhptGh6d1JdtEuRLIYBkUc64JyOsdqL+ClJ2jTlo2hWs1SR0mreNwdhRzRmSejObgeRlD2RiYbefSTlxni0DgBe/CBpoKfbXNs+GmeUzzk8kZXxVY/ZAYNbImgbS+HV7nrFRzGxtuV9O8sXGwDjXVyEaWHSA1b6vDNnw35jNP5osj4APNgOMzg6RHJLBTpXdYNfGSlK/ti2tVo3/gpiq1WfhPamBw2bs0ZehWjTUWsu2Oyn4o98pWpum9WVhDn2TMJKUMZMoTp8l7oy7wMwtGQR62h9E9dWKlrFYrtUDK0GO8oRJXNRi4fd8dmH0mty51d5xspbD7NAobAUqI8sF8tRe24UChOXSTh0EMoNi+1JGlQ3mdXieIv94WAbLZhn6hh/MIxxtY9y6BswOoocX40mSs6WZCCv4wr+XuRsOlqcDl2Q1RrDEJ89+T08tP7Ffg7EbZvuryJq0qWzHGXLSMVhk2xLFjPl+oLYkeh9KiM08nNa9Pi6ZLjJSfnq38cfSabJPPTRrfKVptDjJhDWDjPS5+EnATMrm5KI5GhKXXhdXSBhcpuvUkhozriuLg22WMWZujZbOQ+4QSU1MwPnKl/1SreDC6FKmiyhdZFkjFmxaQW6eGc5NqLzRF9ezFsAJtQeXz2jHzQmQ3Z25BL8Nbn8ItfzaUVd2N8sRU2B2F/ecXRn3XBiL1prJsktAd2XQumSwxMnPajFYOtSYIakxs9zjSkFZB2RIDEBq8nwDaBePFv1nXBrTMOqEMasJSMvq0XhashK4uyBKHh34IRzUlg3GLGH4cxp4h6dHKMV4BcyeJ2uWyhIVQCUujUFGKHK5bP2JafSQ5OnYpNZqmqMlZiCZdXzKumm9G29nA3MtWFrWYwRMgVgbduoz3hbaDgZrpmB4xdDpOhvAI0A5gc6E3SsYtWpFjquO+JkcqapcSc8pgWomeMU5q4yNCpEDsz6BKe9puCPLFftOaB2aWCaz9bova2enUbDsgMfioU4F3lGTFUx6zYYKJw2mzYnZweffDiz0VzxUZDx8Ibhb5YEbslBplzqzmSnL680yP6rsJDS5ng9A2bItXNR2fvBFha62BpUuv+CZsWeThzrVVfkhPF2VBsCV3PW8zPCoqRwz2st+R1wg8w0XO3W6rkOC14lztbfapNb0oEo1umi9h3NHFtjS4EI6Xlaiu4RaAhZymiiAFMbtDI7ybtJOSIeUDQPWtWcxa8yCO2P2zwJQ8+W2eDqpYnmA8zwPElGUL+zygamEi5uZ2bI8SiAvGzaZfLD0UNn6EHp2A7NRMBcYN8spQrw4cwl+Gm5/EbV8T1prhkVeGTNmarO/NP/gmjKbWbIWMA2tLRuyxg6ciDELDBm5MrrFurKpxgw7dvmYw6XDPVyCpqfXZAaSMWYteNpxgtU7WXc2lVcgrznLlnfD+wD871PA7Au3C2PVoXPAdJqU4pNQ4rFzzMLWvcoxux2UnZUTnjWn2LHHn0AUkzFZjhlIZsegStwj1ap/AkPy+4W2qTJb6O6BAWQ2j/8yGyi29GCgyfVjBLpSV0oCgauQ7Qzs9Vwyqh3T9mnvFdpu8PJ07nf2sdOL23JcXybbH60d3ctkly9lRj0OSrk5ho6ik3PCMSB5QgNaF09CKpVF4/wyZfs56ygNaLTcYKPNjtdExuhaX4UZ63qJVvls/gFIyHTmdJKOnVIRD9evMEhTa/yxKgsyxirDjoosYLqm6NrTz5QtWiFNmuRJClviYCwewOUMgnzgh4Nlz0d92Ls/6gY62dvLVrrl5x2fYzs/7Mo+2z5utRND8QnGbBpKX64h2Y8AjA1Hu5x+7tIG7PCvOT6KWm3WY0+bz4wZm3vcmdA2JE8MIE3Bs0tdKsc2N6fR+N4KcGj1VwNqTepYwpRHAXqaGZuAFFkbM4ZR2jgmbbDZ7c98eOYxMIVPcy0ZFgHT9NxLJB4zUV3GjGVgtZzj+zBVLFhm7lEjzdfMYno/r1ULvIMvzg7Fvh9u341avjoFZivmzJIcsiyTzJMQaS+JsQfVkpVh9NHAmbvh0mJr2u2qDpbMJVi6HoCeVcDyxJYpU4bcBGRVa3a5LFizxE7/Itt42fsLykBbALajOrPtVv9dMPzTsyfLi3fzyM1kosjWMxRvY8bsUc0/npPRR7bcDcBslV82CWz2lktqnTLjD0h+WWfjEqt7F4MNFuGwZI8Dn0PI9NYOdZNFYmOl+lxCey5/Ie+1/ZNCjS651LapCfgK1vNqlS9Sz+VEu3rgCxhr65qWXwGuE5zMLGU8ICZcWCoTiqYbfjh9ziVcFBp9IRduT2RZzII5GRkocwauYTtiX2zu2MaPaZp2Rm0R6mTLKbYU73pNp7uYz8Vyimd2Gl6N8Q3r5HDmirKfYtv8UQ9Tt+F3DWtQnk5/zXfrzSZ2f3kmukc2Y8VzrXp7v9ddYo3wprJQj8ydr4Df8vf81MY57HBRvwmwZReUr2m9sw1e51N52SSes5Tr97LvWd6UpcxooBAobsANSRFTYIecsq4gNWYm8MXo3fF8ODCODW05Zu3YajRYwcouH5MbY5QzjnjZaKGP8HlWGyeXWipbDPVnFuMbO7aB9P9lBqcrkJbt2S2s5C5faS2psQhzRnJH0yOg5eangVmF48+hlt+NYu+61oCp66ICM3FaNJMQ6DLQSMacgTLLphbWurJRW9bruxmQsfFHFXdGo7KDhV1+FqqydGVcWefX2Qyk8nsYc6CHtWY7TFmWc+YnQZnnrz+7sWWnbz8dmC07Pdt5X2+ap+ca31Jg9lKZf2SGGjoQkjqzFHytwNyKYeJlpQYNCWjjbbHEan5i5Whd5YRLIzNRKi9U4MTuicv3st/KmMHEAbOTbJIjVzDbZEDBqYRpt3avG6OWaepWA2DXuj+5uveuE6t70/kMwHxWBE5qwHbTr7GrSd2bLLJl3fQDwU19lr1oTU1d7HHXYeoA1YUe1EPVXl/mFTLdF6brmDnzOYRNQ1BuQBaG/UxqNc3MTTQH91MD6KobI3CRXLPagdsasHL7zVsWr6l23IZ5xNUWPQIUNirv2WMmth5uZOVukXDhUHHLRFyzHUY/t7txhkf7i81Wv9nvz5JHi+vibDbJY+vu+RZZw74sohFKhwlbpEBzbhzS3hjeDH4eYqaJbW2MkEdWMEQNGDBDZsAog24rDJ4t5n1Y3vPKBGpdB48SXN3BuXlvQzCz0yzOC9E1AXDRMTdyueCp5sypsdFAlMMXmar5vcxlqsCo1zCsiCejjbFu+BHrzdi5UXk6ZcxsMcxjN0TPFHyCjDpxaIJlkEsb2UhEwRiEsGSGrWOlZDZmKv3bG8emmsfFDix5zvb67pbh2E/A7UOo5a+HDDPbs7xPDDwy98Usv8xtdmX0xXMzuNtQ2ZO4QyWM1SRgGosMMzuQMiZ1Zqx+WdWaTdb5HDp9gjVLa8yUQUOsPbssgNnlBHvmhr8Bw3+/5UTpwMwyjbvtvPYl4nlVY/aMHgvGLBxZCS3GDgumrFmc5Zbnkm1mM2GDPdCVyf2AWcbXj+vGioXnLFek3ylJOLUCQl+9155zLRuDnQbCxDp/CYjl3FQAiyRYmy32IdN5YV4y236SYe4xY9P3lTHzPe8HlxlzNfnAYMcUpIHYMi7Lqha9NLLSLM/MR+gzU8SiU8NtEBlki613a4UUTqNlWs4qDdTqGBQ6cotJpfYc56xXDgFZiCheKyGx9GEJ4Cyu/xJusx6sySnwOQVlvqTC+inCLrKUNzaYS4+1io2RowF2HYZD/WRz5/qZcWx4UN/AW4dOfrV7dAJsxpCwZZr1aIXNMbC1ilPQdXttc71YMK8xDxmAbfhcIblhHUey9b0F9qi232/By5WcF1te2GZH32rL2saM32vAczDIFrLdKFvOWhi3hYvf6fj1bQ6yxC1QwY0MRjyAVtCWebUpMaJN7NRt3ddDb1u7Vsoq24KCVTMXmDPkodLm+RgJLlAnWlTbgunh2bPWa1wWnfmYjYumHy5m+3l+WdnhmUyuRpsM32wFyDhYmiK+OH85JVItd1/kwOkAhQqBNf7cJMkgERpMqHGCxUAaMN12Rmm+8Lzewpi1x4dQy1fCypdF10VDeF13jD1WtWWwBMQlDFkAZxtbd1cG4LlDZM4seX7G9ZBvf5gdGbnOLJMyLoOmte7sMoxAel1ZEnj9+fa8JGzZDoPGph8sc1xlncnrfwnDh289SV58ITP4R7MLYungYmRU7fGBz+uvvx4utUfIMXsFzBbAaMU2rQxBEmC1B26mZWXgH8yoxAa/cOBykyU2i3kKYS6UO9YMLzoAq+TFvbFWzRyjP2+SxPY8q4Pj502SqVJGYbkmB8iEBVN5qLKALhlqS4nioj5sNcRfSiV3vl8umB3oVVfGkRtakuV1hJO6RUxjnpddqYt8dcE2bJtNBJerFC4rmq18E9fiGEkGqx5txrxisoWE7GzAKK1mzeOdK+AZdVRIiM0EGNOwelUhJEutwqWZbxrMVHxVA1M2wBoA+YYduEH0w3CpUUK/DeBnM4qgJ5TR2cbqUBuyMcUANrR/tbkDjqIlNwIT7rNLMZ1QPQbZI4sXgbCPUyetNWu/x5HbYoxiNoM5/n64X3sHnPEnagB96OHYurW8nsFU9qDpahGsWKZU8KkAzJ1NPWyeLvC11LhuTGC1eFnwcRuXGHUcTapYhPWaPNrZBl8ljRYZtOSqui5V+mKXqdaMk8RMAtzVwWkY29+FSZdC9WVlGoTbbD05gTEP/B02+aTNNWbKQi2MPbh8qxAoc/JeAbl/lzsBW1jLGiewJqxaGzm4R1fHcHw0v86zilr6Vxh1Jmizv767dUj283D7clzKjwLli3drygp9xq6JF3Fb3KspY3ZtA2BRErm5MGJgwW6mofVlVVwYhTWbGDTcT8rIOWY1sdDfkzRm2WauLJmAyiOXRpU3ZsumwMzwP9zwFUSInwdm72qnmsXzV+tb59nlePY3NIuXrMbs7SRlTIDRLsji2qnk+YpBS001mFFqz3mZ7am6HU7TWvx58jwDlbPp8bHLokofjwBrykqqdFKeF7HEbzVpwc5+27e6WL4Q2Au5aYgZavo9SwDjNPInVlA/D873tmNSMTmu+cKxEUGtNHXimfhNjQ4BcWhUwGI7kHSSN3ocWUDQJW/85MYoU7Zhh0ymDD32+iCUOan9/LAX0zJ+XzBjnHSWsWaFIBeICbNg9OHwPndYCcTVzcmRwVmGJC3pnGsf8MfQcpLLdbZSHNVaGPGWz+WImWjOtvgeyB4CbKPw8frH2tVElXQkpyTwtlWjwopLfeMwY2kywKvfgJPpjZhbOBDcItl+HoMRGtJCxlUtnDq2bLeYt+EeCZZBbmYmYTOsLePdLMb6xIWPNg/W+0YsJIJ0jgFZNRC7hTAd0Fu657axhb6cTXUDOhtAc2tFsJvssZk5dBYs09DJwD01F/aFPC5nyqIdz/zXgrzRl5lnBSNzcIRAm7Bkca2OLK8s5pnxjmjkNAgEBS2lmhwqspQJr6AKJBf6Ujec7JEpU7WpphekgLHIphWsIxQLTXpZAexCAAYzq9ZY6CLC0o40v+A+w7KfhtvXopaP7jos2oaULiRPNKopUzbNE6AW3BrZ7EPCpMUaPwAynwHZBM4wSxn9pJSR/6YSRg2crpE165LGOuzzd3PNzkgbEYw79pkysdOnW/2fheEz9zlBrgHTMiGkEbzGE72JG5NZGEe8VDVmz8noI1uOGbNbWbM9mSLLEzNJokokV3JKXs+2rdd7+jCyCJLAPSBJZM/K0THY8N/jeQbIMoYw/V4C4oJvWCJNRCJVVIdFlUCy9NMo2BrERKomQ9kyO2DWSt0hMPayyjrpROYfXeLYVIF1QBzGMWE2yvOfUbIptHsVcJbtZQdfGiZqg8pjgDb0YVdNRQaVnO4GjSLkpOzg0IgYcM1VyJjGf9N40U9IFld53zUZc8baMlBNWW0CtG4E4onE0ae50qxwbmz5pW5gjo1ayFDDKknruqyO09auX6hU8cW0ameQGqhwG/VhPgBNq3na9HFdZthugi5uis5By5VEgQ2UkdTwKoMUmWY1il2rPS/NTPLrujxv20/basm27WvySppxilxhlzGGfJJR0+UkcZR4r96t2QCnnU3EAEedK5SS4khEt2PsG4jm884FmLVjNySavFGtzo499i9OVXCGIWFcebOr6o9DqEFBW+bRgcjyaQZbvKdQb5jb+3R5l0l62M7rEvLLBvdmwqSpMYjtToqsHjpnIEaUcDY21DsKq/7oDtZUox0nGylMLWfF9DlKJBOsiLjAdmauuAqhEJixy4K/BKKlcGPLXtx36Pgx1PJ7YOVrJvMPtbwvZSDcizKkmZRROMcGKovIGjdWja3xnQKbOyBzqSk7a6ixkvu5gLQTUsYAztSZkUFaHazZUbbZmQDqDKjVhUtju1VvIO7vwPD373tyvHiXbTS5R2fGlbY4vE8ypYaUnwBIPXeg97aRMu4As13pIoOdxIwjY+G0Hkyf99dNBqiSwJ26tWlbd4DbY4GvvedTG2UB3BmjiGG3j5WkEce1dsvnJOtUiWNqxHJG5sjAzEQmyGhg8slQi/xm9mGRra8b1rkQE6ZxX1XwijPTRla/nbWgWV1f7p2GBrtwg3SnCACNaECf4QyMpiKz8JZJr6lIytcBZFhP4qstyR3NjZtAJu8Qa7BptYfTDnbiWv8S5z29f/OyXFueB1XTnfB6GbP8Pk8G1gA4oiuiJ6er2qhfwbmE6jV1KnyWUbIfu0WKOJhukDFG/F1eNhqbxDDkeJyda8dULzwpBQeIV0YpUtrx+3G1vqst0SD3TKbpgeljsWyubOz9N8Ex7YR8DjkbtYwEIueZFqricw2Ytlhn1kAYO1IEKaPNjJrliGzlcLj/zyQSemSbtcSyBnzvSNg4YqkLMWVc28ZW+jOnvpY6zhjOEvOOsCi/XxCjEBT0XoYXi+aZWSJf5OYO/isJmdnJrXR/k51x3ZEy5KxuswYTWnt27+GpA/ZHUO2XAOW9S8v7zBof4sq4a4+fhUg3We/VHt/ZgZHDpAu5I0uwtMoW/cD445SUESRXxMyWBdt8dWSsMdfskjB7u1LGgwDqzEI/C6Xe/v4j3OGPPWTcfjX/cDrX8j5uDZNI5n95Aimj1oQ9Qo7ZSyVlPAvMFkBjj5XaBSc7oE3Xa2TtzoBsCTzacraFCG37yMYbXTJ5K9hi8JcBPn6fHCcrgbEq7VKTkGxlKxkcRjuKtelJBsQyUw89NlMNmbZtAuQmYOZhkDxP1NDEelADGqv97obph2G7b5Ay0EtkxkAkRc2wTPuti+Cby5kr33asuOcaGNBgOM8042VqDFnj9ElFD3WXUMqnrcSlMBtqjRtjJbrVEoDG9WYe3BmvvFTtsqtKa2DTj/j+nunHLP306sOMgnO+QxLaQPLmmEK0bVEz3SvKCBRNflaeidckLKsNk92DfUkzBMFC/OYybDf+vs05ELaotTIBSrFliK1ih9Hplj2OfZTk7bl/jQvNE/Cr++CWAz7NyHKuBVu0Xc5uy7LUYBZes5SR1jfZAUpn0idmpN7UbEaagYU0qrYcrW1BXGghUcwoUWzmaYzkEXcb4Cq0uQzxEDg4C+dedGqcY+hj/h6pemdBAbsjtv4a1L+3uCzPtRm2MWzFSH5RtvcVgPliCKqu9pmiK1xyJAmeQtnKmAnqRhzbTE7J7CnbEfkFDxmeORzvQy0/ALMvDbVkCqTYndHEuSazx1+Cue3AbMt2FqoQwCkxxaX/qzlztnJldOQMWpijRGL+gejQmFrnkxlIMAKpBOBsXW/mEJMQnA+gDsZjs2zzJ73gL9xeVaaMGQa7n9022czGfX9scLEnYbie+/qe9WOv/ipjxxJAldnOezLI35MV7rI0Z9anpiELQOKJc+G9gNle2x1Y49tOjdu9gKL+9i3behKM3/QdkF1+IJiImuFsslADxKxAHRKUFkbdpIwoQL3EeK82Q+WIfhpBJYiIgcwiNzMN7kJILKR+SQNtXZxMVnVlBaFArAfAUAMEr3/DkmBaGRv6SqUzS6JWJiAzr+Wp3LH2waOafjSgVvtQVNe0ts5HuiO1n88r7itQJ7G0qQOmBReMjH1ZE0W+Qx+t0t/Y2dA9GcSHMZkwtuEHbHnO+h4DxYYrjjh5MFUfzoBzbw5zkG+eT9oqu8fmi7befuSk++50asqNusV2CNe5zW4S2KG0ipp/kMGMI/FyZ4YrXoVRSDSqv5xMQIyyAoe8MU64FOHhTKwlR/h0HKhbiLCGwMXIi48tIp084+0ijroWsayJQsF8QR0WAl8be1bYFEQPl0dLfDYCCSDNF9SlJf10f99kh5LCOlPaT2YA7//4d4C9F7V8L1B+6RwaXYaU0VmGyDVliQV+IYfGBsZKXM43Ex0FZNVne/ylNPAAyOwGTCMptfb9WrOUMasSPl2BS92vNeuGIAkouyQ1aJcIvmbG7Pr3J3CH9wL49w89KV68G8CdpRN248Rf1Gv7nCX56IwZXpl/PCVjluaU6bKaTbYaxDfJ3oJ5WwJBlfpRvduKMcOCPcq2TQEns1OZQ6S+Dt85AWYyU5WjfTlch5qhNNljc68k0w8dMikLVhfLRZwVl5sYs7qa6tDxHvXM3Md04FaJeSsbu3WHLnPsUgWLNuFsrtAs9HnW2qlurU/m66yTjsK5snwU4BBwc1kh2UlaEs7Wuq+mBel3Gw6eFhYNa+C1ZsoO+oDFgfSdf2MY4z1n6TpQGrdVI/hlh2tc7VgctQ3GPJndXjWBhfKi/VH8nofDmQaemJuVowybx9jtt51Ai8XmONrKmAhh+2h+d7sMSiv6wde7yoC6MYetZ3V3dl0DH46O08iUAyRTQQKmbbbMt4xFI0DWLP9YX+fUsVhjypygllPcwbA1QQBew0PVAw9mgakekCCzQC+ITosqa7Qlk25JxtkU8abZZPR+kCuW0e9OCiyWs29/+VCwEYhZYv5Bjour/G9VmCJLo7EaU7BBDFnfeKNOhVAkS7B9m1HEux5hRGr/Fm4fAMpHds1ACmWfTTVm2b/IjkVQZyGrLMgYxSr/dL0W9vO8sjqziTE7y5zVnZqz5tBYDwDlmdBpk1r31d/r86/HBT/yGNTPi/L/tlmKW1fmCUirLx9j9pyMPrLlFJjdwIzshUun0sUkryyV3q1Ak7JnGQhbAKXwGUsZ2QlSX++1i4IhcjbU11wbNi2bbLsfgMuMacQCmO6B1hVLeQf5oQVIs53PiussupaSyNR3qx+DWOgHVaAYHIZZN5ci22hS19fvWR/FBn6sPFwOMjMvcqcbOqI5x+TUKIi0Fb3pzjDL4GLTHwiomfVY6BvCACxD6PNrXxiAXOfRc/OP2mWNjSmrwpp5MHpf8XVcn+SjxnAbILU6q6vrHjNCW15YM9bgIGawc1/LFcNmetGMMlie1kKJicUwMdogRqYDUGvSxejb7t3e37rsOQSNG9VVscSyhyOPE9rImMSZgejcCgdMU31cs8c3cWL0YYZhKh00C8HXTuvr5iJ8vLr5CgV8b9vrxM20tib8ghFKzeYm14vTjWz4nQntzQ3SbIbfxIw3Or/ltXWpZKdiKES6JMCMwZha5qvc0ZBEahidhRYAUHuX+fTIw5QNjA1RYZMc3/UugRkxrkxrtWbjswo2BQFiELUtZhtsOY1g4jHgRmwaY57tuQJevwzAxlb5sNx9kYlKTS6w1TgUSYyL9j2mB9AJjGnQNKNTJHloj8YbfAeqfSlQPjjXmgkrxtvJy0zB0ZJX1hBKKaN2y8jVsMT6slrJQl/Yp37LslnOl7oxWi5j3GXN2vt1KGIqYq0ZZ5sF6/xWa6ZGIOUAkCXW+hwufVlZ6he8H3f4u6cmVc8AM/s5AtjzfT6Xna9UD/XxGa7XX389rO8RcsxeZrv8CXDpZwKcJkB7IpPs8DMBBhzYDAJRae3THnuVsFy7gOsGYIZV6LOARRwxeFjY8LfXWtd2BKTv+9mKHT3TLmjmeOqJIaRIUP3RZ1V9NYxUgURaMTDT0quAZVwcGRPHRo4n09q0URgk2stQI8PFc7xzWyLnZPpBmkyX6cF+B/Nko6mAjsX6ShVWxPC2PhT0lKcCVmJCrgTzMFNfwxAvSuB8s8xXMLaSM+a1ZnUKqEa9DIv+jo88SvaazXwHVZxIxj0ZfW97zZ46DbQ4h1R7ZjgxGBknR0TwL/rgGK+b14CaiH7JwILvtVbFFbOtw6fNQEvHCn1Z38XG4hLe2fLTWEbXGZwNENWaBCk0wONjGF9lpsPBbexiskM5cZP6cWvL6lPH4gzUOFg8k+lg2OlzdEGw8e9jaIu2+To+n4qbLNcCTzMduU2+JSCn0PWVsz6Du7ojprqCq8gG+2E5sgS27+ch03PO1zgzZpkSlylOcE6NQDJ7/Rb/dje6yFa6FfwENUJOUw4sXW2oZS52MPse6srqPOwxW7QnG8GURIfwKI/Xrl1reW0dIr1gzFzqzCaTkEJW+TaADVvks/siyxgVONW1oyGDs0zCOBmAHLBl4XWl31dXxqzmrA5wmdWaMfDi2rNqOShbMoMF70fBNz7mifACbwgwO5p68J1O6vLyMWbP/XHEmO0N2kWaOC2/9znLE/X1arCPGKK8ZNv2ZI1ZThq7E6psMgONOyHY6WcMKEfmtYFfZ9uv2WGyLBL2K1jm62th2VTaGF7z50mG2dFVP6SMtiac2vPq0SSk2+JjKEjafadZ5TfL3pow871jrFKepUYhjK84i1gJKPbY5xFHVQcTj3bZVgG/I1TJh6JGdi1oMbU62hdlWJ4TYxZ46rRL04FUXcy9gSBUyy9rxh6Fhi9jcMi32BmsWZqYplLHipVG8eKDXTIGYWQ1DxsMWu2sTbOK3wa97YRgRmmzXG9D4uoJYxPqp64nWMvPavVrwcG427hbfz4INCNQYRE6EqPT3UmJ5fPIT3Xg0fbNg/8egtX+mAwxOvfHRjvNilTfLOk7WTuYP4P177oUjjWWckQ7cL6Od+auN691e5QYs+MIcdyN2WvtYVngNdcSmhPrichgMuNZioxZLbJixRMQRswqFzoB4kxRwqTA5DmB6IaqrNTgalniOABypayzRfzyiX+j5WYvyPFOpvQuZO4BMtpwiwoIK5hjHdlpnhAfY+DWtKXMhGZgzqTpoWDNF2QFa577RjrJUNm9ClTPpWDM1zWrj/f40BYk/dqgGsmlcZVbZsn7zVXSY21ZNXEzbLVl5MRYmWmqc8D0odU89gFa9dkuP3NoVOOPurLOrzGAmtmzYG1fZsOSy04ItQIzZsocgBe83wq+8bHPhCswy/InbKGWwY6i5gkYM7yqMXtqYDa5MIax7Qy+lsurHG/n9VDBuZ95nckY9XUDZNn+B/nirUD1BHN4+HrF+h3svwK0W4AqEubxPq/3gZlHc6AAesiFsan52hRwn+AWK/2+HNWHBRljRiCZ1Jwxk8djR8ylOxEElYgAA1XBTIGyJGUGYwzQun8/EtaLgEGoM+MpTGVcbN6uRNYw+D8PXfSdeCbqjHkMmB6SxsGe+cRjWo8r5hwqGjSr++JUQbQNzauIJ31I5IwnfnjALvbwwVYjMDsjw6uLzfjarp7c4+qQBiYSOqcRKp+XmNidYMvRs79cJi1ADFQ/OlvwM+/bBFc8u32TlbzxpFlktY0YYyeQ4KhTrRZ1YhJl4CE/gHPVENrFJ6VwgPgdXFqA/HOHRPLQfpo04Dqlh0dgZhqgtTXQCuME20VPAqgNw6l0XQsX54I8VHW1Yz0wTenn6WDOMmA2YI4LoxahO1sDmUza5OweRrZ637beEkW6u+wvAzWj7mL77A6zF0u30fcFiYnIzplMxLE8MtqsbhsQEqrLONds66ML5Zj12mHEGUMrTz2U/NAWIv1aypJpblnPKEts8jm7zEuoJ3NPQBgFTDfPqjRUGrOM8aF2+Zpp5okJiGdW+WL8oWxaNwI5Y2BiO7VlamzyBExZB2b2Bh3nIxizwzU1+fYrxuz5A7MMbAjttbK2h7JOCVs0vW5EljBmh+CCvpPKH3deT2zXLVK9M4ziQ9dxVIOXgaOs9uwEWNbv7IKwpK4wm4YpsahuLFX1nqjeGTR7amUQE1VkMU7Srkoh03EOaMYzIIik0wCcCztPPKlxus0sQHAz2Ta8SRU7BcCjFZpl1aRNHpWy9SQDsVB/JiiUUbG4mhjJGpHAn0pWBAM+ckwtOswqGHbdSFkvtciPAdPReD8CqtpDqqmsjuRhQyV2HTw51RilPKHMfkeeahv8Co4JYGmFrd0P7h5+4n7JDE5kVX2xStd0BgVdO9WErnIXBkjiFumJTaIzCEnqeBwKKOP+ZzFtAeSEtrVDG8a0dlQdSF14q+AIWBLnxcHuLUPHgDlEq197JZiA5Fdb7JAtwDTFNxbCpS+ASB6zxDOOoo7IUq3x2VCfG/wuAWurAdNSBUjkUuhOW+2ZY4oA64pSi1YmGSkZSsEQ65oLRFHK3hyuK6njB73mmsi2ViNmf8q040rBx374Bs4K4OW1UWNmeW6ZZ7llVHNWC+WWEegiENaZJJ/t8XtNWSGwoqCGgQ9yq/w0VBoxUDqTNTpLKCHGHyJjDHVmPhuBhJq5kwAtqzF7SlA2GLOyYMAMO/5umOvRnoAxe+45Zs/J6CNbbpGhNRl7nFhG688UjPWQaJU6MoAjqeIpOeEN7M4pBu4hoIrrv7Qe7ETQ9aqND0GgAFBbAOvd14t13lR7ljJmMpaF5N5Ul8B6j470OsbqSjbWuuusm629/1j6yL+RnsXLzBuLw88WEh06uhJRKftJ6+hcvf05JbvKyJjZtHRU7nMw9sRFzTLFsVeVZu99qjdjgFbJTHtAiNphlYI0X4C2OW65Ut5TDTlKnfEOhOX1GAzjjiG3nEFUDF9iUWCl6p+w502SSDDRuK4puYMMGR5CllmoS5x6z8Eg1YNb0rSNG2sYXeDVsTGjhX06rTuLLWCe5yh6dpyPujmF/plkj3PkqraJSzYcbSdHrg01ouVHwDbG0YfT4XX+IrpBBgVnY8xAFoCdonEBZaSBVpdGyOtAtHuAXQ1cgTismgAgI7BdJJb7EsBTW3eZvBrjxmKBMk16hjs6zzyVMk53kFWxmZNRLY8CPU7AsRzSnDK/IQ6MRSzyMSSOQdqoNWkQR8gpBoVQZSGQxRNqgSVVfaZShU/6+NCGJF4bcspWU6Ynp8hbAyi7fsYOx8H8o0QjkIklq2QKYhGA7VnmO07Y5SeArMsWIazYCev8LNOsW+pjWOT7ym0Ss8QxhE1fQdnXWcE3PeWBn6WMe9M+CtZyYPaKMXtGj9Xg+75gDYBvYcphGXqvr6eFLsvrJfBLXuNomYQ1U+BiJxnCMwYlZySLWc3WUX7c3vec7s2+AGl8F5lkh1jEFqyMU85cQzrh3Wcsiwyw2B1+u68Zdb7ATES1PdFw6UnGiDxzKq03w2JB7sDUa8YgBhvKGYDsaAXM8RZyQEwmaQxuJkgs1lX3ZZjThSNTFCtZYn6VBU7F4uB9A0vXEyc+9ySSWgGaBRMSRxQBzjlrLnYl7t1Sr9ustxqoxsrBt8GrNjnk5DCFZujGF915EKOGTKWRINfFzqlVKR9r+9pq0SqxvrxZdbS+88S7CE55XUES2GvLhgMiIc54irbfMgIoxFJdSye9t/GokxvnXjeosPYaBIiNjEGGKUqvhOLAc8dwoOynah0YukGCvm1buHi0KOFOGizO7bVoQdFbe01iJzmKSVGTzbLGPe1cim2a24QHLqrS0VchqM17FDpuVnZriVYRAGaTxz+wNq5QG/2SGuRzuDSkH+fVuom5YYmMljryeok3jgl88Z4UMfuwGaTBI4ZutXDucZnJ+7+wlEJ3klgw3cFBwWWI/GnBmZc3cClfDy9fMmwvt2NeC3BXZrbMOM/MrpllYonf6su4tmwlYZxMM3C7lDF9fiBlVBOQLGTaReJYxQik/b147i6Z1ZpxADXVnv2UGz6Igr/91Ad9ADNbALNVOqktBzqPfbY+NpB6U66m5/K4XC5pDln2ngKIhblH6tOpUkdm0yBGGTcAorPAZfd7J9mre0kWs/1HHjVwBAZ331uAzYmmoWVK0uap+cdq2j7JMmvv3VXGD4jkkrebdDNp8yh7rOQZbSWWbfRfvESHJ0Ac5xkStBl6i/VkXIblkXzYzcciZwmRCnLBxAoSVioeF8as0iir0sZ4QgsyXeiJ+0kqvcTETkXYZaHeywlAVoqZNaoYG+KfGN5rYvbhHZRFR8ZKYG7mP9RW/2rIwW53Bket28C7rSlxWaDZEfJqMaqnqiSk9LF/1iYpDGaV3ADbvtfRJmxJX5Ug22rRjIEP+ns0fXNdbwVZ2DtJHLcj5ARinUxOnEa2jgEI2cq/NU+VCQZOeiATmxogvXUYVpXyDsYkg56u3VXSaR9pkO91GIGwCQnVANUNBLtMbHg3IgGqeTTQ4BQLj+AWTmdWVbpFiKYJjHkS4IqUucuGKAy98veig+Mqo4QBW6Hhiy+D13SnuK8qBwOq2EdoBZ32lXa0A00JiGiE2LtTkrOned6W+Uwi+nHMm7520ERCGfdb4kV+wCUbIGPS3tTHN8Pt+1Dte+HllwWzD2ODD2LIikgeyfDDhSHzRMJYy8wsBTv8BVO2J2XMANlKyjiZf2CuKZus85Ow6crujHXIEkPANANPLAHaj/sd3os7/OibccBf2BuPeJ49DWP2yvzjERizM4wJciv9MyAj8Ko7AGLFBtk93kPG3S5YoOk2cl9gtgBPpwHbPcDYWWYvBXJSYxaO69G+L669AsAuSO5VFEHENfiVS1Uq5yhJELTkfHJZVU3MDPv4vEaIEsKmaWxaXaRaAVRS0FJ16dQKjQaysDRelgdFrQZNGLJqSf2Y4ipP6D/HWi5HLE9aaySD5T7AJTBAg/NCosfr0KXSuKd2axDv++2pUX80+VBz/rko2UMOgzaHVobNvbmLq+WyfqrbrIPYutj2k8lHgsOnSiinEhxaXx+Yu4dg9Mi8Rkg9wVjP9nvsg5ZKqlX9nOsnUknJl+vHx8m4hA0++kyLkM8VydnlIv10WjTKTud4xWhoCpWZ8rZMUk+jHLOEUCriyc4THCbe63Y0ZZyn963wS1YZUuQK4iFVM//g+W+bgFq6k0it34lBW1oMWEwWANnYU9lkYNrMIvXnjIG2ybhGXIZDkAVML2zy2ZURG/u26yU86ekTWo0RpBN1N8kX6xNxBruPH0a1r4CVbwXKb7kCrw2EfX4LkiaGjGWPzJZ18FIEkEmY9JI5w8ycLcKWUynjMsMsAWiBCUMeMK2OjZNLY1ZrhrFvYb/KQp5p+EG/w5+xNwmUXRmzz2E/pwM4V2OGPkPyqGfr66+/Htb3CDlmL52U8YFA5BZwFoYGWa3ZWYB3Arzw9+1G8HILILoZJD0UdJ54X8FXOo13hmF8CIutY97JrMCiuzyY/VI7ZcVBWdyXZ0lYO07zEmTNCiSfR95xA7O5nEAgaphRkdOfXRnlLqUjZA2YTkf9tF51bpThrvUaLt2LSsu42I8HqnCWhvbhn4d6pPFbc7UawzEIA8f1T5Ulj4TKA4AnJN0t1QHOiR6gojEywf4dovzcqn26nT7JFdmATwZvwZQvbUHXyq7AnBqHJfcQagwb+e5kOCi5ZtZhKgh1qplbjfSNArRt5yIlvm3Uq20M2eZmGXK3232lRQV0as+CtweDqeaaKNXE5NdinFwgfQvFIICO1QYazax7OfBlbK0DCPb4WMgYTZwbF2RU7MERg6QTPIDZKsIWM16q6L4LA9ohQYwMmMk8WlkANAVn+a0g4BOfyaQp9oswrSUlWA3fqGdRkCcmitJC5h4K0Do4pD69WEKQAVK4WKM+k+coOzjnnahydCTX5c19/BsAvxXVPgYvXzObfdDrLUgaxQIYq3VmzEL0TBHmLJEy+hkp4x5bhmPLfM4vy+zylzVmPpt/qCHIxfM8s5oD0O/EF+CPv9kH+oV/lk5wexin5E9jl/+sGbjnZPSRLdeK6W8BXCsQdAtg2gM9C9h/E0g6AB6nlt1pl0dpr1vbZa+9VqBuwX4dMYz3bq92d8qSqJjI0awbh+AYI+BGBeJMPHXVHgZr1p9jP7/Mce2IQQMMP9XNyIjDaSThghwn90bIDb3JSSxKFgMQgxh9iPd/bzMx4q40eNTPBHipDLFBq0L7y+wYsyZsr2CdSatAcFlUCWMFQuSzyhlrgDEMFJ10Tr3cjFgrYwkcIrY1jNyyYXPvoT6s0ijS4cOQoMsJY7TCiLKrlAOmnpc+ndoIVvcDoFdQ9lmTO1ZOWh81mcPwhLw03SlXDds6t+Vkq5oDo/POBDbuKt/02mScRtvFoedVcsysS5TbTnqrw3Pljq4Xrm+5be61A6nr+8bp2GMKwVtuXJNwgkDYYO96FJwP1nMEbdPsTGPFoKArcZOYpADUeU3Ad18YiMWQKuPVnK6xFkChCj0Xt0WI82KsUJujq30pnByvJ/sQE7m5NItt8jirs/iAu08T9FkI1BWbmTJImRfngncyKysFy+5c5qKp1EkJX3CZi1ugFbxl4ivHHwXsB1DLNwH2njRQerPJ9xYm3RJbCkn/WIliM3O2kjLWPSkjxGYex+BskjcmNvmh7iyrN6tSi5a5M0q2mZfdmrPPeMGf9xf4zreCyclrzFY9iO9OtLyyy3+GD871uoEh22XEbgVzR58pSEuyvB4KJm4FYDe//xCQm8gQ/RZp5GOxbwvgnC3fXRld/SlMMsPqyOfsmczimohtdq7duJ3xjJO0Ajmu2XOTDwBDas1in0dTsJP7YdbpSYhP12hyOOkBMAMiS1bbAB4j2TP4lNdYX7YolnMy7MBUxcUCx7lIsPbBIQS2gfixOVA62uGD4N2QxwExhyuakWyD01qxIjOZPULWl3H4nfyeSt9YuDckdRZ4DZfRtXMWUo1Oj4lXIqJccuzMrMokiZRRbQ4xVw2chZorgdttGw11uoDNhzQ1sJmNafRu1RjYuDF5Qu23sXp12o8o+QzCUecatAZGB6jLAsD6sfHoGOk1ssd5voeP9jNsThNCKDF5FOgbnwFcn6wRbZ/NnfTOEGlnSOKbwY4J/zrO7SYytiA/tO2b1kFblpBmEp6RgcflVJWU3BmXavE8AEXCtQkTEy8kI23bJFHckS2auO0Gkovn01JW0wigr4BXBlJr0mKsmnjLqmIqgI/A8Y9xKf8AtXxZs8O/Shob9VUGIKuYzT/YcZFCppmAqwtA5isZo+2HS6fGHxDwRX8nlgy0P5hrzNhKv+pzMQJZsWVu+CTu8AdQ8J/fKrBwrTFbTffY3vB4OZR7VWP2jB579u0MKNrMZPbd5DO1wU/BCdvMY9/1cZoW0PytZJvbuh2JpHELlQZyuWOW8aW/nzJ8yfvLz3ZYqtUxyiiYs8DztJzxxDlz9B3TuCetK4PHLOQW+VVpBrUmcDWAKouMGJNJzIC55OB2wxGSrsmYOz+rPMl9kpn85MPA3kyjeaxoPY8bNhXJER2UUX4hC8DToZaTKb1+7pRkFv0cr59ewvh1ODIagS0jcaTEBGMWnc6vLZjnb+tLCqK6JUGoAfPIWnjCaDBISDLt5otThGRO+WZTyHcd8sN0qskp22pxA83yuCoxbv37G2Ayk3YezCBLLivmDDs2PhnvzKxfZPkaU8LWqy3g26T9mL6aGacp+yz8iETQ9T7FUZuE06MDac5ZcrD2cPa8dlZlBl+pzR+k5gwzYAt2g5gy3gZLvRMpMHV9Rt2TTTcCB3AX7HnmvLJCgK3VnkWYl2WfRceMLGTaVhutzJlIFk3xDCjqsVA9me/Y4GNtlc/tw6abqZZU7SU16yLYrKrxB/dnBQu/37fi8R/h+B1wez9Q/jJgd8MqvwzJIjFmVUKlqyU2+QTW0tqrE1b54Z++5zuvEykjs2MMxjTLLLgy+syU6euLEyC9bufna8EH8QLfZMD/eSsP7Fxj5vsM7i70egJgpjVhj5Bj9rIyZisGLICzFUtzw2cTS5YZU9zIsK0AB4Ohyb3xrCX9CTbsST7DwqnxHgzZaZbs5GdHLFqpHuukw02dJSYsVZRoMFAYafucyabMTR6+YM48kQ554qlxeEvds2l0mTWtycxq1an4KMRf7QDkeRUakoGj1xhEHQZ00aYbIXGqTiMW3fKME4wsQJYeB+DgfQsiSshzxsBSq9YBDoVTT4P6OvbYWaw3QqV7jZXUivlC+xSjAaz/JLkHIar7HFZtsu13AZnTqLaBvx6qbYHNavuROniQdivIOXuLeFyX6fUwwGWv4VImvC0VcqDm/LtWL9fNZxw5kygTHg2ANRBKUHibYKlhbkIrO02cScOvbdJN76N6kTCGSzyhaqT+LsocgRyVazCERcCIzOHUwn7bdBU1Nm2uJ/MgU2ywQZ0VLWXMIrayCWuFXDpgylE3S+dAeoLA5K/RmGZy7V0dlqzMD2KSuOq1beWZkDGdjDpDkjUWzifP7vGzAD6Aap+A219DLV/ZWDO1xue8MicJ4+TKSADN+XZjUksm9WWhlFrqy/JwlTw9JrBmiazRBZSlrowC0porI7/fQ6cBeMHH/Q7fgIJPPYeD+gKfTTipI8v8bIJ23Pdf2eU/T2B2K0jAAUg4AlM3AbEzYOwhgOMME/SU7XP03Sdo30dvHwZmviCcQo0B38jrAF2qXBr24cJmlJkwCkN+i6QRSyQrclC2lu+wPiaxdMyy1sNsrCMLcQ3ADIkJyATMMDNDwTJ/tVcMgvLhl0+dtSWDZwuBtzONy0YenryOrAybfIwtnION0WdMK+Vhxcy16tvyzQmQZwLa4N55uxno1AEejKR1ZvBuxx+dA/teWR0xD0yK8ngOm7V+DUVx2/I+AqvNgvV8BKMeJYOhxaxrwyzaE1L93WYQsWmIOzA1dmccv+/G4Cw6WJq5OJp6CINu+2LCtF3BVrSXMbMAdTuxuW1Pbe81o5GeXyZMepcmyj44CMolLHz1IWVMY77Uq10G86HQyXOkMo/4YTu8npNkODhXytXSRI7DAzXWi5VwtQ72LLJl/L4CwxxWYrH73KVNBLXNE3GmogIbcsYMdNnqENBvl6TFNShgfxgpbHt6R0KiivAUNj+Tx78C7Pei2h8G7Our49dUAmGVasvqDmN2+A87z7HzPPvnO893mLO9oOnJrbHO1vnBuRH44VrwmhX8PXGweouB2eeQx9Ia1vVmixwzexog9azX95yMPrLlGJgdgItTnz8WyLgnGLsVcDjyEOr7ALOwTMgUunGZvTq1J26/PVDqN3xeapz4HjddzA6MoetQC3SbX/db32XM2CFxlQ9MGd1bU+d5O1P3oXpMAWjZtDG2u146WBPnE3YzgbgxMhM2jctFJoaMonQagFWZtzepNPOJd8jgW0DiCUPBhh8M2thlMZqARGDHtVEdTFVPbOJHVpXLLIDxOeW+mDsUZ1pmfQjYeWA64sp9GV3nM3HZAYz8hoCwjNGFa0KdR6Dks5gx7rNTeaRjElNrAWY4qTwCoQ3rZOagDjkeMlHhpGl2T+rwnCAKgWJwDl0AZeJkaghOLfNVJ9dec5dgtGFi9KFaONbOwRauFHPfoPVhlnJlJkw3pnFhSxaMoki26EEAaUbQpBBY498qAShOItb+eRjQCVHNk25muZDKbcze9ck6aWKT9ZiaIyJKHaHMGS03Za6tbq9KrZlj984QPjKsZOPPZR4ewEfh+D6veL87/oQbvqgDGq4hy2rLjOLQDmzymTVb1phhBmmcX+YLUMZs2eTKCGHIstoyYc68xuU2oPYzXvEdbvgwCn76uR3IKzBbDRH9tnPRX0Jg9twfZ4KVbwRnp5c5AHG3LHcTYFkAkSP27ibgI7V7h6HWZ0DfWRB1j+UevIw8ShfxSVF23Zt+TW54Kn/UYvLAiAmcUPA1ATx57/hWunJB2vsmB0Ol0ayxoGm54S5MGpKaNEsAZM6MmQ7WJ+Egf0vn12dJU+0cSH4UYoB0tPgImVjTFsQbTbhOVMEXzhGyzA/7bJCkssA9QJhACFy0LLU6ID2LrorLkVwu98tBNdc12hYNMB8rjfdy0zqxYe0R6rnS09fk+MgnPJqW3fPVZZHWbCIFLi5zGxws2OSNzYEzlm1qenwiQ1W6HriW3yxNPRSk2SxphKCO3oFZBgcJiDkxWXHvdUoEUxB8jIS/6/WDWjMGMg5R1m7u20xYNo2eTq3yqdl0noqbjA9nJxlb1hjisQzNbjMzFuSNlpObsBkQmq/GsD7LGVMbSQwpY/G3oyvBTwH4Oq/45mp4X3X8qVrxnu6kz/VkLiCMLfKLyBYXoCzki4pdvuaYHdrlI3FlRO7EmDFoWc4ZM2XV8Rl3fDsc3wLgvz3XA3iVMp4dkr0FNWavcsweOIVS61OBqjNA5ywL9uDlbgErNwKl02D/ndpeCXArFbPPgroeWnJz1xq0EN0lticuAI0H6ynGwb7dxHKSKfhA04DLD9DlJGFUOJMAsxSg2RwYfbSM+w5rolKo7HSIkC3O50eAN4s0XZivyBBZECx6qE/z5LMQd+2eDvQtEk+UtaVAS/PScirKF2gimsmnDjzBZ8R5EJefdYEX8fRnRSKVGMisMKDLvjtyXBl3Xz0dZzxlq77P5DyUCZBshRMLm036agQCg/kdlnA5A6RKnh5yZWtDPksoGWRsGdkSBuasyPUQa8ci64UA38ZVWEJ9ZN34r7ItXYI0MQNc6x3T4VkEfzOfXhDl4VO/rgY6qgZPvJJM5L+GBGTZTvqa5Te3UAub5ZmZ5TSYKbq02MnwRuUn7XN+/ASA98Pxre7409XxJ2vFF3VjD4qkqSUyZE6OjX6D6ccEzjDXlZ11Z+yfqazR1zVnVd0aB5P2M9XxEQDfBuC/PPcD98I+l9yvz7C0iXPjyyhlfBsCs9Og5ARTdQvb9KgA5IjRekSG6AyQfXB7PWL7Pnp7Jb1BaR2rIXgChEGhiVQRMhOrZBDf3Fm95IkkJuCWQqTVDlCDLdi5zLo8gC6/oU9cUH8pWkxsLF06V60/S3+0IgqoVuYC2dxZrDXz4OHmU1ONiozZGl9Bm9bOmByRWI+WMGbTCchrnFKgd5afyZYg3tzqm1TaFbBCcnPr1V9tFGM7Yb0pyMNkFpJEt9/wyC64AzC66Al9cmJsY1afBttTqLsElvuqN/HDiONpMmf+xHZnjPvybJdvi5E9lI5BZNkmeigV8W3vlIm/tl2wzv6JZbtmCu4Cn51udOC551oyrj8b37epFde3xECe2ux4O01LSfdlfHlI51xs51AkOJovF1sMOG2vg870mFiAtukmYUdX9HN9/CcAfwkV3+KG9znwB93xy1ttWQdEwozVM1JGLBwZE3CWZpkldWae/F1JGadcszpiPzdg9l8d+Bgcfwv2fBmyCZjhs1hb/mYd90rWmN/1XwGzt/hxQ1DyY7BCj/adhwCWRwSFuh9ZpMCZersz37Mbjqnf4zs7w7CbQazVg4HnxFh47CayVnMZZ2k4tSMHX6jz+0i6KV/JrjL2QvGrn5i1cuSf++o3FzpNeLLDR5eB7zMIApTmoUZmOoEwlHORMuaCwHmH5/+z13yeRhnYPELfzsBmJ199k/UxO+A9yypkhSNK5LI6sDFkvgY3s0W8J7HSTuYTYQDcjRJ05iKe0G4EqjfzEFuBy8Ut2RRoC0YrFOvNrqhIkkS8B1lv7diMNmrCNlR2zTRRGvrMXmxW9twdVsI9174y7lx3jPR4HKfSObsKbocqcosP8A2YZaN+HACzie5Z8TVt2TJ9zxZuqevZcKPJDxMxcAk8G8LVgiBMnIMaon0+/xZ2hnU1qfMKUY8iR3RurnZcufmHj82QRyI39cCivswzkObREV/SUSloTVHkwZ3RGSFWPNP6sjOPH4fj62D4gFf8fr/KHX+9MmdpwDTOSxkDEFtlmXkEaqeljJAcsxVT5vjXAD4M4BNw/Nzb7UBda8zOGH+cH1K/VMDsORl9ZMtljNkDQNN9gNOpNr9V2veIbNARiD1a5hRLtve9N7E9Hwv8lWyMtsxlRiJFE3lif7/MQdVh1hY5CPMzOAjLbGK643siTdthJ4CEKQNSTea0UVktE0831wVI9B1sGPzwpL6LZ999GsDF1CtMgzqwZb2wXzbJE+NvcOZZtN6X574GflPzs/GDI4muHsBphqjIzTcm4OhzePIEvD04RE4431dnZZwxcNqoPZCcAtrslUfwo1LBfMaC9sHrAkLr7Igj2fOpjSM4S5sghnGHdayY1Hm5iLGZ8ZLBeMqcMVgjuDB9L4PHJVwpM9TiKzSDRPEKLAmA8gDITISMNu3Uylw7q2abbhLbR3erG4klsYGWN496I03W+FgcEpvr3CZIbNJlLzOjRQER5F47seBLuerbdo7/DQAfdcd3OfAb3PFVteL3ueFXV7bGLwNc3SJl9HtKGdX8g6WMWdi0z/9+xIFPAPhuOD4Fw+XteoCujFkyObScRTie53+VY/aMHjvA7KEA7bA9H8KUPTXwuC8wu3UfHgp87wlm790WJ9m4UjFP9nLNzZTfuehGQr2OAbiM555MWiIJsNaxpSd1Lx3Y1Z3Wqpk9/hn3I1/MNWMGZmFn6syyhXoy+V3XpNasU7bUfsKW9hs2gRm2MYimIS7OcSqT1F/Q+rK89o2BoNdKDBK1rshdBxOT3KRcptrlME3iMLfOsOigOuOq0vfpOI5AbI9FLzrNL6xGts+w+Hx8tirygRTZ+CJ0yqjt04TkHi2gFiPrQKwW7Ly1Jek/VXGa1SVNEzuIJhqRuZjbaVfdU0oyQMcMtHSAntEyhwDNpqvRE9iVAzq9PkzWvhbu+QTELPmF+UxbBWx0ILS89g7uPst6XkxW+7aDhVIMpZef5Yd2WuOhlPFoR4B7CE+e6+PnAby+/fur7vjN7viqCvyuavh1wQgkkTD6I0sZ3fcljZn5R3X8kAPf48A/dOCfv1PG7S/wBh6PlX0JGbO3OzBrEjsKavb7gpRErncmE2sJkMxsD0CcOY437cSZdfI2HbTRoxuRPNK57Sd/286vBHmtiYClXUdXxSae4BlPJuwzr4gFoeR+codWNpEndNzp65Te8IMNyyiFve/kACsfiiNlteIve8KszdvlkYvBMnyYwF1s3cjHXIPLr9O21WQ7ndbjFpwUXcbPTUpnCbjllLM+6N+6yauszrvdezX1pLmeXHUbBQ6pY7N+byPXitadGGKKas//6qHSVNFHYKbnezXgSBkVlSSGfYOMjrDLMF0yLIb0UwKk+40DPRcuunFuv0BANIR7O7GznPHnV0dBeDKnEJSem5wT6MHZVzkdcb0aNO1xG8IAvO1LKTu9W5JhmC23nGnyZBAUZa/zVEPeb7SY6Jm1NumRWE7b0s5M4i2sP8dywsHSq7tgVhl0GSLh2wDSuL44wUJxYLLf1OH9DEcfLWeLLrUsfrGFr+FovvcdA8qyxz/b/v0Vd/xGd/z2DaT9qgr8ymo5g3arlDGAL+xLGSfzD+DHquM/VMf3u+GfAPgUgM+/0w7Evl3+rcPbJwBmJwfgpwe9tjfafwc+jgb9jymxuxFgPApgeQrW6DH28RHB1qNOMpyJSzgF+I9gqK+AbUIGLZZ3uw1t+31mcHfx9JETkp/b+b0uzB/p/TQsOvtk3eBRdpXLHu1Q2unS5Bo+vXZEDIN+O5L0rdbC2YEm0dm5QNKXDoieuo0ifOzJRIGPoGvfcXYMkwwiB3RucY+MdMdYOvuhreXJKcJyxljJlnvmL1o6fL6y1Pd0tiStBw2f+dw2Imf0M/2aWsQuL5sd+ZoaVtj5LtMW5icKqmz5wxkutAXTtObEdF2rYdqeUM8ypssSr5pE3pg1vZUbbj52EiMf3blsZ2BrRxYiN5d1v50fPw/gkwA+CceHAbwbjt8EwxdXx1dXwy+uwG/bQNgvDOYgoHo05FJGRx4sLQzZ/93+/mB1fMYNH3fHp93wL96ONWM3A7M3Pk8X4wFj68rmS49T7W1x5r5izJ5Bu73JLNE7HmC/6efVCrL4OdxjOHajPzslk0kXd4HZubXugof9m3e2I2eRYeZ1jpPfy8FlllSVeb0dYb+cQWM/yLpoK1/uif71lYvL6UO4NkHxdA2Om1b55l/56824tU/wG3bM8YB2eYbmCKXc/67ywDuMnT44tvsdT2Acg3BbmsTYyV99grvtCg/77T+eQqcHEVj2hDv+jnp8DsAPbs8/vp04X7J1QV/uhvdsDNfvrIZfEZgxS9gyAWTb6x+rhh/Y1vNpN3z/xrj/z5exwf8/KN3SXB79k9cAAAAASUVORK5CYII=)}.minicolors-no-data-uris .minicolors-sprite{background-image:url(jquery.minicolors.png)}.minicolors-swatch{position:absolute;vertical-align:middle;background-position:-80px 0;border:1px solid #ccc;cursor:text;padding:0;margin:0;display:inline-block}.minicolors-swatch-color{position:absolute;top:0;left:0;right:0;bottom:0}.minicolors input[type=hidden]+.minicolors-swatch{width:28px;position:static;cursor:pointer}.minicolors input[type=hidden][disabled]+.minicolors-swatch{cursor:default}.minicolors-panel{position:absolute;width:173px;height:152px;background:#fff;border:1px solid #ccc;box-shadow:0 0 20px rgba(0,0,0,.2);z-index:99999;box-sizing:content-box;display:none}.minicolors-panel.minicolors-visible{display:block}.minicolors-position-top .minicolors-panel{top:-154px}.minicolors-position-right .minicolors-panel{right:0}.minicolors-position-bottom .minicolors-panel{top:auto}.minicolors-position-left .minicolors-panel{left:0}.minicolors-with-opacity .minicolors-panel{width:194px}.minicolors .minicolors-grid{position:absolute;top:1px;left:1px;width:150px;height:150px;background-position:-120px 0;cursor:crosshair}.minicolors .minicolors-grid-inner{position:absolute;top:0;left:0;width:150px;height:150px}.minicolors-slider-saturation .minicolors-grid{background-position:-420px 0}.minicolors-slider-saturation .minicolors-grid-inner{background-position:-270px 0;background-image:inherit}.minicolors-slider-brightness .minicolors-grid{background-position:-570px 0}.minicolors-slider-brightness .minicolors-grid-inner{background-color:#000}.minicolors-slider-wheel .minicolors-grid{background-position:-720px 0}.minicolors-opacity-slider,.minicolors-slider{position:absolute;top:1px;left:152px;width:20px;height:150px;background-color:#fff;background-position:0 0;cursor:row-resize}.minicolors-slider-saturation .minicolors-slider{background-position:-60px 0}.minicolors-slider-brightness .minicolors-slider,.minicolors-slider-wheel .minicolors-slider{background-position:-20px 0}.minicolors-opacity-slider{left:173px;background-position:-40px 0;display:none}.minicolors-with-opacity .minicolors-opacity-slider{display:block}.minicolors-grid .minicolors-picker{position:absolute;top:70px;left:70px;width:12px;height:12px;border:1px solid #000;border-radius:10px;margin-top:-6px;margin-left:-6px;background:none}.minicolors-grid .minicolors-picker>div{position:absolute;top:0;left:0;width:8px;height:8px;border-radius:8px;border:2px solid #fff;box-sizing:content-box}.minicolors-picker{position:absolute;top:0;left:0;width:18px;height:2px;background:#fff;border:1px solid #000;margin-top:-2px;box-sizing:content-box}.minicolors-inline{display:inline-block}.minicolors-inline .minicolors-input{display:none!important}.minicolors-inline .minicolors-panel{position:relative;top:auto;left:auto;box-shadow:none;z-index:auto;display:inline-block}.minicolors-theme-default .minicolors-swatch{top:5px;left:5px;width:18px;height:18px}.minicolors-theme-default.minicolors-position-right .minicolors-swatch{left:auto;right:5px}.minicolors-theme-default.minicolors{width:auto;display:inline-block}.minicolors-theme-default .minicolors-input{height:20px;width:auto;display:inline-block;padding-left:26px}.minicolors-theme-default.minicolors-position-right .minicolors-input{padding-right:26px;padding-left:inherit}.minicolors-theme-bootstrap .minicolors-swatch{z-index:2;top:3px;left:3px;width:28px;height:28px;border-radius:3px}.minicolors-theme-bootstrap .minicolors-swatch-color{border-radius:inherit}.minicolors-theme-bootstrap.minicolors-position-right .minicolors-swatch{left:auto;right:3px}.minicolors-theme-bootstrap .minicolors-input{float:none;padding-left:44px}.minicolors-theme-bootstrap.minicolors-position-right .minicolors-input{padding-right:44px;padding-left:12px}.minicolors-theme-bootstrap .minicolors-input.input-lg+.minicolors-swatch{top:4px;left:4px;width:37px;height:37px;border-radius:5px}.minicolors-theme-bootstrap .minicolors-input.input-sm+.minicolors-swatch{width:24px;height:24px}.input-group .minicolors-theme-bootstrap:not(:first-child) .minicolors-input{border-top-left-radius:0;border-bottom-left-radius:0}body.stop-scrolling{height:100%;overflow:hidden}.sweet-overlay{background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";background-color:rgba(0,0,0,.4);position:fixed;left:0;right:0;top:0;bottom:0;display:none;z-index:10000}.sweet-alert{background-color:#fff;font-family:Open Sans,Helvetica Neue,Helvetica,Arial,sans-serif;width:478px;padding:17px;border-radius:5px;text-align:center;position:fixed;left:50%;top:50%;margin-left:-256px;margin-top:-200px;overflow:hidden;display:none;z-index:99999}@media all and (max-width:540px){.sweet-alert{width:auto;margin-left:0;margin-right:0;left:15px;right:15px}}.sweet-alert h2{color:#575757;font-size:30px;font-weight:600;text-transform:none;margin:25px 0;line-height:40px;display:block}.sweet-alert h2,.sweet-alert p{text-align:center;position:relative;padding:0}.sweet-alert p{color:#797979;font-size:16px;font-weight:300;text-align:inherit;float:none;margin:0;line-height:normal}.sweet-alert fieldset{border:none;position:relative}.sweet-alert .sa-error-container{background-color:#f1f1f1;margin-left:-17px;margin-right:-17px;overflow:hidden;padding:0 10px;max-height:0;webkit-transition:padding .15s,max-height .15s;transition:padding .15s,max-height .15s}.sweet-alert .sa-error-container.show{padding:10px 0;max-height:100px;webkit-transition:padding .2s,max-height .2s;transition:padding .25s,max-height .25s}.sweet-alert .sa-error-container .icon{display:inline-block;width:24px;height:24px;border-radius:50%;background-color:#ea7d7d;color:#fff;line-height:24px;text-align:center;margin-right:3px}.sweet-alert .sa-error-container p{display:inline-block}.sweet-alert .sa-input-error{position:absolute;top:29px;right:26px;width:20px;height:20px;opacity:0;-webkit-transform:scale(.5);transform:scale(.5);-webkit-transform-origin:50% 50%;transform-origin:50% 50%;-webkit-transition:all .1s;transition:all .1s}.sweet-alert .sa-input-error:after,.sweet-alert .sa-input-error:before{content:"";width:20px;height:6px;background-color:#f06e57;border-radius:3px;position:absolute;top:50%;margin-top:-4px;left:50%;margin-left:-9px}.sweet-alert .sa-input-error:before{-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.sweet-alert .sa-input-error:after{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.sweet-alert .sa-input-error.show{opacity:1;-webkit-transform:scale(1);transform:scale(1)}.sweet-alert input{width:100%;box-sizing:border-box;border-radius:3px;border:1px solid #d7d7d7;height:43px;margin-top:10px;margin-bottom:17px;font-size:18px;box-shadow:inset 0 1px 1px rgba(0,0,0,.06);padding:0 12px;display:none;-webkit-transition:all .3s;transition:all .3s}.sweet-alert input:focus{outline:none;box-shadow:0 0 3px #c4e6f5;border:1px solid #b4dbed}.sweet-alert input:focus::-moz-placeholder{transition:opacity .3s ease .03s;opacity:.5}.sweet-alert input:focus:-ms-input-placeholder{transition:opacity .3s ease .03s;opacity:.5}.sweet-alert input:focus::-webkit-input-placeholder{transition:opacity .3s ease .03s;opacity:.5}.sweet-alert input::-moz-placeholder{color:#bdbdbd}.sweet-alert input:-ms-input-placeholder{color:#bdbdbd}.sweet-alert input::-webkit-input-placeholder{color:#bdbdbd}.sweet-alert.show-input input{display:block}.sweet-alert .sa-confirm-button-container{display:inline-block;position:relative}.sweet-alert .la-ball-fall{position:absolute;left:50%;top:50%;margin-left:-27px;margin-top:4px;opacity:0;visibility:hidden}.sweet-alert button{background-color:#8cd4f5;color:#fff;border:none;box-shadow:none;font-size:17px;font-weight:500;border-radius:5px;padding:10px 32px;margin:26px 5px 0;cursor:pointer}.sweet-alert button:focus{outline:none;box-shadow:0 0 2px rgba(128,179,235,.5),inset 0 0 0 1px rgba(0,0,0,.05)}.sweet-alert button:hover{background-color:#7ecff4}.sweet-alert button:active{background-color:#5dc2f1}.sweet-alert button.cancel{background-color:#c1c1c1}.sweet-alert button.cancel:hover{background-color:#b9b9b9}.sweet-alert button.cancel:active{background-color:#a8a8a8}.sweet-alert button.cancel:focus{box-shadow:0 0 2px rgba(197,205,211,.8),inset 0 0 0 1px rgba(0,0,0,.0470588)!important}.sweet-alert button[disabled]{opacity:.6;cursor:default}.sweet-alert button.confirm[disabled]{color:transparent}.sweet-alert button.confirm[disabled]~.la-ball-fall{opacity:1;visibility:visible;transition-delay:0s}.sweet-alert button::-moz-focus-inner{border:0}.sweet-alert[data-has-cancel-button=false] button{box-shadow:none!important}.sweet-alert[data-has-confirm-button=false][data-has-cancel-button=false]{padding-bottom:40px}.sweet-alert .sa-icon{width:80px;height:80px;border:4px solid gray;border-radius:40px;border-radius:50%;margin:20px auto;padding:0;position:relative;box-sizing:content-box}.sweet-alert .sa-icon.sa-error{border-color:#f27474}.sweet-alert .sa-icon.sa-error .sa-x-mark{position:relative;display:block}.sweet-alert .sa-icon.sa-error .sa-line{position:absolute;height:5px;width:47px;background-color:#f27474;display:block;top:37px;border-radius:2px}.sweet-alert .sa-icon.sa-error .sa-line.sa-left{-webkit-transform:rotate(45deg);transform:rotate(45deg);left:17px}.sweet-alert .sa-icon.sa-error .sa-line.sa-right{-webkit-transform:rotate(-45deg);transform:rotate(-45deg);right:16px}.sweet-alert .sa-icon.sa-warning{border-color:#f8bb86}.sweet-alert .sa-icon.sa-warning .sa-body{position:absolute;width:5px;height:47px;left:50%;top:10px;border-radius:2px;margin-left:-2px;background-color:#f8bb86}.sweet-alert .sa-icon.sa-warning .sa-dot{position:absolute;width:7px;height:7px;border-radius:50%;margin-left:-3px;left:50%;bottom:10px;background-color:#f8bb86}.sweet-alert .sa-icon.sa-info{border-color:#c9dae1}.sweet-alert .sa-icon.sa-info:before{content:"";position:absolute;width:5px;height:29px;left:50%;bottom:17px;border-radius:2px;margin-left:-2px;background-color:#c9dae1}.sweet-alert .sa-icon.sa-info:after{content:"";position:absolute;width:7px;height:7px;border-radius:50%;margin-left:-3px;top:19px;background-color:#c9dae1}.sweet-alert .sa-icon.sa-success{border-color:#a5dc86}.sweet-alert .sa-icon.sa-success:after,.sweet-alert .sa-icon.sa-success:before{content:'';border-radius:40px;border-radius:50%;position:absolute;width:60px;height:120px;background:#fff;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.sweet-alert .sa-icon.sa-success:before{border-radius:120px 0 0 120px;top:-7px;left:-33px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transform-origin:60px 60px;transform-origin:60px 60px}.sweet-alert .sa-icon.sa-success:after{border-radius:0 120px 120px 0;top:-11px;left:30px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transform-origin:0 60px;transform-origin:0 60px}.sweet-alert .sa-icon.sa-success .sa-placeholder{width:80px;height:80px;border:4px solid hsla(98,55%,69%,.2);border-radius:40px;border-radius:50%;box-sizing:content-box;position:absolute;left:-4px;top:-4px;z-index:2}.sweet-alert .sa-icon.sa-success .sa-fix{width:5px;height:90px;background-color:#fff;position:absolute;left:28px;top:8px;z-index:1;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.sweet-alert .sa-icon.sa-success .sa-line{height:5px;background-color:#a5dc86;display:block;border-radius:2px;position:absolute;z-index:2}.sweet-alert .sa-icon.sa-success .sa-line.sa-tip{width:25px;left:14px;top:46px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.sweet-alert .sa-icon.sa-success .sa-line.sa-long{width:47px;right:8px;top:38px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.sweet-alert .sa-icon.sa-custom{background-size:contain;border-radius:0;border:none;background-position:50%;background-repeat:no-repeat}@-webkit-keyframes showSweetAlert{0%{transform:scale(.7);-webkit-transform:scale(.7)}45%{transform:scale(1.05);-webkit-transform:scale(1.05)}80%{transform:scale(.95);-webkit-transform:scale(.95)}to{transform:scale(1);-webkit-transform:scale(1)}}@keyframes showSweetAlert{0%{transform:scale(.7);-webkit-transform:scale(.7)}45%{transform:scale(1.05);-webkit-transform:scale(1.05)}80%{transform:scale(.95);-webkit-transform:scale(.95)}to{transform:scale(1);-webkit-transform:scale(1)}}@-webkit-keyframes hideSweetAlert{0%{transform:scale(1);-webkit-transform:scale(1)}to{transform:scale(.5);-webkit-transform:scale(.5)}}@keyframes hideSweetAlert{0%{transform:scale(1);-webkit-transform:scale(1)}to{transform:scale(.5);-webkit-transform:scale(.5)}}@-webkit-keyframes slideFromTop{0%{top:0}to{top:50%}}@keyframes slideFromTop{0%{top:0}to{top:50%}}@-webkit-keyframes slideToTop{0%{top:50%}to{top:0}}@keyframes slideToTop{0%{top:50%}to{top:0}}@-webkit-keyframes slideFromBottom{0%{top:70%}to{top:50%}}@keyframes slideFromBottom{0%{top:70%}to{top:50%}}@-webkit-keyframes slideToBottom{0%{top:50%}to{top:70%}}@keyframes slideToBottom{0%{top:50%}to{top:70%}}.showSweetAlert[data-animation=pop]{-webkit-animation:showSweetAlert .3s;animation:showSweetAlert .3s}.showSweetAlert[data-animation=none]{-webkit-animation:none;animation:none}.showSweetAlert[data-animation=slide-from-top]{-webkit-animation:slideFromTop .3s;animation:slideFromTop .3s}.showSweetAlert[data-animation=slide-from-bottom]{-webkit-animation:slideFromBottom .3s;animation:slideFromBottom .3s}.hideSweetAlert[data-animation=pop]{-webkit-animation:hideSweetAlert .2s;animation:hideSweetAlert .2s}.hideSweetAlert[data-animation=none]{-webkit-animation:none;animation:none}.hideSweetAlert[data-animation=slide-from-top]{-webkit-animation:slideToTop .4s;animation:slideToTop .4s}.hideSweetAlert[data-animation=slide-from-bottom]{-webkit-animation:slideToBottom .3s;animation:slideToBottom .3s}@-webkit-keyframes animateSuccessTip{0%{width:0;left:1px;top:19px}54%{width:0;left:1px;top:19px}70%{width:50px;left:-8px;top:37px}84%{width:17px;left:21px;top:48px}to{width:25px;left:14px;top:45px}}@keyframes animateSuccessTip{0%{width:0;left:1px;top:19px}54%{width:0;left:1px;top:19px}70%{width:50px;left:-8px;top:37px}84%{width:17px;left:21px;top:48px}to{width:25px;left:14px;top:45px}}@-webkit-keyframes animateSuccessLong{0%{width:0;right:46px;top:54px}65%{width:0;right:46px;top:54px}84%{width:55px;right:0;top:35px}to{width:47px;right:8px;top:38px}}@keyframes animateSuccessLong{0%{width:0;right:46px;top:54px}65%{width:0;right:46px;top:54px}84%{width:55px;right:0;top:35px}to{width:47px;right:8px;top:38px}}@-webkit-keyframes rotatePlaceholder{0%{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}5%{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}12%{transform:rotate(-405deg);-webkit-transform:rotate(-405deg)}to{transform:rotate(-405deg);-webkit-transform:rotate(-405deg)}}@keyframes rotatePlaceholder{0%{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}5%{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}12%{transform:rotate(-405deg);-webkit-transform:rotate(-405deg)}to{transform:rotate(-405deg);-webkit-transform:rotate(-405deg)}}.animateSuccessTip{-webkit-animation:animateSuccessTip .75s;animation:animateSuccessTip .75s}.animateSuccessLong{-webkit-animation:animateSuccessLong .75s;animation:animateSuccessLong .75s}.sa-icon.sa-success.animate:after{-webkit-animation:rotatePlaceholder 4.25s ease-in;animation:rotatePlaceholder 4.25s ease-in}@-webkit-keyframes animateErrorIcon{0%{transform:rotateX(100deg);-webkit-transform:rotateX(100deg);opacity:0}to{transform:rotateX(0deg);-webkit-transform:rotateX(0deg);opacity:1}}@keyframes animateErrorIcon{0%{transform:rotateX(100deg);-webkit-transform:rotateX(100deg);opacity:0}to{transform:rotateX(0deg);-webkit-transform:rotateX(0deg);opacity:1}}.animateErrorIcon{-webkit-animation:animateErrorIcon .5s;animation:animateErrorIcon .5s}@-webkit-keyframes animateXMark{0%{transform:scale(.4);-webkit-transform:scale(.4);margin-top:26px;opacity:0}50%{transform:scale(.4);-webkit-transform:scale(.4);margin-top:26px;opacity:0}80%{transform:scale(1.15);-webkit-transform:scale(1.15);margin-top:-6px}to{transform:scale(1);-webkit-transform:scale(1);margin-top:0;opacity:1}}@keyframes animateXMark{0%{transform:scale(.4);-webkit-transform:scale(.4);margin-top:26px;opacity:0}50%{transform:scale(.4);-webkit-transform:scale(.4);margin-top:26px;opacity:0}80%{transform:scale(1.15);-webkit-transform:scale(1.15);margin-top:-6px}to{transform:scale(1);-webkit-transform:scale(1);margin-top:0;opacity:1}}.animateXMark{-webkit-animation:animateXMark .5s;animation:animateXMark .5s}@-webkit-keyframes pulseWarning{0%{border-color:#f8d486}to{border-color:#f8bb86}}@keyframes pulseWarning{0%{border-color:#f8d486}to{border-color:#f8bb86}}.pulseWarning{-webkit-animation:pulseWarning .75s infinite alternate;animation:pulseWarning .75s infinite alternate}@-webkit-keyframes pulseWarningIns{0%{background-color:#f8d486}to{background-color:#f8bb86}}@keyframes pulseWarningIns{0%{background-color:#f8d486}to{background-color:#f8bb86}}.pulseWarningIns{-webkit-animation:pulseWarningIns .75s infinite alternate;animation:pulseWarningIns .75s infinite alternate}@-webkit-keyframes rotate-loading{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes rotate-loading{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.sweet-alert .sa-icon.sa-error .sa-line.sa-left{-ms-transform:rotate(45deg)\9}.sweet-alert .sa-icon.sa-error .sa-line.sa-right{-ms-transform:rotate(-45deg)\9}.sweet-alert .sa-icon.sa-success{border-color:transparent\9}.sweet-alert .sa-icon.sa-success .sa-line.sa-tip{-ms-transform:rotate(45deg)\9}.sweet-alert .sa-icon.sa-success .sa-line.sa-long{-ms-transform:rotate(-45deg)\9} - -/*! - * Load Awesome v1.1.0 (http://github.danielcardoso.net/load-awesome/) - * Copyright 2015 Daniel Cardoso <@DanielCardoso> - * Licensed under MIT - */.la-ball-fall,.la-ball-fall>div{position:relative;box-sizing:border-box}.la-ball-fall{display:block;font-size:0;color:#fff}.la-ball-fall.la-dark{color:#333}.la-ball-fall>div{display:inline-block;float:none;background-color:currentColor;border:0 solid currentColor}.la-ball-fall{width:54px;height:18px}.la-ball-fall>div{width:10px;height:10px;margin:4px;border-radius:100%;opacity:0;-webkit-animation:ball-fall 1s ease-in-out infinite;animation:ball-fall 1s ease-in-out infinite}.la-ball-fall>div:nth-child(1){-webkit-animation-delay:-.2s;animation-delay:-.2s}.la-ball-fall>div:nth-child(2){-webkit-animation-delay:-.1s;animation-delay:-.1s}.la-ball-fall>div:nth-child(3){-webkit-animation-delay:0ms;animation-delay:0ms}.la-ball-fall.la-sm{width:26px;height:8px}.la-ball-fall.la-sm>div{width:4px;height:4px;margin:2px}.la-ball-fall.la-2x{width:108px;height:36px}.la-ball-fall.la-2x>div{width:20px;height:20px;margin:8px}.la-ball-fall.la-3x{width:162px;height:54px}.la-ball-fall.la-3x>div{width:30px;height:30px;margin:12px}@-webkit-keyframes ball-fall{0%{opacity:0;-webkit-transform:translateY(-145%);transform:translateY(-145%)}10%{opacity:.5}20%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}80%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}90%{opacity:.5}to{opacity:0;-webkit-transform:translateY(145%);transform:translateY(145%)}}@keyframes ball-fall{0%{opacity:0;-webkit-transform:translateY(-145%);transform:translateY(-145%)}10%{opacity:.5}20%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}80%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}90%{opacity:.5}to{opacity:0;-webkit-transform:translateY(145%);transform:translateY(145%)}}@font-face{font-family:octicons-link;src:url(data:font/woff;charset=utf-8;base64,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) format('woff')}.markdown-body{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;color:#333;font-family:Helvetica Neue,Helvetica,Segoe UI,Arial,freesans,sans-serif;font-size:16px;line-height:1.6;word-wrap:break-word}.markdown-body a{background-color:transparent;-webkit-text-decoration-skip:objects}.markdown-body a:active,.markdown-body a:hover{outline-width:0}.markdown-body strong{font-weight:inherit;font-weight:bolder}.markdown-body h1{font-size:2em;margin:.67em 0}.markdown-body img{border-style:none}.markdown-body svg:not(:root){overflow:hidden}.markdown-body code,.markdown-body kbd,.markdown-body pre{font-family:monospace,monospace;font-size:1em}.markdown-body hr{box-sizing:content-box;height:0;overflow:visible}.markdown-body input{font:inherit;margin:0;overflow:visible}.markdown-body [type=button]:-moz-focusring,.markdown-body [type=reset]:-moz-focusring,.markdown-body [type=submit]:-moz-focusring,.markdown-body button:-moz-focusring{outline:1px dotted ButtonText}.markdown-body [type=checkbox]{box-sizing:border-box;padding:0}.markdown-body table{border-spacing:0;border-collapse:collapse}.markdown-body td,.markdown-body th{padding:0}.markdown-body *{box-sizing:border-box}.markdown-body input{font:13px/1.4 Helvetica,arial,nimbussansl,liberationsans,freesans,clean,sans-serif}.markdown-body a{color:#4078c0;text-decoration:none}.markdown-body a:active,.markdown-body a:hover{text-decoration:underline}.markdown-body hr{height:0;margin:15px 0;overflow:hidden;background:transparent;border:0;border-bottom:1px solid #ddd}.markdown-body hr:after,.markdown-body hr:before{display:table;content:""}.markdown-body hr:after{clear:both}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:0;margin-bottom:0;line-height:1.5}.markdown-body h1{font-size:30px}.markdown-body h2{font-size:21px}.markdown-body h3{font-size:16px}.markdown-body h4{font-size:14px}.markdown-body h5{font-size:12px}.markdown-body h6{font-size:11px}.markdown-body p{margin-top:0;margin-bottom:10px}.markdown-body blockquote{margin:0}.markdown-body ol,.markdown-body ul{padding-left:0;margin-top:0;margin-bottom:0}.markdown-body ol ol,.markdown-body ul ol{list-style-type:lower-roman}.markdown-body ol ol ol,.markdown-body ol ul ol,.markdown-body ul ol ol,.markdown-body ul ul ol{list-style-type:lower-alpha}.markdown-body dd{margin-left:0}.markdown-body code{font-family:Consolas,Liberation Mono,Menlo,Courier,monospace;font-size:12px}.markdown-body pre{margin-top:0;margin-bottom:0;font:12px Consolas,Liberation Mono,Menlo,Courier,monospace}.markdown-body .pl-0{padding-left:0!important}.markdown-body .pl-1{padding-left:3px!important}.markdown-body .pl-2{padding-left:6px!important}.markdown-body .pl-3{padding-left:12px!important}.markdown-body .pl-4{padding-left:24px!important}.markdown-body .pl-5{padding-left:36px!important}.markdown-body .pl-6{padding-left:48px!important}.markdown-body .form-select::-ms-expand{opacity:0}.markdown-body:after,.markdown-body:before{display:table;content:""}.markdown-body:after{clear:both}.markdown-body>:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdown-body a:not([href]){color:inherit;text-decoration:none}.markdown-body .anchor{display:inline-block;padding-right:2px;margin-left:-18px}.markdown-body .anchor:focus{outline:none}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:1em;margin-bottom:16px;font-weight:700;line-height:1.4}.markdown-body h1 .octicon-link,.markdown-body h2 .octicon-link,.markdown-body h3 .octicon-link,.markdown-body h4 .octicon-link,.markdown-body h5 .octicon-link,.markdown-body h6 .octicon-link{color:#000;vertical-align:middle;visibility:hidden}.markdown-body h1:hover .anchor,.markdown-body h2:hover .anchor,.markdown-body h3:hover .anchor,.markdown-body h4:hover .anchor,.markdown-body h5:hover .anchor,.markdown-body h6:hover .anchor{text-decoration:none}.markdown-body h1:hover .anchor .octicon-link,.markdown-body h2:hover .anchor .octicon-link,.markdown-body h3:hover .anchor .octicon-link,.markdown-body h4:hover .anchor .octicon-link,.markdown-body h5:hover .anchor .octicon-link,.markdown-body h6:hover .anchor .octicon-link{visibility:visible}.markdown-body h1{padding-bottom:.3em;font-size:2.25em;line-height:1.2;border-bottom:1px solid #eee}.markdown-body h1 .anchor{line-height:1}.markdown-body h2{padding-bottom:.3em;font-size:1.75em;line-height:1.225;border-bottom:1px solid #eee}.markdown-body h2 .anchor{line-height:1}.markdown-body h3{font-size:1.5em;line-height:1.43}.markdown-body h3 .anchor{line-height:1.2}.markdown-body h4{font-size:1.25em}.markdown-body h4 .anchor{line-height:1.2}.markdown-body h5{font-size:1em}.markdown-body h5 .anchor{line-height:1.1}.markdown-body h6{font-size:1em;color:#777}.markdown-body h6 .anchor{line-height:1.1}.markdown-body blockquote,.markdown-body dl,.markdown-body ol,.markdown-body p,.markdown-body pre,.markdown-body table,.markdown-body ul{margin-top:0;margin-bottom:16px}.markdown-body hr{height:4px;padding:0;margin:16px 0;background-color:#e7e7e7;border:0 none}.markdown-body ol,.markdown-body ul{padding-left:2em}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:0;margin-bottom:0}.markdown-body li>p{margin-top:16px}.markdown-body dl{padding:0}.markdown-body dl dt{padding:0;margin-top:16px;font-size:1em;font-style:italic;font-weight:700}.markdown-body dl dd{padding:0 16px;margin-bottom:16px}.markdown-body blockquote{padding:0 15px;color:#777;border-left:4px solid #ddd}.markdown-body blockquote>:first-child{margin-top:0}.markdown-body blockquote>:last-child{margin-bottom:0}.markdown-body table{display:block;width:100%;overflow:auto;word-break:normal;word-break:keep-all}.markdown-body table th{font-weight:700}.markdown-body table td,.markdown-body table th{padding:6px 13px;border:1px solid #ddd}.markdown-body table tr{background-color:#fff;border-top:1px solid #ccc}.markdown-body table tr:nth-child(2n){background-color:#f8f8f8}.markdown-body img{max-width:100%;box-sizing:content-box;background-color:#fff}.markdown-body code{padding:0;padding-top:.2em;padding-bottom:.2em;margin:0;font-size:85%;background-color:rgba(0,0,0,.04);border-radius:3px}.markdown-body code:after,.markdown-body code:before{letter-spacing:-.2em;content:"\00a0"}.markdown-body pre>code{padding:0;margin:0;font-size:100%;word-break:normal;white-space:pre;background:transparent;border:0}.markdown-body .highlight{margin-bottom:16px}.markdown-body .highlight pre,.markdown-body pre{padding:16px;overflow:auto;font-size:85%;line-height:1.45;background-color:#f7f7f7;border-radius:3px}.markdown-body .highlight pre{margin-bottom:0;word-break:normal}.markdown-body pre{word-wrap:normal}.markdown-body pre code{display:inline;max-width:none;padding:0;margin:0;overflow:initial;line-height:inherit;word-wrap:normal;background-color:transparent;border:0}.markdown-body pre code:after,.markdown-body pre code:before{content:normal}.markdown-body kbd{display:inline-block;padding:3px 5px;font-size:11px;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:1px solid #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb}.markdown-body .pl-c{color:#969896}.markdown-body .pl-c1,.markdown-body .pl-s .pl-v{color:#0086b3}.markdown-body .pl-e,.markdown-body .pl-en{color:#795da3}.markdown-body .pl-s .pl-s1,.markdown-body .pl-smi{color:#333}.markdown-body .pl-ent{color:#63a35c}.markdown-body .pl-k{color:#a71d5d}.markdown-body .pl-pds,.markdown-body .pl-s,.markdown-body .pl-s .pl-pse .pl-s1,.markdown-body .pl-sr,.markdown-body .pl-sr .pl-cce,.markdown-body .pl-sr .pl-sra,.markdown-body .pl-sr .pl-sre{color:#183691}.markdown-body .pl-v{color:#ed6a43}.markdown-body .pl-id{color:#b52a1d}.markdown-body .pl-ii{background-color:#b52a1d;color:#f8f8f8}.markdown-body .pl-sr .pl-cce{color:#63a35c;font-weight:700}.markdown-body .pl-ml{color:#693a17}.markdown-body .pl-mh,.markdown-body .pl-mh .pl-en,.markdown-body .pl-ms{color:#1d3e81;font-weight:700}.markdown-body .pl-mq{color:teal}.markdown-body .pl-mi{color:#333;font-style:italic}.markdown-body .pl-mb{color:#333;font-weight:700}.markdown-body .pl-md{background-color:#ffecec;color:#bd2c00}.markdown-body .pl-mi1{background-color:#eaffea;color:#55a532}.markdown-body .pl-mdr{color:#795da3;font-weight:700}.markdown-body .pl-mo{color:#1d3e81}.markdown-body kbd{display:inline-block;padding:3px 5px;font:11px Consolas,Liberation Mono,Menlo,Courier,monospace;line-height:10px;color:#555;vertical-align:middle;background-color:#fcfcfc;border:1px solid #ccc;border-bottom-color:#bbb;border-radius:3px;box-shadow:inset 0 -1px 0 #bbb}.markdown-body .full-commit .btn-outline:not(:disabled):hover{color:#4078c0;border:1px solid #4078c0}.markdown-body :checked+.radio-label{position:relative;z-index:1;border-color:#4078c0}.markdown-body .octicon{display:inline-block;vertical-align:text-top;fill:currentColor}.markdown-body .task-list-item{list-style-type:none}.markdown-body .task-list-item+.task-list-item{margin-top:3px}.markdown-body .task-list-item input{margin:0 .2em .25em -1.6em;vertical-align:middle}.markdown-body hr{border-bottom-color:#eee} -/*! - Ionicons, v2.0.1 - Created by Ben Sperry for the Ionic Framework, http://ionicons.com/ - https://twitter.com/benjsperry https://twitter.com/ionicframework - MIT License: https://github.com/driftyco/ionicons - - Android-style icons originally built by Google’s - Material Design Icons: https://github.com/google/material-design-icons - used under CC BY http://creativecommons.org/licenses/by/4.0/ - Modified icons to fit ionicon’s grid from original. -*/@font-face{font-family:Ionicons;src:url(../../../fonts/ionicons.eot?v=2.0.1);src:url(../../../fonts/ionicons.eot?v=2.0.1#iefix) format("embedded-opentype"),url(../../../fonts/ionicons.ttf?v=2.0.1) format("truetype"),url(../../../fonts/ionicons.woff?v=2.0.1) format("woff"),url(../../../fonts/ionicons.svg?v=2.0.1#Ionicons) format("svg");font-weight:400;font-style:normal}.ion,.ion-alert-circled:before,.ion-alert:before,.ion-android-add-circle:before,.ion-android-add:before,.ion-android-alarm-clock:before,.ion-android-alert:before,.ion-android-apps:before,.ion-android-archive:before,.ion-android-arrow-back:before,.ion-android-arrow-down:before,.ion-android-arrow-dropdown-circle:before,.ion-android-arrow-dropdown:before,.ion-android-arrow-dropleft-circle:before,.ion-android-arrow-dropleft:before,.ion-android-arrow-dropright-circle:before,.ion-android-arrow-dropright:before,.ion-android-arrow-dropup-circle:before,.ion-android-arrow-dropup:before,.ion-android-arrow-forward:before,.ion-android-arrow-up:before,.ion-android-attach:before,.ion-android-bar:before,.ion-android-bicycle:before,.ion-android-boat:before,.ion-android-bookmark:before,.ion-android-bulb:before,.ion-android-bus:before,.ion-android-calendar:before,.ion-android-call:before,.ion-android-camera:before,.ion-android-cancel:before,.ion-android-car:before,.ion-android-cart:before,.ion-android-chat:before,.ion-android-checkbox-blank:before,.ion-android-checkbox-outline-blank:before,.ion-android-checkbox-outline:before,.ion-android-checkbox:before,.ion-android-checkmark-circle:before,.ion-android-clipboard:before,.ion-android-close:before,.ion-android-cloud-circle:before,.ion-android-cloud-done:before,.ion-android-cloud-outline:before,.ion-android-cloud:before,.ion-android-color-palette:before,.ion-android-compass:before,.ion-android-contact:before,.ion-android-contacts:before,.ion-android-contract:before,.ion-android-create:before,.ion-android-delete:before,.ion-android-desktop:before,.ion-android-document:before,.ion-android-done-all:before,.ion-android-done:before,.ion-android-download:before,.ion-android-drafts:before,.ion-android-exit:before,.ion-android-expand:before,.ion-android-favorite-outline:before,.ion-android-favorite:before,.ion-android-film:before,.ion-android-folder-open:before,.ion-android-folder:before,.ion-android-funnel:before,.ion-android-globe:before,.ion-android-hand:before,.ion-android-hangout:before,.ion-android-happy:before,.ion-android-home:before,.ion-android-image:before,.ion-android-laptop:before,.ion-android-list:before,.ion-android-locate:before,.ion-android-lock:before,.ion-android-mail:before,.ion-android-map:before,.ion-android-menu:before,.ion-android-microphone-off:before,.ion-android-microphone:before,.ion-android-more-horizontal:before,.ion-android-more-vertical:before,.ion-android-navigate:before,.ion-android-notifications-none:before,.ion-android-notifications-off:before,.ion-android-notifications:before,.ion-android-open:before,.ion-android-options:before,.ion-android-people:before,.ion-android-person-add:before,.ion-android-person:before,.ion-android-phone-landscape:before,.ion-android-phone-portrait:before,.ion-android-pin:before,.ion-android-plane:before,.ion-android-playstore:before,.ion-android-print:before,.ion-android-radio-button-off:before,.ion-android-radio-button-on:before,.ion-android-refresh:before,.ion-android-remove-circle:before,.ion-android-remove:before,.ion-android-restaurant:before,.ion-android-sad:before,.ion-android-search:before,.ion-android-send:before,.ion-android-settings:before,.ion-android-share-alt:before,.ion-android-share:before,.ion-android-star-half:before,.ion-android-star-outline:before,.ion-android-star:before,.ion-android-stopwatch:before,.ion-android-subway:before,.ion-android-sunny:before,.ion-android-sync:before,.ion-android-textsms:before,.ion-android-time:before,.ion-android-train:before,.ion-android-unlock:before,.ion-android-upload:before,.ion-android-volume-down:before,.ion-android-volume-mute:before,.ion-android-volume-off:before,.ion-android-volume-up:before,.ion-android-walk:before,.ion-android-warning:before,.ion-android-watch:before,.ion-android-wifi:before,.ion-aperture:before,.ion-archive:before,.ion-arrow-down-a:before,.ion-arrow-down-b:before,.ion-arrow-down-c:before,.ion-arrow-expand:before,.ion-arrow-graph-down-left:before,.ion-arrow-graph-down-right:before,.ion-arrow-graph-up-left:before,.ion-arrow-graph-up-right:before,.ion-arrow-left-a:before,.ion-arrow-left-b:before,.ion-arrow-left-c:before,.ion-arrow-move:before,.ion-arrow-resize:before,.ion-arrow-return-left:before,.ion-arrow-return-right:before,.ion-arrow-right-a:before,.ion-arrow-right-b:before,.ion-arrow-right-c:before,.ion-arrow-shrink:before,.ion-arrow-swap:before,.ion-arrow-up-a:before,.ion-arrow-up-b:before,.ion-arrow-up-c:before,.ion-asterisk:before,.ion-at:before,.ion-backspace-outline:before,.ion-backspace:before,.ion-bag:before,.ion-battery-charging:before,.ion-battery-empty:before,.ion-battery-full:before,.ion-battery-half:before,.ion-battery-low:before,.ion-beaker:before,.ion-beer:before,.ion-bluetooth:before,.ion-bonfire:before,.ion-bookmark:before,.ion-bowtie:before,.ion-briefcase:before,.ion-bug:before,.ion-calculator:before,.ion-calendar:before,.ion-camera:before,.ion-card:before,.ion-cash:before,.ion-chatbox-working:before,.ion-chatbox:before,.ion-chatboxes:before,.ion-chatbubble-working:before,.ion-chatbubble:before,.ion-chatbubbles:before,.ion-checkmark-circled:before,.ion-checkmark-round:before,.ion-checkmark:before,.ion-chevron-down:before,.ion-chevron-left:before,.ion-chevron-right:before,.ion-chevron-up:before,.ion-clipboard:before,.ion-clock:before,.ion-close-circled:before,.ion-close-round:before,.ion-close:before,.ion-closed-captioning:before,.ion-cloud:before,.ion-code-download:before,.ion-code-working:before,.ion-code:before,.ion-coffee:before,.ion-compass:before,.ion-compose:before,.ion-connection-bars:before,.ion-contrast:before,.ion-crop:before,.ion-cube:before,.ion-disc:before,.ion-document-text:before,.ion-document:before,.ion-drag:before,.ion-earth:before,.ion-easel:before,.ion-edit:before,.ion-egg:before,.ion-eject:before,.ion-email-unread:before,.ion-email:before,.ion-erlenmeyer-flask-bubbles:before,.ion-erlenmeyer-flask:before,.ion-eye-disabled:before,.ion-eye:before,.ion-female:before,.ion-filing:before,.ion-film-marker:before,.ion-fireball:before,.ion-flag:before,.ion-flame:before,.ion-flash-off:before,.ion-flash:before,.ion-folder:before,.ion-fork-repo:before,.ion-fork:before,.ion-forward:before,.ion-funnel:before,.ion-gear-a:before,.ion-gear-b:before,.ion-grid:before,.ion-hammer:before,.ion-happy-outline:before,.ion-happy:before,.ion-headphone:before,.ion-heart-broken:before,.ion-heart:before,.ion-help-buoy:before,.ion-help-circled:before,.ion-help:before,.ion-home:before,.ion-icecream:before,.ion-image:before,.ion-images:before,.ion-information-circled:before,.ion-information:before,.ion-ionic:before,.ion-ios-alarm-outline:before,.ion-ios-alarm:before,.ion-ios-albums-outline:before,.ion-ios-albums:before,.ion-ios-americanfootball-outline:before,.ion-ios-americanfootball:before,.ion-ios-analytics-outline:before,.ion-ios-analytics:before,.ion-ios-arrow-back:before,.ion-ios-arrow-down:before,.ion-ios-arrow-forward:before,.ion-ios-arrow-left:before,.ion-ios-arrow-right:before,.ion-ios-arrow-thin-down:before,.ion-ios-arrow-thin-left:before,.ion-ios-arrow-thin-right:before,.ion-ios-arrow-thin-up:before,.ion-ios-arrow-up:before,.ion-ios-at-outline:before,.ion-ios-at:before,.ion-ios-barcode-outline:before,.ion-ios-barcode:before,.ion-ios-baseball-outline:before,.ion-ios-baseball:before,.ion-ios-basketball-outline:before,.ion-ios-basketball:before,.ion-ios-bell-outline:before,.ion-ios-bell:before,.ion-ios-body-outline:before,.ion-ios-body:before,.ion-ios-bolt-outline:before,.ion-ios-bolt:before,.ion-ios-book-outline:before,.ion-ios-book:before,.ion-ios-bookmarks-outline:before,.ion-ios-bookmarks:before,.ion-ios-box-outline:before,.ion-ios-box:before,.ion-ios-briefcase-outline:before,.ion-ios-briefcase:before,.ion-ios-browsers-outline:before,.ion-ios-browsers:before,.ion-ios-calculator-outline:before,.ion-ios-calculator:before,.ion-ios-calendar-outline:before,.ion-ios-calendar:before,.ion-ios-camera-outline:before,.ion-ios-camera:before,.ion-ios-cart-outline:before,.ion-ios-cart:before,.ion-ios-chatboxes-outline:before,.ion-ios-chatboxes:before,.ion-ios-chatbubble-outline:before,.ion-ios-chatbubble:before,.ion-ios-checkmark-empty:before,.ion-ios-checkmark-outline:before,.ion-ios-checkmark:before,.ion-ios-circle-filled:before,.ion-ios-circle-outline:before,.ion-ios-clock-outline:before,.ion-ios-clock:before,.ion-ios-close-empty:before,.ion-ios-close-outline:before,.ion-ios-close:before,.ion-ios-cloud-download-outline:before,.ion-ios-cloud-download:before,.ion-ios-cloud-outline:before,.ion-ios-cloud-upload-outline:before,.ion-ios-cloud-upload:before,.ion-ios-cloud:before,.ion-ios-cloudy-night-outline:before,.ion-ios-cloudy-night:before,.ion-ios-cloudy-outline:before,.ion-ios-cloudy:before,.ion-ios-cog-outline:before,.ion-ios-cog:before,.ion-ios-color-filter-outline:before,.ion-ios-color-filter:before,.ion-ios-color-wand-outline:before,.ion-ios-color-wand:before,.ion-ios-compose-outline:before,.ion-ios-compose:before,.ion-ios-contact-outline:before,.ion-ios-contact:before,.ion-ios-copy-outline:before,.ion-ios-copy:before,.ion-ios-crop-strong:before,.ion-ios-crop:before,.ion-ios-download-outline:before,.ion-ios-download:before,.ion-ios-drag:before,.ion-ios-email-outline:before,.ion-ios-email:before,.ion-ios-eye-outline:before,.ion-ios-eye:before,.ion-ios-fastforward-outline:before,.ion-ios-fastforward:before,.ion-ios-filing-outline:before,.ion-ios-filing:before,.ion-ios-film-outline:before,.ion-ios-film:before,.ion-ios-flag-outline:before,.ion-ios-flag:before,.ion-ios-flame-outline:before,.ion-ios-flame:before,.ion-ios-flask-outline:before,.ion-ios-flask:before,.ion-ios-flower-outline:before,.ion-ios-flower:before,.ion-ios-folder-outline:before,.ion-ios-folder:before,.ion-ios-football-outline:before,.ion-ios-football:before,.ion-ios-game-controller-a-outline:before,.ion-ios-game-controller-a:before,.ion-ios-game-controller-b-outline:before,.ion-ios-game-controller-b:before,.ion-ios-gear-outline:before,.ion-ios-gear:before,.ion-ios-glasses-outline:before,.ion-ios-glasses:before,.ion-ios-grid-view-outline:before,.ion-ios-grid-view:before,.ion-ios-heart-outline:before,.ion-ios-heart:before,.ion-ios-help-empty:before,.ion-ios-help-outline:before,.ion-ios-help:before,.ion-ios-home-outline:before,.ion-ios-home:before,.ion-ios-infinite-outline:before,.ion-ios-infinite:before,.ion-ios-information-empty:before,.ion-ios-information-outline:before,.ion-ios-information:before,.ion-ios-ionic-outline:before,.ion-ios-keypad-outline:before,.ion-ios-keypad:before,.ion-ios-lightbulb-outline:before,.ion-ios-lightbulb:before,.ion-ios-list-outline:before,.ion-ios-list:before,.ion-ios-location-outline:before,.ion-ios-location:before,.ion-ios-locked-outline:before,.ion-ios-locked:before,.ion-ios-loop-strong:before,.ion-ios-loop:before,.ion-ios-medical-outline:before,.ion-ios-medical:before,.ion-ios-medkit-outline:before,.ion-ios-medkit:before,.ion-ios-mic-off:before,.ion-ios-mic-outline:before,.ion-ios-mic:before,.ion-ios-minus-empty:before,.ion-ios-minus-outline:before,.ion-ios-minus:before,.ion-ios-monitor-outline:before,.ion-ios-monitor:before,.ion-ios-moon-outline:before,.ion-ios-moon:before,.ion-ios-more-outline:before,.ion-ios-more:before,.ion-ios-musical-note:before,.ion-ios-musical-notes:before,.ion-ios-navigate-outline:before,.ion-ios-navigate:before,.ion-ios-nutrition-outline:before,.ion-ios-nutrition:before,.ion-ios-paper-outline:before,.ion-ios-paper:before,.ion-ios-paperplane-outline:before,.ion-ios-paperplane:before,.ion-ios-partlysunny-outline:before,.ion-ios-partlysunny:before,.ion-ios-pause-outline:before,.ion-ios-pause:before,.ion-ios-paw-outline:before,.ion-ios-paw:before,.ion-ios-people-outline:before,.ion-ios-people:before,.ion-ios-person-outline:before,.ion-ios-person:before,.ion-ios-personadd-outline:before,.ion-ios-personadd:before,.ion-ios-photos-outline:before,.ion-ios-photos:before,.ion-ios-pie-outline:before,.ion-ios-pie:before,.ion-ios-pint-outline:before,.ion-ios-pint:before,.ion-ios-play-outline:before,.ion-ios-play:before,.ion-ios-plus-empty:before,.ion-ios-plus-outline:before,.ion-ios-plus:before,.ion-ios-pricetag-outline:before,.ion-ios-pricetag:before,.ion-ios-pricetags-outline:before,.ion-ios-pricetags:before,.ion-ios-printer-outline:before,.ion-ios-printer:before,.ion-ios-pulse-strong:before,.ion-ios-pulse:before,.ion-ios-rainy-outline:before,.ion-ios-rainy:before,.ion-ios-recording-outline:before,.ion-ios-recording:before,.ion-ios-redo-outline:before,.ion-ios-redo:before,.ion-ios-refresh-empty:before,.ion-ios-refresh-outline:before,.ion-ios-refresh:before,.ion-ios-reload:before,.ion-ios-reverse-camera-outline:before,.ion-ios-reverse-camera:before,.ion-ios-rewind-outline:before,.ion-ios-rewind:before,.ion-ios-rose-outline:before,.ion-ios-rose:before,.ion-ios-search-strong:before,.ion-ios-search:before,.ion-ios-settings-strong:before,.ion-ios-settings:before,.ion-ios-shuffle-strong:before,.ion-ios-shuffle:before,.ion-ios-skipbackward-outline:before,.ion-ios-skipbackward:before,.ion-ios-skipforward-outline:before,.ion-ios-skipforward:before,.ion-ios-snowy:before,.ion-ios-speedometer-outline:before,.ion-ios-speedometer:before,.ion-ios-star-half:before,.ion-ios-star-outline:before,.ion-ios-star:before,.ion-ios-stopwatch-outline:before,.ion-ios-stopwatch:before,.ion-ios-sunny-outline:before,.ion-ios-sunny:before,.ion-ios-telephone-outline:before,.ion-ios-telephone:before,.ion-ios-tennisball-outline:before,.ion-ios-tennisball:before,.ion-ios-thunderstorm-outline:before,.ion-ios-thunderstorm:before,.ion-ios-time-outline:before,.ion-ios-time:before,.ion-ios-timer-outline:before,.ion-ios-timer:before,.ion-ios-toggle-outline:before,.ion-ios-toggle:before,.ion-ios-trash-outline:before,.ion-ios-trash:before,.ion-ios-undo-outline:before,.ion-ios-undo:before,.ion-ios-unlocked-outline:before,.ion-ios-unlocked:before,.ion-ios-upload-outline:before,.ion-ios-upload:before,.ion-ios-videocam-outline:before,.ion-ios-videocam:before,.ion-ios-volume-high:before,.ion-ios-volume-low:before,.ion-ios-wineglass-outline:before,.ion-ios-wineglass:before,.ion-ios-world-outline:before,.ion-ios-world:before,.ion-ipad:before,.ion-iphone:before,.ion-ipod:before,.ion-jet:before,.ion-key:before,.ion-knife:before,.ion-laptop:before,.ion-leaf:before,.ion-levels:before,.ion-lightbulb:before,.ion-link:before,.ion-load-a:before,.ion-load-b:before,.ion-load-c:before,.ion-load-d:before,.ion-location:before,.ion-lock-combination:before,.ion-locked:before,.ion-log-in:before,.ion-log-out:before,.ion-loop:before,.ion-magnet:before,.ion-male:before,.ion-man:before,.ion-map:before,.ion-medkit:before,.ion-merge:before,.ion-mic-a:before,.ion-mic-b:before,.ion-mic-c:before,.ion-minus-circled:before,.ion-minus-round:before,.ion-minus:before,.ion-model-s:before,.ion-monitor:before,.ion-more:before,.ion-mouse:before,.ion-music-note:before,.ion-navicon-round:before,.ion-navicon:before,.ion-navigate:before,.ion-network:before,.ion-no-smoking:before,.ion-nuclear:before,.ion-outlet:before,.ion-paintbrush:before,.ion-paintbucket:before,.ion-paper-airplane:before,.ion-paperclip:before,.ion-pause:before,.ion-person-add:before,.ion-person-stalker:before,.ion-person:before,.ion-pie-graph:before,.ion-pin:before,.ion-pinpoint:before,.ion-pizza:before,.ion-plane:before,.ion-planet:before,.ion-play:before,.ion-playstation:before,.ion-plus-circled:before,.ion-plus-round:before,.ion-plus:before,.ion-podium:before,.ion-pound:before,.ion-power:before,.ion-pricetag:before,.ion-pricetags:before,.ion-printer:before,.ion-pull-request:before,.ion-qr-scanner:before,.ion-quote:before,.ion-radio-waves:before,.ion-record:before,.ion-refresh:before,.ion-reply-all:before,.ion-reply:before,.ion-ribbon-a:before,.ion-ribbon-b:before,.ion-sad-outline:before,.ion-sad:before,.ion-scissors:before,.ion-search:before,.ion-settings:before,.ion-share:before,.ion-shuffle:before,.ion-skip-backward:before,.ion-skip-forward:before,.ion-social-android-outline:before,.ion-social-android:before,.ion-social-angular-outline:before,.ion-social-angular:before,.ion-social-apple-outline:before,.ion-social-apple:before,.ion-social-bitcoin-outline:before,.ion-social-bitcoin:before,.ion-social-buffer-outline:before,.ion-social-buffer:before,.ion-social-chrome-outline:before,.ion-social-chrome:before,.ion-social-codepen-outline:before,.ion-social-codepen:before,.ion-social-css3-outline:before,.ion-social-css3:before,.ion-social-designernews-outline:before,.ion-social-designernews:before,.ion-social-dribbble-outline:before,.ion-social-dribbble:before,.ion-social-dropbox-outline:before,.ion-social-dropbox:before,.ion-social-euro-outline:before,.ion-social-euro:before,.ion-social-facebook-outline:before,.ion-social-facebook:before,.ion-social-foursquare-outline:before,.ion-social-foursquare:before,.ion-social-freebsd-devil:before,.ion-social-github-outline:before,.ion-social-github:before,.ion-social-google-outline:before,.ion-social-google:before,.ion-social-googleplus-outline:before,.ion-social-googleplus:before,.ion-social-hackernews-outline:before,.ion-social-hackernews:before,.ion-social-html5-outline:before,.ion-social-html5:before,.ion-social-instagram-outline:before,.ion-social-instagram:before,.ion-social-javascript-outline:before,.ion-social-javascript:before,.ion-social-linkedin-outline:before,.ion-social-linkedin:before,.ion-social-markdown:before,.ion-social-nodejs:before,.ion-social-octocat:before,.ion-social-pinterest-outline:before,.ion-social-pinterest:before,.ion-social-python:before,.ion-social-reddit-outline:before,.ion-social-reddit:before,.ion-social-rss-outline:before,.ion-social-rss:before,.ion-social-sass:before,.ion-social-skype-outline:before,.ion-social-skype:before,.ion-social-snapchat-outline:before,.ion-social-snapchat:before,.ion-social-tumblr-outline:before,.ion-social-tumblr:before,.ion-social-tux:before,.ion-social-twitch-outline:before,.ion-social-twitch:before,.ion-social-twitter-outline:before,.ion-social-twitter:before,.ion-social-usd-outline:before,.ion-social-usd:before,.ion-social-vimeo-outline:before,.ion-social-vimeo:before,.ion-social-whatsapp-outline:before,.ion-social-whatsapp:before,.ion-social-windows-outline:before,.ion-social-windows:before,.ion-social-wordpress-outline:before,.ion-social-wordpress:before,.ion-social-yahoo-outline:before,.ion-social-yahoo:before,.ion-social-yen-outline:before,.ion-social-yen:before,.ion-social-youtube-outline:before,.ion-social-youtube:before,.ion-soup-can-outline:before,.ion-soup-can:before,.ion-speakerphone:before,.ion-speedometer:before,.ion-spoon:before,.ion-star:before,.ion-stats-bars:before,.ion-steam:before,.ion-stop:before,.ion-thermometer:before,.ion-thumbsdown:before,.ion-thumbsup:before,.ion-toggle-filled:before,.ion-toggle:before,.ion-transgender:before,.ion-trash-a:before,.ion-trash-b:before,.ion-trophy:before,.ion-tshirt-outline:before,.ion-tshirt:before,.ion-umbrella:before,.ion-university:before,.ion-unlocked:before,.ion-upload:before,.ion-usb:before,.ion-videocamera:before,.ion-volume-high:before,.ion-volume-low:before,.ion-volume-medium:before,.ion-volume-mute:before,.ion-wand:before,.ion-waterdrop:before,.ion-wifi:before,.ion-wineglass:before,.ion-woman:before,.ion-wrench:before,.ion-xbox:before,.ionicons{display:inline-block;font-family:Ionicons;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;text-rendering:auto;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ion-alert:before{content:""}.ion-alert-circled:before{content:""}.ion-android-add:before{content:""}.ion-android-add-circle:before{content:""}.ion-android-alarm-clock:before{content:""}.ion-android-alert:before{content:""}.ion-android-apps:before{content:""}.ion-android-archive:before{content:""}.ion-android-arrow-back:before{content:""}.ion-android-arrow-down:before{content:""}.ion-android-arrow-dropdown:before{content:""}.ion-android-arrow-dropdown-circle:before{content:""}.ion-android-arrow-dropleft:before{content:""}.ion-android-arrow-dropleft-circle:before{content:""}.ion-android-arrow-dropright:before{content:""}.ion-android-arrow-dropright-circle:before{content:""}.ion-android-arrow-dropup:before{content:""}.ion-android-arrow-dropup-circle:before{content:""}.ion-android-arrow-forward:before{content:""}.ion-android-arrow-up:before{content:""}.ion-android-attach:before{content:""}.ion-android-bar:before{content:""}.ion-android-bicycle:before{content:""}.ion-android-boat:before{content:""}.ion-android-bookmark:before{content:""}.ion-android-bulb:before{content:""}.ion-android-bus:before{content:""}.ion-android-calendar:before{content:""}.ion-android-call:before{content:""}.ion-android-camera:before{content:""}.ion-android-cancel:before{content:""}.ion-android-car:before{content:""}.ion-android-cart:before{content:""}.ion-android-chat:before{content:""}.ion-android-checkbox:before{content:""}.ion-android-checkbox-blank:before{content:""}.ion-android-checkbox-outline:before{content:""}.ion-android-checkbox-outline-blank:before{content:""}.ion-android-checkmark-circle:before{content:""}.ion-android-clipboard:before{content:""}.ion-android-close:before{content:""}.ion-android-cloud:before{content:""}.ion-android-cloud-circle:before{content:""}.ion-android-cloud-done:before{content:""}.ion-android-cloud-outline:before{content:""}.ion-android-color-palette:before{content:""}.ion-android-compass:before{content:""}.ion-android-contact:before{content:""}.ion-android-contacts:before{content:""}.ion-android-contract:before{content:""}.ion-android-create:before{content:""}.ion-android-delete:before{content:""}.ion-android-desktop:before{content:""}.ion-android-document:before{content:""}.ion-android-done:before{content:""}.ion-android-done-all:before{content:""}.ion-android-download:before{content:""}.ion-android-drafts:before{content:""}.ion-android-exit:before{content:""}.ion-android-expand:before{content:""}.ion-android-favorite:before{content:""}.ion-android-favorite-outline:before{content:""}.ion-android-film:before{content:""}.ion-android-folder:before{content:""}.ion-android-folder-open:before{content:""}.ion-android-funnel:before{content:""}.ion-android-globe:before{content:""}.ion-android-hand:before{content:""}.ion-android-hangout:before{content:""}.ion-android-happy:before{content:""}.ion-android-home:before{content:""}.ion-android-image:before{content:""}.ion-android-laptop:before{content:""}.ion-android-list:before{content:""}.ion-android-locate:before{content:""}.ion-android-lock:before{content:""}.ion-android-mail:before{content:""}.ion-android-map:before{content:""}.ion-android-menu:before{content:""}.ion-android-microphone:before{content:""}.ion-android-microphone-off:before{content:""}.ion-android-more-horizontal:before{content:""}.ion-android-more-vertical:before{content:""}.ion-android-navigate:before{content:""}.ion-android-notifications:before{content:""}.ion-android-notifications-none:before{content:""}.ion-android-notifications-off:before{content:""}.ion-android-open:before{content:""}.ion-android-options:before{content:""}.ion-android-people:before{content:""}.ion-android-person:before{content:""}.ion-android-person-add:before{content:""}.ion-android-phone-landscape:before{content:""}.ion-android-phone-portrait:before{content:""}.ion-android-pin:before{content:""}.ion-android-plane:before{content:""}.ion-android-playstore:before{content:""}.ion-android-print:before{content:""}.ion-android-radio-button-off:before{content:""}.ion-android-radio-button-on:before{content:""}.ion-android-refresh:before{content:""}.ion-android-remove:before{content:""}.ion-android-remove-circle:before{content:""}.ion-android-restaurant:before{content:""}.ion-android-sad:before{content:""}.ion-android-search:before{content:""}.ion-android-send:before{content:""}.ion-android-settings:before{content:""}.ion-android-share:before{content:""}.ion-android-share-alt:before{content:""}.ion-android-star:before{content:""}.ion-android-star-half:before{content:""}.ion-android-star-outline:before{content:""}.ion-android-stopwatch:before{content:""}.ion-android-subway:before{content:""}.ion-android-sunny:before{content:""}.ion-android-sync:before{content:""}.ion-android-textsms:before{content:""}.ion-android-time:before{content:""}.ion-android-train:before{content:""}.ion-android-unlock:before{content:""}.ion-android-upload:before{content:""}.ion-android-volume-down:before{content:""}.ion-android-volume-mute:before{content:""}.ion-android-volume-off:before{content:""}.ion-android-volume-up:before{content:""}.ion-android-walk:before{content:""}.ion-android-warning:before{content:""}.ion-android-watch:before{content:""}.ion-android-wifi:before{content:""}.ion-aperture:before{content:""}.ion-archive:before{content:""}.ion-arrow-down-a:before{content:""}.ion-arrow-down-b:before{content:""}.ion-arrow-down-c:before{content:""}.ion-arrow-expand:before{content:""}.ion-arrow-graph-down-left:before{content:""}.ion-arrow-graph-down-right:before{content:""}.ion-arrow-graph-up-left:before{content:""}.ion-arrow-graph-up-right:before{content:""}.ion-arrow-left-a:before{content:""}.ion-arrow-left-b:before{content:""}.ion-arrow-left-c:before{content:""}.ion-arrow-move:before{content:""}.ion-arrow-resize:before{content:""}.ion-arrow-return-left:before{content:""}.ion-arrow-return-right:before{content:""}.ion-arrow-right-a:before{content:""}.ion-arrow-right-b:before{content:""}.ion-arrow-right-c:before{content:""}.ion-arrow-shrink:before{content:""}.ion-arrow-swap:before{content:""}.ion-arrow-up-a:before{content:""}.ion-arrow-up-b:before{content:""}.ion-arrow-up-c:before{content:""}.ion-asterisk:before{content:""}.ion-at:before{content:""}.ion-backspace:before{content:""}.ion-backspace-outline:before{content:""}.ion-bag:before{content:""}.ion-battery-charging:before{content:""}.ion-battery-empty:before{content:""}.ion-battery-full:before{content:""}.ion-battery-half:before{content:""}.ion-battery-low:before{content:""}.ion-beaker:before{content:""}.ion-beer:before{content:""}.ion-bluetooth:before{content:""}.ion-bonfire:before{content:""}.ion-bookmark:before{content:""}.ion-bowtie:before{content:""}.ion-briefcase:before{content:""}.ion-bug:before{content:""}.ion-calculator:before{content:""}.ion-calendar:before{content:""}.ion-camera:before{content:""}.ion-card:before{content:""}.ion-cash:before{content:""}.ion-chatbox:before{content:""}.ion-chatbox-working:before{content:""}.ion-chatboxes:before{content:""}.ion-chatbubble:before{content:""}.ion-chatbubble-working:before{content:""}.ion-chatbubbles:before{content:""}.ion-checkmark:before{content:""}.ion-checkmark-circled:before{content:""}.ion-checkmark-round:before{content:""}.ion-chevron-down:before{content:""}.ion-chevron-left:before{content:""}.ion-chevron-right:before{content:""}.ion-chevron-up:before{content:""}.ion-clipboard:before{content:""}.ion-clock:before{content:""}.ion-close:before{content:""}.ion-close-circled:before{content:""}.ion-close-round:before{content:""}.ion-closed-captioning:before{content:""}.ion-cloud:before{content:""}.ion-code:before{content:""}.ion-code-download:before{content:""}.ion-code-working:before{content:""}.ion-coffee:before{content:""}.ion-compass:before{content:""}.ion-compose:before{content:""}.ion-connection-bars:before{content:""}.ion-contrast:before{content:""}.ion-crop:before{content:""}.ion-cube:before{content:""}.ion-disc:before{content:""}.ion-document:before{content:""}.ion-document-text:before{content:""}.ion-drag:before{content:""}.ion-earth:before{content:""}.ion-easel:before{content:""}.ion-edit:before{content:""}.ion-egg:before{content:""}.ion-eject:before{content:""}.ion-email:before{content:""}.ion-email-unread:before{content:""}.ion-erlenmeyer-flask:before{content:""}.ion-erlenmeyer-flask-bubbles:before{content:""}.ion-eye:before{content:""}.ion-eye-disabled:before{content:""}.ion-female:before{content:""}.ion-filing:before{content:""}.ion-film-marker:before{content:""}.ion-fireball:before{content:""}.ion-flag:before{content:""}.ion-flame:before{content:""}.ion-flash:before{content:""}.ion-flash-off:before{content:""}.ion-folder:before{content:""}.ion-fork:before{content:""}.ion-fork-repo:before{content:""}.ion-forward:before{content:""}.ion-funnel:before{content:""}.ion-gear-a:before{content:""}.ion-gear-b:before{content:""}.ion-grid:before{content:""}.ion-hammer:before{content:""}.ion-happy:before{content:""}.ion-happy-outline:before{content:""}.ion-headphone:before{content:""}.ion-heart:before{content:""}.ion-heart-broken:before{content:""}.ion-help:before{content:""}.ion-help-buoy:before{content:""}.ion-help-circled:before{content:""}.ion-home:before{content:""}.ion-icecream:before{content:""}.ion-image:before{content:""}.ion-images:before{content:""}.ion-information:before{content:""}.ion-information-circled:before{content:""}.ion-ionic:before{content:""}.ion-ios-alarm:before{content:""}.ion-ios-alarm-outline:before{content:""}.ion-ios-albums:before{content:""}.ion-ios-albums-outline:before{content:""}.ion-ios-americanfootball:before{content:""}.ion-ios-americanfootball-outline:before{content:""}.ion-ios-analytics:before{content:""}.ion-ios-analytics-outline:before{content:""}.ion-ios-arrow-back:before{content:""}.ion-ios-arrow-down:before{content:""}.ion-ios-arrow-forward:before{content:""}.ion-ios-arrow-left:before{content:""}.ion-ios-arrow-right:before{content:""}.ion-ios-arrow-thin-down:before{content:""}.ion-ios-arrow-thin-left:before{content:""}.ion-ios-arrow-thin-right:before{content:""}.ion-ios-arrow-thin-up:before{content:""}.ion-ios-arrow-up:before{content:""}.ion-ios-at:before{content:""}.ion-ios-at-outline:before{content:""}.ion-ios-barcode:before{content:""}.ion-ios-barcode-outline:before{content:""}.ion-ios-baseball:before{content:""}.ion-ios-baseball-outline:before{content:""}.ion-ios-basketball:before{content:""}.ion-ios-basketball-outline:before{content:""}.ion-ios-bell:before{content:""}.ion-ios-bell-outline:before{content:""}.ion-ios-body:before{content:""}.ion-ios-body-outline:before{content:""}.ion-ios-bolt:before{content:""}.ion-ios-bolt-outline:before{content:""}.ion-ios-book:before{content:""}.ion-ios-book-outline:before{content:""}.ion-ios-bookmarks:before{content:""}.ion-ios-bookmarks-outline:before{content:""}.ion-ios-box:before{content:""}.ion-ios-box-outline:before{content:""}.ion-ios-briefcase:before{content:""}.ion-ios-briefcase-outline:before{content:""}.ion-ios-browsers:before{content:""}.ion-ios-browsers-outline:before{content:""}.ion-ios-calculator:before{content:""}.ion-ios-calculator-outline:before{content:""}.ion-ios-calendar:before{content:""}.ion-ios-calendar-outline:before{content:""}.ion-ios-camera:before{content:""}.ion-ios-camera-outline:before{content:""}.ion-ios-cart:before{content:""}.ion-ios-cart-outline:before{content:""}.ion-ios-chatboxes:before{content:""}.ion-ios-chatboxes-outline:before{content:""}.ion-ios-chatbubble:before{content:""}.ion-ios-chatbubble-outline:before{content:""}.ion-ios-checkmark:before{content:""}.ion-ios-checkmark-empty:before{content:""}.ion-ios-checkmark-outline:before{content:""}.ion-ios-circle-filled:before{content:""}.ion-ios-circle-outline:before{content:""}.ion-ios-clock:before{content:""}.ion-ios-clock-outline:before{content:""}.ion-ios-close:before{content:""}.ion-ios-close-empty:before{content:""}.ion-ios-close-outline:before{content:""}.ion-ios-cloud:before{content:""}.ion-ios-cloud-download:before{content:""}.ion-ios-cloud-download-outline:before{content:""}.ion-ios-cloud-outline:before{content:""}.ion-ios-cloud-upload:before{content:""}.ion-ios-cloud-upload-outline:before{content:""}.ion-ios-cloudy:before{content:""}.ion-ios-cloudy-night:before{content:""}.ion-ios-cloudy-night-outline:before{content:""}.ion-ios-cloudy-outline:before{content:""}.ion-ios-cog:before{content:""}.ion-ios-cog-outline:before{content:""}.ion-ios-color-filter:before{content:""}.ion-ios-color-filter-outline:before{content:""}.ion-ios-color-wand:before{content:""}.ion-ios-color-wand-outline:before{content:""}.ion-ios-compose:before{content:""}.ion-ios-compose-outline:before{content:""}.ion-ios-contact:before{content:""}.ion-ios-contact-outline:before{content:""}.ion-ios-copy:before{content:""}.ion-ios-copy-outline:before{content:""}.ion-ios-crop:before{content:""}.ion-ios-crop-strong:before{content:""}.ion-ios-download:before{content:""}.ion-ios-download-outline:before{content:""}.ion-ios-drag:before{content:""}.ion-ios-email:before{content:""}.ion-ios-email-outline:before{content:""}.ion-ios-eye:before{content:""}.ion-ios-eye-outline:before{content:""}.ion-ios-fastforward:before{content:""}.ion-ios-fastforward-outline:before{content:""}.ion-ios-filing:before{content:""}.ion-ios-filing-outline:before{content:""}.ion-ios-film:before{content:""}.ion-ios-film-outline:before{content:""}.ion-ios-flag:before{content:""}.ion-ios-flag-outline:before{content:""}.ion-ios-flame:before{content:""}.ion-ios-flame-outline:before{content:""}.ion-ios-flask:before{content:""}.ion-ios-flask-outline:before{content:""}.ion-ios-flower:before{content:""}.ion-ios-flower-outline:before{content:""}.ion-ios-folder:before{content:""}.ion-ios-folder-outline:before{content:""}.ion-ios-football:before{content:""}.ion-ios-football-outline:before{content:""}.ion-ios-game-controller-a:before{content:""}.ion-ios-game-controller-a-outline:before{content:""}.ion-ios-game-controller-b:before{content:""}.ion-ios-game-controller-b-outline:before{content:""}.ion-ios-gear:before{content:""}.ion-ios-gear-outline:before{content:""}.ion-ios-glasses:before{content:""}.ion-ios-glasses-outline:before{content:""}.ion-ios-grid-view:before{content:""}.ion-ios-grid-view-outline:before{content:""}.ion-ios-heart:before{content:""}.ion-ios-heart-outline:before{content:""}.ion-ios-help:before{content:""}.ion-ios-help-empty:before{content:""}.ion-ios-help-outline:before{content:""}.ion-ios-home:before{content:""}.ion-ios-home-outline:before{content:""}.ion-ios-infinite:before{content:""}.ion-ios-infinite-outline:before{content:""}.ion-ios-information:before{content:""}.ion-ios-information-empty:before{content:""}.ion-ios-information-outline:before{content:""}.ion-ios-ionic-outline:before{content:""}.ion-ios-keypad:before{content:""}.ion-ios-keypad-outline:before{content:""}.ion-ios-lightbulb:before{content:""}.ion-ios-lightbulb-outline:before{content:""}.ion-ios-list:before{content:""}.ion-ios-list-outline:before{content:""}.ion-ios-location:before{content:""}.ion-ios-location-outline:before{content:""}.ion-ios-locked:before{content:""}.ion-ios-locked-outline:before{content:""}.ion-ios-loop:before{content:""}.ion-ios-loop-strong:before{content:""}.ion-ios-medical:before{content:""}.ion-ios-medical-outline:before{content:""}.ion-ios-medkit:before{content:""}.ion-ios-medkit-outline:before{content:""}.ion-ios-mic:before{content:""}.ion-ios-mic-off:before{content:""}.ion-ios-mic-outline:before{content:""}.ion-ios-minus:before{content:""}.ion-ios-minus-empty:before{content:""}.ion-ios-minus-outline:before{content:""}.ion-ios-monitor:before{content:""}.ion-ios-monitor-outline:before{content:""}.ion-ios-moon:before{content:""}.ion-ios-moon-outline:before{content:""}.ion-ios-more:before{content:""}.ion-ios-more-outline:before{content:""}.ion-ios-musical-note:before{content:""}.ion-ios-musical-notes:before{content:""}.ion-ios-navigate:before{content:""}.ion-ios-navigate-outline:before{content:""}.ion-ios-nutrition:before{content:""}.ion-ios-nutrition-outline:before{content:""}.ion-ios-paper:before{content:""}.ion-ios-paper-outline:before{content:""}.ion-ios-paperplane:before{content:""}.ion-ios-paperplane-outline:before{content:""}.ion-ios-partlysunny:before{content:""}.ion-ios-partlysunny-outline:before{content:""}.ion-ios-pause:before{content:""}.ion-ios-pause-outline:before{content:""}.ion-ios-paw:before{content:""}.ion-ios-paw-outline:before{content:""}.ion-ios-people:before{content:""}.ion-ios-people-outline:before{content:""}.ion-ios-person:before{content:""}.ion-ios-person-outline:before{content:""}.ion-ios-personadd:before{content:""}.ion-ios-personadd-outline:before{content:""}.ion-ios-photos:before{content:""}.ion-ios-photos-outline:before{content:""}.ion-ios-pie:before{content:""}.ion-ios-pie-outline:before{content:""}.ion-ios-pint:before{content:""}.ion-ios-pint-outline:before{content:""}.ion-ios-play:before{content:""}.ion-ios-play-outline:before{content:""}.ion-ios-plus:before{content:""}.ion-ios-plus-empty:before{content:""}.ion-ios-plus-outline:before{content:""}.ion-ios-pricetag:before{content:""}.ion-ios-pricetag-outline:before{content:""}.ion-ios-pricetags:before{content:""}.ion-ios-pricetags-outline:before{content:""}.ion-ios-printer:before{content:""}.ion-ios-printer-outline:before{content:""}.ion-ios-pulse:before{content:""}.ion-ios-pulse-strong:before{content:""}.ion-ios-rainy:before{content:""}.ion-ios-rainy-outline:before{content:""}.ion-ios-recording:before{content:""}.ion-ios-recording-outline:before{content:""}.ion-ios-redo:before{content:""}.ion-ios-redo-outline:before{content:""}.ion-ios-refresh:before{content:""}.ion-ios-refresh-empty:before{content:""}.ion-ios-refresh-outline:before{content:""}.ion-ios-reload:before{content:""}.ion-ios-reverse-camera:before{content:""}.ion-ios-reverse-camera-outline:before{content:""}.ion-ios-rewind:before{content:""}.ion-ios-rewind-outline:before{content:""}.ion-ios-rose:before{content:""}.ion-ios-rose-outline:before{content:""}.ion-ios-search:before{content:""}.ion-ios-search-strong:before{content:""}.ion-ios-settings:before{content:""}.ion-ios-settings-strong:before{content:""}.ion-ios-shuffle:before{content:""}.ion-ios-shuffle-strong:before{content:""}.ion-ios-skipbackward:before{content:""}.ion-ios-skipbackward-outline:before{content:""}.ion-ios-skipforward:before{content:""}.ion-ios-skipforward-outline:before{content:""}.ion-ios-snowy:before{content:""}.ion-ios-speedometer:before{content:""}.ion-ios-speedometer-outline:before{content:""}.ion-ios-star:before{content:""}.ion-ios-star-half:before{content:""}.ion-ios-star-outline:before{content:""}.ion-ios-stopwatch:before{content:""}.ion-ios-stopwatch-outline:before{content:""}.ion-ios-sunny:before{content:""}.ion-ios-sunny-outline:before{content:""}.ion-ios-telephone:before{content:""}.ion-ios-telephone-outline:before{content:""}.ion-ios-tennisball:before{content:""}.ion-ios-tennisball-outline:before{content:""}.ion-ios-thunderstorm:before{content:""}.ion-ios-thunderstorm-outline:before{content:""}.ion-ios-time:before{content:""}.ion-ios-time-outline:before{content:""}.ion-ios-timer:before{content:""}.ion-ios-timer-outline:before{content:""}.ion-ios-toggle:before{content:""}.ion-ios-toggle-outline:before{content:""}.ion-ios-trash:before{content:""}.ion-ios-trash-outline:before{content:""}.ion-ios-undo:before{content:""}.ion-ios-undo-outline:before{content:""}.ion-ios-unlocked:before{content:""}.ion-ios-unlocked-outline:before{content:""}.ion-ios-upload:before{content:""}.ion-ios-upload-outline:before{content:""}.ion-ios-videocam:before{content:""}.ion-ios-videocam-outline:before{content:""}.ion-ios-volume-high:before{content:""}.ion-ios-volume-low:before{content:""}.ion-ios-wineglass:before{content:""}.ion-ios-wineglass-outline:before{content:""}.ion-ios-world:before{content:""}.ion-ios-world-outline:before{content:""}.ion-ipad:before{content:""}.ion-iphone:before{content:""}.ion-ipod:before{content:""}.ion-jet:before{content:""}.ion-key:before{content:""}.ion-knife:before{content:""}.ion-laptop:before{content:""}.ion-leaf:before{content:""}.ion-levels:before{content:""}.ion-lightbulb:before{content:""}.ion-link:before{content:""}.ion-load-a:before{content:""}.ion-load-b:before{content:""}.ion-load-c:before{content:""}.ion-load-d:before{content:""}.ion-location:before{content:""}.ion-lock-combination:before{content:""}.ion-locked:before{content:""}.ion-log-in:before{content:""}.ion-log-out:before{content:""}.ion-loop:before{content:""}.ion-magnet:before{content:""}.ion-male:before{content:""}.ion-man:before{content:""}.ion-map:before{content:""}.ion-medkit:before{content:""}.ion-merge:before{content:""}.ion-mic-a:before{content:""}.ion-mic-b:before{content:""}.ion-mic-c:before{content:""}.ion-minus:before{content:""}.ion-minus-circled:before{content:""}.ion-minus-round:before{content:""}.ion-model-s:before{content:""}.ion-monitor:before{content:""}.ion-more:before{content:""}.ion-mouse:before{content:""}.ion-music-note:before{content:""}.ion-navicon:before{content:""}.ion-navicon-round:before{content:""}.ion-navigate:before{content:""}.ion-network:before{content:""}.ion-no-smoking:before{content:""}.ion-nuclear:before{content:""}.ion-outlet:before{content:""}.ion-paintbrush:before{content:""}.ion-paintbucket:before{content:""}.ion-paper-airplane:before{content:""}.ion-paperclip:before{content:""}.ion-pause:before{content:""}.ion-person:before{content:""}.ion-person-add:before{content:""}.ion-person-stalker:before{content:""}.ion-pie-graph:before{content:""}.ion-pin:before{content:""}.ion-pinpoint:before{content:""}.ion-pizza:before{content:""}.ion-plane:before{content:""}.ion-planet:before{content:""}.ion-play:before{content:""}.ion-playstation:before{content:""}.ion-plus:before{content:""}.ion-plus-circled:before{content:""}.ion-plus-round:before{content:""}.ion-podium:before{content:""}.ion-pound:before{content:""}.ion-power:before{content:""}.ion-pricetag:before{content:""}.ion-pricetags:before{content:""}.ion-printer:before{content:""}.ion-pull-request:before{content:""}.ion-qr-scanner:before{content:""}.ion-quote:before{content:""}.ion-radio-waves:before{content:""}.ion-record:before{content:""}.ion-refresh:before{content:""}.ion-reply:before{content:""}.ion-reply-all:before{content:""}.ion-ribbon-a:before{content:""}.ion-ribbon-b:before{content:""}.ion-sad:before{content:""}.ion-sad-outline:before{content:""}.ion-scissors:before{content:""}.ion-search:before{content:""}.ion-settings:before{content:""}.ion-share:before{content:""}.ion-shuffle:before{content:""}.ion-skip-backward:before{content:""}.ion-skip-forward:before{content:""}.ion-social-android:before{content:""}.ion-social-android-outline:before{content:""}.ion-social-angular:before{content:""}.ion-social-angular-outline:before{content:""}.ion-social-apple:before{content:""}.ion-social-apple-outline:before{content:""}.ion-social-bitcoin:before{content:""}.ion-social-bitcoin-outline:before{content:""}.ion-social-buffer:before{content:""}.ion-social-buffer-outline:before{content:""}.ion-social-chrome:before{content:""}.ion-social-chrome-outline:before{content:""}.ion-social-codepen:before{content:""}.ion-social-codepen-outline:before{content:""}.ion-social-css3:before{content:""}.ion-social-css3-outline:before{content:""}.ion-social-designernews:before{content:""}.ion-social-designernews-outline:before{content:""}.ion-social-dribbble:before{content:""}.ion-social-dribbble-outline:before{content:""}.ion-social-dropbox:before{content:""}.ion-social-dropbox-outline:before{content:""}.ion-social-euro:before{content:""}.ion-social-euro-outline:before{content:""}.ion-social-facebook:before{content:""}.ion-social-facebook-outline:before{content:""}.ion-social-foursquare:before{content:""}.ion-social-foursquare-outline:before{content:""}.ion-social-freebsd-devil:before{content:""}.ion-social-github:before{content:""}.ion-social-github-outline:before{content:""}.ion-social-google:before{content:""}.ion-social-google-outline:before{content:""}.ion-social-googleplus:before{content:""}.ion-social-googleplus-outline:before{content:""}.ion-social-hackernews:before{content:""}.ion-social-hackernews-outline:before{content:""}.ion-social-html5:before{content:""}.ion-social-html5-outline:before{content:""}.ion-social-instagram:before{content:""}.ion-social-instagram-outline:before{content:""}.ion-social-javascript:before{content:""}.ion-social-javascript-outline:before{content:""}.ion-social-linkedin:before{content:""}.ion-social-linkedin-outline:before{content:""}.ion-social-markdown:before{content:""}.ion-social-nodejs:before{content:""}.ion-social-octocat:before{content:""}.ion-social-pinterest:before{content:""}.ion-social-pinterest-outline:before{content:""}.ion-social-python:before{content:""}.ion-social-reddit:before{content:""}.ion-social-reddit-outline:before{content:""}.ion-social-rss:before{content:""}.ion-social-rss-outline:before{content:""}.ion-social-sass:before{content:""}.ion-social-skype:before{content:""}.ion-social-skype-outline:before{content:""}.ion-social-snapchat:before{content:""}.ion-social-snapchat-outline:before{content:""}.ion-social-tumblr:before{content:""}.ion-social-tumblr-outline:before{content:""}.ion-social-tux:before{content:""}.ion-social-twitch:before{content:""}.ion-social-twitch-outline:before{content:""}.ion-social-twitter:before{content:""}.ion-social-twitter-outline:before{content:""}.ion-social-usd:before{content:""}.ion-social-usd-outline:before{content:""}.ion-social-vimeo:before{content:""}.ion-social-vimeo-outline:before{content:""}.ion-social-whatsapp:before{content:""}.ion-social-whatsapp-outline:before{content:""}.ion-social-windows:before{content:""}.ion-social-windows-outline:before{content:""}.ion-social-wordpress:before{content:""}.ion-social-wordpress-outline:before{content:""}.ion-social-yahoo:before{content:""}.ion-social-yahoo-outline:before{content:""}.ion-social-yen:before{content:""}.ion-social-yen-outline:before{content:""}.ion-social-youtube:before{content:""}.ion-social-youtube-outline:before{content:""}.ion-soup-can:before{content:""}.ion-soup-can-outline:before{content:""}.ion-speakerphone:before{content:""}.ion-speedometer:before{content:""}.ion-spoon:before{content:""}.ion-star:before{content:""}.ion-stats-bars:before{content:""}.ion-steam:before{content:""}.ion-stop:before{content:""}.ion-thermometer:before{content:""}.ion-thumbsdown:before{content:""}.ion-thumbsup:before{content:""}.ion-toggle:before{content:""}.ion-toggle-filled:before{content:""}.ion-transgender:before{content:""}.ion-trash-a:before{content:""}.ion-trash-b:before{content:""}.ion-trophy:before{content:""}.ion-tshirt:before{content:""}.ion-tshirt-outline:before{content:""}.ion-umbrella:before{content:""}.ion-university:before{content:""}.ion-unlocked:before{content:""}.ion-upload:before{content:""}.ion-usb:before{content:""}.ion-videocamera:before{content:""}.ion-volume-high:before{content:""}.ion-volume-low:before{content:""}.ion-volume-medium:before{content:""}.ion-volume-mute:before{content:""}.ion-wand:before{content:""}.ion-waterdrop:before{content:""}.ion-wifi:before{content:""}.ion-wineglass:before{content:""}.ion-woman:before{content:""}.ion-wrench:before{content:""}.ion-xbox:before{content:""} - -/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0} - -/*! Source: https://github.com/h5bp/html5-boilerplate/blob/master/src/css/main.css */@media print{*,:after,:before{background:transparent!important;color:#000!important;box-shadow:none!important;text-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}blockquote,pre{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}img{max-width:100%!important}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.navbar{display:none}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #ddd!important}}*,:after,:before{box-sizing:border-box}html{font-size:10px;-webkit-tap-highlight-color:transparent}body{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}button,input,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#67808c;text-decoration:none}a:focus,a:hover{color:#465760;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:4px}.img-thumbnail{padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:3px;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.bootstrap-datetimepicker-widget .btn[data-action=clear]:after,.bootstrap-datetimepicker-widget .btn[data-action=decrementHours]:after,.bootstrap-datetimepicker-widget .btn[data-action=decrementMinutes]:after,.bootstrap-datetimepicker-widget .btn[data-action=incrementHours]:after,.bootstrap-datetimepicker-widget .btn[data-action=incrementMinutes]:after,.bootstrap-datetimepicker-widget .btn[data-action=showHours]:after,.bootstrap-datetimepicker-widget .btn[data-action=showMinutes]:after,.bootstrap-datetimepicker-widget .btn[data-action=today]:after,.bootstrap-datetimepicker-widget .btn[data-action=togglePeriod]:after,.bootstrap-datetimepicker-widget .picker-switch:after,.bootstrap-datetimepicker-widget table th.next:after,.bootstrap-datetimepicker-widget table th.prev:after,.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}[role=button]{cursor:pointer}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-weight:400;line-height:1;color:#777}.h1,.h2,.h3,h1,h2,h3{margin-top:20px;margin-bottom:10px}.h1 .small,.h1 small,.h2 .small,.h2 small,.h3 .small,.h3 small,h1 .small,h1 small,h2 .small,h2 small,h3 .small,h3 small{font-size:65%}.h4,.h5,.h6,h4,h5,h6{margin-top:10px;margin-bottom:10px}.h4 .small,.h4 small,.h5 .small,.h5 small,.h6 .small,.h6 small,h4 .small,h4 small,h5 .small,h5 small,h6 .small,h6 small{font-size:75%}.h1,h1{font-size:36px}.h2,h2{font-size:30px}.h3,h3{font-size:24px}.h4,h4{font-size:18px}.h5,h5{font-size:14px}.h6,h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:300;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}.small,small{font-size:85%}.mark,mark{background-color:#fcf8e3;padding:.2em}.text-left{text-align:left}.component-inline-update,.text-right{text-align:right}.text-center,body.dashboard .sidebar .sidebar-inner .quick-add-incident{text-align:center}.text-justify{text-align:justify}.text-nowrap{white-space:nowrap}.text-lowercase{text-transform:lowercase}.initialism,.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-muted{color:#777}.text-primary{color:#67808c}a.text-primary:focus,a.text-primary:hover{color:#51656f}.text-success{color:#3c763d}a.text-success:focus,a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:focus,a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:focus,a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:focus,a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#67808c}a.bg-primary:focus,a.bg-primary:hover{background-color:#51656f}.bg-success{background-color:#dff0d8}a.bg-success:focus,a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:focus,a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:focus,a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:focus,a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ol,ul{margin-top:0;margin-bottom:10px}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline{margin-left:-5px}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}dl{margin-top:0;margin-bottom:20px}dd,dt{line-height:1.428571429}dt{font-weight:700}dd{margin-left:0}.dl-horizontal dd:after,.dl-horizontal dd:before{content:" ";display:table}.dl-horizontal dd:after{clear:both}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[data-original-title],abbr[title]{cursor:help;border-bottom:1px dotted #777}.initialism{font-size:90%}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote ol:last-child,blockquote p:last-child,blockquote ul:last-child{margin-bottom:0}blockquote .small,blockquote footer,blockquote small{display:block;font-size:80%;line-height:1.428571429;color:#777}blockquote .small:before,blockquote footer:before,blockquote small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse .small:before,.blockquote-reverse footer:before,.blockquote-reverse small:before,blockquote.pull-right .small:before,blockquote.pull-right footer:before,blockquote.pull-right small:before{content:''}.blockquote-reverse .small:after,.blockquote-reverse footer:after,.blockquote-reverse small:after,blockquote.pull-right .small:after,blockquote.pull-right footer:after,blockquote.pull-right small:after{content:'\00A0 \2014'}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,Courier New,monospace}code{color:#c7254e;background-color:#f9f2f4;border-radius:3px}code,kbd{padding:2px 4px;font-size:90%}kbd{color:#fff;background-color:#333;border-radius:2px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;box-shadow:none}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:3px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.container:after,.container:before{content:" ";display:table}.container:after{clear:both}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.container-fluid:after,.container-fluid:before{content:" ";display:table}.container-fluid:after{clear:both}.row,.setup-page .steps{margin-left:-15px;margin-right:-15px}.row:after,.row:before,.setup-page .steps:after,.setup-page .steps:before{content:" ";display:table}.row:after,.setup-page .steps:after{clear:both}.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.setup-page .steps .step{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.setup-page .steps .step{float:left}.col-xs-1{width:8.3333333333%}.col-xs-2{width:16.6666666667%}.col-xs-3,.setup-page .steps .step{width:25%}.col-xs-4{width:33.3333333333%}.col-xs-5{width:41.6666666667%}.col-xs-6{width:50%}.col-xs-7{width:58.3333333333%}.col-xs-8{width:66.6666666667%}.col-xs-9{width:75%}.col-xs-10{width:83.3333333333%}.col-xs-11{width:91.6666666667%}.col-xs-12{width:100%}.col-xs-pull-0{right:auto}.col-xs-pull-1{right:8.3333333333%}.col-xs-pull-2{right:16.6666666667%}.col-xs-pull-3{right:25%}.col-xs-pull-4{right:33.3333333333%}.col-xs-pull-5{right:41.6666666667%}.col-xs-pull-6{right:50%}.col-xs-pull-7{right:58.3333333333%}.col-xs-pull-8{right:66.6666666667%}.col-xs-pull-9{right:75%}.col-xs-pull-10{right:83.3333333333%}.col-xs-pull-11{right:91.6666666667%}.col-xs-pull-12{right:100%}.col-xs-push-0{left:auto}.col-xs-push-1{left:8.3333333333%}.col-xs-push-2{left:16.6666666667%}.col-xs-push-3{left:25%}.col-xs-push-4{left:33.3333333333%}.col-xs-push-5{left:41.6666666667%}.col-xs-push-6{left:50%}.col-xs-push-7{left:58.3333333333%}.col-xs-push-8{left:66.6666666667%}.col-xs-push-9{left:75%}.col-xs-push-10{left:83.3333333333%}.col-xs-push-11{left:91.6666666667%}.col-xs-push-12{left:100%}.col-xs-offset-0{margin-left:0}.col-xs-offset-1{margin-left:8.3333333333%}.col-xs-offset-2{margin-left:16.6666666667%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-4{margin-left:33.3333333333%}.col-xs-offset-5{margin-left:41.6666666667%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-7{margin-left:58.3333333333%}.col-xs-offset-8{margin-left:66.6666666667%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-10{margin-left:83.3333333333%}.col-xs-offset-11{margin-left:91.6666666667%}.col-xs-offset-12{margin-left:100%}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-1{width:8.3333333333%}.col-sm-2{width:16.6666666667%}.col-sm-3{width:25%}.col-sm-4{width:33.3333333333%}.col-sm-5{width:41.6666666667%}.col-sm-6{width:50%}.col-sm-7{width:58.3333333333%}.col-sm-8{width:66.6666666667%}.col-sm-9{width:75%}.col-sm-10{width:83.3333333333%}.col-sm-11{width:91.6666666667%}.col-sm-12{width:100%}.col-sm-pull-0{right:auto}.col-sm-pull-1{right:8.3333333333%}.col-sm-pull-2{right:16.6666666667%}.col-sm-pull-3{right:25%}.col-sm-pull-4{right:33.3333333333%}.col-sm-pull-5{right:41.6666666667%}.col-sm-pull-6{right:50%}.col-sm-pull-7{right:58.3333333333%}.col-sm-pull-8{right:66.6666666667%}.col-sm-pull-9{right:75%}.col-sm-pull-10{right:83.3333333333%}.col-sm-pull-11{right:91.6666666667%}.col-sm-pull-12{right:100%}.col-sm-push-0{left:auto}.col-sm-push-1{left:8.3333333333%}.col-sm-push-2{left:16.6666666667%}.col-sm-push-3{left:25%}.col-sm-push-4{left:33.3333333333%}.col-sm-push-5{left:41.6666666667%}.col-sm-push-6{left:50%}.col-sm-push-7{left:58.3333333333%}.col-sm-push-8{left:66.6666666667%}.col-sm-push-9{left:75%}.col-sm-push-10{left:83.3333333333%}.col-sm-push-11{left:91.6666666667%}.col-sm-push-12{left:100%}.col-sm-offset-0{margin-left:0}.col-sm-offset-1{margin-left:8.3333333333%}.col-sm-offset-2{margin-left:16.6666666667%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-4{margin-left:33.3333333333%}.col-sm-offset-5{margin-left:41.6666666667%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-7{margin-left:58.3333333333%}.col-sm-offset-8{margin-left:66.6666666667%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-10{margin-left:83.3333333333%}.col-sm-offset-11{margin-left:91.6666666667%}.col-sm-offset-12{margin-left:100%}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-1{width:8.3333333333%}.col-md-2{width:16.6666666667%}.col-md-3{width:25%}.col-md-4{width:33.3333333333%}.col-md-5{width:41.6666666667%}.col-md-6{width:50%}.col-md-7{width:58.3333333333%}.col-md-8{width:66.6666666667%}.col-md-9{width:75%}.col-md-10{width:83.3333333333%}.col-md-11{width:91.6666666667%}.col-md-12{width:100%}.col-md-pull-0{right:auto}.col-md-pull-1{right:8.3333333333%}.col-md-pull-2{right:16.6666666667%}.col-md-pull-3{right:25%}.col-md-pull-4{right:33.3333333333%}.col-md-pull-5{right:41.6666666667%}.col-md-pull-6{right:50%}.col-md-pull-7{right:58.3333333333%}.col-md-pull-8{right:66.6666666667%}.col-md-pull-9{right:75%}.col-md-pull-10{right:83.3333333333%}.col-md-pull-11{right:91.6666666667%}.col-md-pull-12{right:100%}.col-md-push-0{left:auto}.col-md-push-1{left:8.3333333333%}.col-md-push-2{left:16.6666666667%}.col-md-push-3{left:25%}.col-md-push-4{left:33.3333333333%}.col-md-push-5{left:41.6666666667%}.col-md-push-6{left:50%}.col-md-push-7{left:58.3333333333%}.col-md-push-8{left:66.6666666667%}.col-md-push-9{left:75%}.col-md-push-10{left:83.3333333333%}.col-md-push-11{left:91.6666666667%}.col-md-push-12{left:100%}.col-md-offset-0{margin-left:0}.col-md-offset-1{margin-left:8.3333333333%}.col-md-offset-2{margin-left:16.6666666667%}.col-md-offset-3{margin-left:25%}.col-md-offset-4{margin-left:33.3333333333%}.col-md-offset-5{margin-left:41.6666666667%}.col-md-offset-6{margin-left:50%}.col-md-offset-7{margin-left:58.3333333333%}.col-md-offset-8{margin-left:66.6666666667%}.col-md-offset-9{margin-left:75%}.col-md-offset-10{margin-left:83.3333333333%}.col-md-offset-11{margin-left:91.6666666667%}.col-md-offset-12{margin-left:100%}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-1{width:8.3333333333%}.col-lg-2{width:16.6666666667%}.col-lg-3{width:25%}.col-lg-4{width:33.3333333333%}.col-lg-5{width:41.6666666667%}.col-lg-6{width:50%}.col-lg-7{width:58.3333333333%}.col-lg-8{width:66.6666666667%}.col-lg-9{width:75%}.col-lg-10{width:83.3333333333%}.col-lg-11{width:91.6666666667%}.col-lg-12{width:100%}.col-lg-pull-0{right:auto}.col-lg-pull-1{right:8.3333333333%}.col-lg-pull-2{right:16.6666666667%}.col-lg-pull-3{right:25%}.col-lg-pull-4{right:33.3333333333%}.col-lg-pull-5{right:41.6666666667%}.col-lg-pull-6{right:50%}.col-lg-pull-7{right:58.3333333333%}.col-lg-pull-8{right:66.6666666667%}.col-lg-pull-9{right:75%}.col-lg-pull-10{right:83.3333333333%}.col-lg-pull-11{right:91.6666666667%}.col-lg-pull-12{right:100%}.col-lg-push-0{left:auto}.col-lg-push-1{left:8.3333333333%}.col-lg-push-2{left:16.6666666667%}.col-lg-push-3{left:25%}.col-lg-push-4{left:33.3333333333%}.col-lg-push-5{left:41.6666666667%}.col-lg-push-6{left:50%}.col-lg-push-7{left:58.3333333333%}.col-lg-push-8{left:66.6666666667%}.col-lg-push-9{left:75%}.col-lg-push-10{left:83.3333333333%}.col-lg-push-11{left:91.6666666667%}.col-lg-push-12{left:100%}.col-lg-offset-0{margin-left:0}.col-lg-offset-1{margin-left:8.3333333333%}.col-lg-offset-2{margin-left:16.6666666667%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-4{margin-left:33.3333333333%}.col-lg-offset-5{margin-left:41.6666666667%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-7{margin-left:58.3333333333%}.col-lg-offset-8{margin-left:66.6666666667%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-10{margin-left:83.3333333333%}.col-lg-offset-11{margin-left:91.6666666667%}.col-lg-offset-12{margin-left:100%}}table{background-color:transparent}caption{padding-top:8px;padding-bottom:8px;color:#777}caption,th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th{padding:5px}.table-bordered,.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border:1px solid #ddd}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#f9f9f9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>thead>tr>td.active,.table>thead>tr>th.active{background-color:#f5f5f5}.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover{background-color:#e8e8e8}.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>thead>tr>td.success,.table>thead>tr>th.success{background-color:#dff0d8}.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover{background-color:#d0e9c6}.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>thead>tr>td.info,.table>thead>tr>th.info{background-color:#d9edf7}.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover{background-color:#c4e3f3}.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>thead>tr>td.warning,.table>thead>tr>th.warning{background-color:#fcf8e3}.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover{background-color:#faf2cc}.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>thead>tr>td.danger,.table>thead>tr>th.danger{background-color:#f2dede}.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:.01%}@media screen and (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th{border-bottom:0}}fieldset{margin:0;min-width:0}fieldset,legend{padding:0;border:0}legend{display:block;width:100%;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border-bottom:1px solid #e5e5e5}label{display:inline-block;max-width:100%;margin-bottom:5px;font-weight:700}input[type=search]{box-sizing:border-box}input[type=checkbox],input[type=radio]{margin:4px 0 0;margin-top:1px\9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=checkbox]:focus,input[type=file]:focus,input[type=radio]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{padding-top:7px}.form-control,output{display:block;font-size:14px;line-height:1.428571429;color:#555}.form-control{width:100%;height:34px;padding:6px 12px;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:3px;box-shadow:inset 0 1px 1px rgba(0,0,0,.075);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control:focus{border-color:#66afe9;outline:0;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control::-ms-expand{border:0;background-color:transparent}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{background-color:#eee;opacity:1}.form-control[disabled],fieldset[disabled] .form-control{cursor:not-allowed}textarea.form-control{height:auto}input[type=search]{-webkit-appearance:none}@media screen and (-webkit-min-device-pixel-ratio:0){input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{line-height:34px}.input-group-sm>.input-group-btn>input[type=date].btn,.input-group-sm>.input-group-btn>input[type=datetime-local].btn,.input-group-sm>.input-group-btn>input[type=month].btn,.input-group-sm>.input-group-btn>input[type=time].btn,.input-group-sm>input[type=date].form-control,.input-group-sm>input[type=date].input-group-addon,.input-group-sm>input[type=datetime-local].form-control,.input-group-sm>input[type=datetime-local].input-group-addon,.input-group-sm>input[type=month].form-control,.input-group-sm>input[type=month].input-group-addon,.input-group-sm>input[type=time].form-control,.input-group-sm>input[type=time].input-group-addon,.input-group-sm input[type=date],.input-group-sm input[type=datetime-local],.input-group-sm input[type=month],.input-group-sm input[type=time],input[type=date].input-sm,input[type=datetime-local].input-sm,input[type=month].input-sm,input[type=time].input-sm{line-height:30px}.input-group-lg>.input-group-btn>input[type=date].btn,.input-group-lg>.input-group-btn>input[type=datetime-local].btn,.input-group-lg>.input-group-btn>input[type=month].btn,.input-group-lg>.input-group-btn>input[type=time].btn,.input-group-lg>input[type=date].form-control,.input-group-lg>input[type=date].input-group-addon,.input-group-lg>input[type=datetime-local].form-control,.input-group-lg>input[type=datetime-local].input-group-addon,.input-group-lg>input[type=month].form-control,.input-group-lg>input[type=month].input-group-addon,.input-group-lg>input[type=time].form-control,.input-group-lg>input[type=time].input-group-addon,.input-group-lg input[type=date],.input-group-lg input[type=datetime-local],.input-group-lg input[type=month],.input-group-lg input[type=time],input[type=date].input-lg,input[type=datetime-local].input-lg,input[type=month].input-lg,input[type=time].input-lg{line-height:46px}}.form-group{margin-bottom:15px}.checkbox,.radio{position:relative;display:block;margin-top:10px;margin-bottom:10px}.checkbox label,.radio label{min-height:20px;padding-left:20px;margin-bottom:0;font-weight:400;cursor:pointer}.checkbox-inline input[type=checkbox],.checkbox input[type=checkbox],.radio-inline input[type=radio],.radio input[type=radio]{position:absolute;margin-left:-20px;margin-top:4px\9}.checkbox+.checkbox,.radio+.radio{margin-top:-5px}.checkbox-inline,.radio-inline{position:relative;display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.checkbox-inline+.checkbox-inline,.radio-inline+.radio-inline{margin-top:0;margin-left:10px}.checkbox-inline.disabled,.checkbox.disabled label,.radio-inline.disabled,.radio.disabled label,fieldset[disabled] .checkbox-inline,fieldset[disabled] .checkbox label,fieldset[disabled] .radio-inline,fieldset[disabled] .radio label,fieldset[disabled] input[type=checkbox],fieldset[disabled] input[type=radio],input[type=checkbox].disabled,input[type=checkbox][disabled],input[type=radio].disabled,input[type=radio][disabled]{cursor:not-allowed}.form-control-static{padding-top:7px;padding-bottom:7px;margin-bottom:0;min-height:34px}.form-control-static.input-lg,.form-control-static.input-sm,.input-group-lg>.form-control-static.form-control,.input-group-lg>.form-control-static.input-group-addon,.input-group-lg>.input-group-btn>.form-control-static.btn,.input-group-sm>.form-control-static.form-control,.input-group-sm>.form-control-static.input-group-addon,.input-group-sm>.input-group-btn>.form-control-static.btn{padding-left:0;padding-right:0}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn,.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:2px}.input-group-sm>.input-group-btn>select.btn,.input-group-sm>select.form-control,.input-group-sm>select.input-group-addon,select.input-sm{height:30px;line-height:30px}.input-group-sm>.input-group-btn>select[multiple].btn,.input-group-sm>.input-group-btn>textarea.btn,.input-group-sm>select[multiple].form-control,.input-group-sm>select[multiple].input-group-addon,.input-group-sm>textarea.form-control,.input-group-sm>textarea.input-group-addon,select[multiple].input-sm,textarea.input-sm{height:auto}.form-group-sm .form-control{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:2px}.form-group-sm select.form-control{height:30px;line-height:30px}.form-group-sm select[multiple].form-control,.form-group-sm textarea.form-control{height:auto}.form-group-sm .form-control-static{height:30px;min-height:32px;padding:6px 10px;font-size:12px;line-height:1.5}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn,.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:4px}.input-group-lg>.input-group-btn>select.btn,.input-group-lg>select.form-control,.input-group-lg>select.input-group-addon,select.input-lg{height:46px;line-height:46px}.input-group-lg>.input-group-btn>select[multiple].btn,.input-group-lg>.input-group-btn>textarea.btn,.input-group-lg>select[multiple].form-control,.input-group-lg>select[multiple].input-group-addon,.input-group-lg>textarea.form-control,.input-group-lg>textarea.input-group-addon,select[multiple].input-lg,textarea.input-lg{height:auto}.form-group-lg .form-control{height:46px;padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:4px}.form-group-lg select.form-control{height:46px;line-height:46px}.form-group-lg select[multiple].form-control,.form-group-lg textarea.form-control{height:auto}.form-group-lg .form-control-static{height:46px;min-height:38px;padding:11px 16px;font-size:18px;line-height:1.3333333}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.form-control-feedback{position:absolute;top:0;right:0;z-index:2;display:block;width:34px;height:34px;line-height:34px;text-align:center;pointer-events:none}.form-group-lg .form-control+.form-control-feedback,.input-group-lg+.form-control-feedback,.input-group-lg>.form-control+.form-control-feedback,.input-group-lg>.input-group-addon+.form-control-feedback,.input-group-lg>.input-group-btn>.btn+.form-control-feedback,.input-lg+.form-control-feedback{width:46px;height:46px;line-height:46px}.form-group-sm .form-control+.form-control-feedback,.input-group-sm+.form-control-feedback,.input-group-sm>.form-control+.form-control-feedback,.input-group-sm>.input-group-addon+.form-control-feedback,.input-group-sm>.input-group-btn>.btn+.form-control-feedback,.input-sm+.form-control-feedback{width:30px;height:30px;line-height:30px}.has-success .checkbox,.has-success .checkbox-inline,.has-success.checkbox-inline label,.has-success.checkbox label,.has-success .control-label,.has-success .help-block,.has-success .radio,.has-success .radio-inline,.has-success.radio-inline label,.has-success.radio label{color:#3c763d}.has-success .form-control{border-color:#3c763d;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .checkbox,.has-warning .checkbox-inline,.has-warning.checkbox-inline label,.has-warning.checkbox label,.has-warning .control-label,.has-warning .help-block,.has-warning .radio,.has-warning .radio-inline,.has-warning.radio-inline label,.has-warning.radio label{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .checkbox,.has-error .checkbox-inline,.has-error.checkbox-inline label,.has-error.checkbox label,.has-error .control-label,.has-error .help-block,.has-error .radio,.has-error .radio-inline,.has-error.radio-inline label,.has-error.radio label{color:#a94442}.has-error .form-control{border-color:#a94442;box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.has-feedback label~.form-control-feedback{top:25px}.bootstrap-datetimepicker-widget .has-feedback label.btn[data-action=clear]:after~.form-control-feedback,.bootstrap-datetimepicker-widget .has-feedback label.btn[data-action=decrementHours]:after~.form-control-feedback,.bootstrap-datetimepicker-widget .has-feedback label.btn[data-action=decrementMinutes]:after~.form-control-feedback,.bootstrap-datetimepicker-widget .has-feedback label.btn[data-action=incrementHours]:after~.form-control-feedback,.bootstrap-datetimepicker-widget .has-feedback label.btn[data-action=incrementMinutes]:after~.form-control-feedback,.bootstrap-datetimepicker-widget .has-feedback label.btn[data-action=showHours]:after~.form-control-feedback,.bootstrap-datetimepicker-widget .has-feedback label.btn[data-action=showMinutes]:after~.form-control-feedback,.bootstrap-datetimepicker-widget .has-feedback label.btn[data-action=today]:after~.form-control-feedback,.bootstrap-datetimepicker-widget .has-feedback label.btn[data-action=togglePeriod]:after~.form-control-feedback,.bootstrap-datetimepicker-widget .has-feedback label.picker-switch:after~.form-control-feedback,.has-feedback .bootstrap-datetimepicker-widget label.btn[data-action=clear]:after~.form-control-feedback,.has-feedback .bootstrap-datetimepicker-widget label.btn[data-action=decrementHours]:after~.form-control-feedback,.has-feedback .bootstrap-datetimepicker-widget label.btn[data-action=decrementMinutes]:after~.form-control-feedback,.has-feedback .bootstrap-datetimepicker-widget label.btn[data-action=incrementHours]:after~.form-control-feedback,.has-feedback .bootstrap-datetimepicker-widget label.btn[data-action=incrementMinutes]:after~.form-control-feedback,.has-feedback .bootstrap-datetimepicker-widget label.btn[data-action=showHours]:after~.form-control-feedback,.has-feedback .bootstrap-datetimepicker-widget label.btn[data-action=showMinutes]:after~.form-control-feedback,.has-feedback .bootstrap-datetimepicker-widget label.btn[data-action=today]:after~.form-control-feedback,.has-feedback .bootstrap-datetimepicker-widget label.btn[data-action=togglePeriod]:after~.form-control-feedback,.has-feedback .bootstrap-datetimepicker-widget label.picker-switch:after~.form-control-feedback,.has-feedback label.sr-only~.form-control-feedback{top:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-static{display:inline-block}.form-inline .input-group{display:inline-table;vertical-align:middle}.form-inline .input-group .form-control,.form-inline .input-group .input-group-addon,.form-inline .input-group .input-group-btn{width:auto}.form-inline .input-group>.form-control{width:100%}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .checkbox,.form-inline .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.form-inline .checkbox label,.form-inline .radio label{padding-left:0}.form-inline .checkbox input[type=checkbox],.form-inline .radio input[type=radio]{position:relative;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .checkbox,.form-horizontal .checkbox-inline,.form-horizontal .radio,.form-horizontal .radio-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .checkbox,.form-horizontal .radio{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .form-group:after,.form-horizontal .form-group:before{content:" ";display:table}.form-horizontal .form-group:after{clear:both}@media (min-width:768px){.form-horizontal .control-label{text-align:right;margin-bottom:0;padding-top:7px}}.form-horizontal .has-feedback .form-control-feedback{right:15px}@media (min-width:768px){.form-horizontal .form-group-lg .control-label{padding-top:11px;font-size:18px}}@media (min-width:768px){.form-horizontal .form-group-sm .control-label{padding-top:6px;font-size:12px}}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.428571429;border-radius:3px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn.active.focus,.btn.active:focus,.btn.focus,.btn:active.focus,.btn:active:focus,.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.focus,.btn:focus,.btn:hover{color:#333;text-decoration:none}.btn.active,.btn:active{outline:0;background-image:none;box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);box-shadow:none}a.btn.disabled,fieldset[disabled] a.btn{pointer-events:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default.focus,.btn-default:focus{color:#333;background-color:#e6e6e6;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.btn-default:hover,.open>.btn-default.dropdown-toggle{color:#333;background-color:#e6e6e6;border-color:#adadad}.btn-default.active.focus,.btn-default.active:focus,.btn-default.active:hover,.btn-default:active.focus,.btn-default:active:focus,.btn-default:active:hover,.open>.btn-default.dropdown-toggle.focus,.open>.btn-default.dropdown-toggle:focus,.open>.btn-default.dropdown-toggle:hover{color:#333;background-color:#d4d4d4;border-color:#8c8c8c}.btn-default.active,.btn-default:active,.open>.btn-default.dropdown-toggle{background-image:none}.btn-default.disabled.focus,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled].focus,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#67808c;border-color:#5c727d}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#51656f;border-color:#262f34}.btn-primary.active,.btn-primary:active,.btn-primary:hover,.open>.btn-primary.dropdown-toggle{color:#fff;background-color:#51656f;border-color:#42525a}.btn-primary.active.focus,.btn-primary.active:focus,.btn-primary.active:hover,.btn-primary:active.focus,.btn-primary:active:focus,.btn-primary:active:hover,.open>.btn-primary.dropdown-toggle.focus,.open>.btn-primary.dropdown-toggle:focus,.open>.btn-primary.dropdown-toggle:hover{color:#fff;background-color:#42525a;border-color:#262f34}.btn-primary.active,.btn-primary:active,.open>.btn-primary.dropdown-toggle{background-image:none}.btn-primary.disabled.focus,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled].focus,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#67808c;border-color:#5c727d}.btn-primary .badge{color:#67808c;background-color:#fff}.btn-success{color:#fff;background-color:#7ed321;border-color:#71bd1e}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#64a71a;border-color:#2f4f0c}.btn-success.active,.btn-success:active,.btn-success:hover,.open>.btn-success.dropdown-toggle{color:#fff;background-color:#64a71a;border-color:#518815}.btn-success.active.focus,.btn-success.active:focus,.btn-success.active:hover,.btn-success:active.focus,.btn-success:active:focus,.btn-success:active:hover,.open>.btn-success.dropdown-toggle.focus,.open>.btn-success.dropdown-toggle:focus,.open>.btn-success.dropdown-toggle:hover{color:#fff;background-color:#518815;border-color:#2f4f0c}.btn-success.active,.btn-success:active,.open>.btn-success.dropdown-toggle{background-image:none}.btn-success.disabled.focus,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled].focus,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#7ed321;border-color:#71bd1e}.btn-success .badge{color:#7ed321;background-color:#fff}.btn-info{color:#fff;background-color:#3498db;border-color:#258cd1}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#217dbb;border-color:#124364}.btn-info.active,.btn-info:active,.btn-info:hover,.open>.btn-info.dropdown-toggle{color:#fff;background-color:#217dbb;border-color:#1c699d}.btn-info.active.focus,.btn-info.active:focus,.btn-info.active:hover,.btn-info:active.focus,.btn-info:active:focus,.btn-info:active:hover,.open>.btn-info.dropdown-toggle.focus,.open>.btn-info.dropdown-toggle:focus,.open>.btn-info.dropdown-toggle:hover{color:#fff;background-color:#1c699d;border-color:#124364}.btn-info.active,.btn-info:active,.open>.btn-info.dropdown-toggle{background-image:none}.btn-info.disabled.focus,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled].focus,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#3498db;border-color:#258cd1}.btn-info .badge{color:#3498db;background-color:#fff}.btn-warning{color:#fff;background-color:#f80;border-color:#e67a00}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#cc6d00;border-color:#663600}.btn-warning.active,.btn-warning:active,.btn-warning:hover,.open>.btn-warning.dropdown-toggle{color:#fff;background-color:#cc6d00;border-color:#a85a00}.btn-warning.active.focus,.btn-warning.active:focus,.btn-warning.active:hover,.btn-warning:active.focus,.btn-warning:active:focus,.btn-warning:active:hover,.open>.btn-warning.dropdown-toggle.focus,.open>.btn-warning.dropdown-toggle:focus,.open>.btn-warning.dropdown-toggle:hover{color:#fff;background-color:#a85a00;border-color:#663600}.btn-warning.active,.btn-warning:active,.open>.btn-warning.dropdown-toggle{background-image:none}.btn-warning.disabled.focus,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled].focus,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#f80;border-color:#e67a00}.btn-warning .badge{color:#f80;background-color:#fff}.btn-danger{color:#fff;background-color:#ff6f6f;border-color:#ff5656}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#ff3c3c;border-color:#d50000}.btn-danger.active,.btn-danger:active,.btn-danger:hover,.open>.btn-danger.dropdown-toggle{color:#fff;background-color:#ff3c3c;border-color:#ff1818}.btn-danger.active.focus,.btn-danger.active:focus,.btn-danger.active:hover,.btn-danger:active.focus,.btn-danger:active:focus,.btn-danger:active:hover,.open>.btn-danger.dropdown-toggle.focus,.open>.btn-danger.dropdown-toggle:focus,.open>.btn-danger.dropdown-toggle:hover{color:#fff;background-color:#ff1818;border-color:#d50000}.btn-danger.active,.btn-danger:active,.open>.btn-danger.dropdown-toggle{background-image:none}.btn-danger.disabled.focus,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled].focus,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#ff6f6f;border-color:#ff5656}.btn-danger .badge{color:#ff6f6f;background-color:#fff}.btn-link{color:#67808c;font-weight:400;border-radius:0}.btn-link,.btn-link.active,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;box-shadow:none}.btn-link,.btn-link:active,.btn-link:focus,.btn-link:hover{border-color:transparent}.btn-link:focus,.btn-link:hover{color:#465760;text-decoration:underline;background-color:transparent}.btn-link[disabled]:focus,.btn-link[disabled]:hover,fieldset[disabled] .btn-link:focus,fieldset[disabled] .btn-link:hover{color:#777;text-decoration:none}.btn-group-lg>.btn,.btn-lg{padding:10px 16px;font-size:18px;line-height:1.3333333;border-radius:4px}.btn-group-sm>.btn,.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:2px}.btn-group-xs>.btn,.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:2px}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:5px}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{opacity:0;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}tr.collapse.in{display:table-row}tbody.collapse.in{display:table-row-group}.collapsing{position:relative;height:0;overflow:hidden;transition-property:height,visibility;transition-duration:.35s;transition-timing-function:ease}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px dashed;border-top:4px solid\9;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown,.dropup{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;text-align:left;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:3px;box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{color:#fff;text-decoration:none;outline:0;background-color:#67808c}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{color:#777}.dropdown-menu>.disabled>a:focus,.dropdown-menu>.disabled>a:hover{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#777;white-space:nowrap}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px dashed;border-bottom:4px solid\9;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:2px}@media (min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;float:left}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:2}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar:after,.btn-toolbar:before{content:" ";display:table}.btn-toolbar:after{clear:both}.btn-toolbar .btn,.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child:not(:first-child)>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px}.btn-group-lg.btn-group>.btn+.dropdown-toggle,.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{box-shadow:none}.btn .caret{margin-left:0}.btn-group-lg>.btn .caret,.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-group-lg>.btn .caret,.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:after,.btn-group-vertical>.btn-group:before{content:" ";display:table}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:3px;border-top-left-radius:3px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-top-left-radius:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}.btn-group-justified>.btn-group .dropdown-menu{left:auto}[data-toggle=buttons]>.btn-group>.btn input[type=checkbox],[data-toggle=buttons]>.btn-group>.btn input[type=radio],[data-toggle=buttons]>.btn input[type=checkbox],[data-toggle=buttons]>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.input-group .form-control{position:relative;z-index:2;float:left;width:100%;margin-bottom:0}.input-group .form-control:focus{z-index:3}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:3px}.input-group-addon.input-sm,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.input-group-addon.btn{padding:5px 10px;font-size:12px;border-radius:2px}.input-group-addon.input-lg,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.input-group-addon.btn{padding:10px 16px;font-size:18px;border-radius:4px}.input-group-addon input[type=checkbox],.input-group-addon input[type=radio]{margin-top:0}.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn-group:not(:last-child)>.btn,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group .form-control:first-child{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group-addon:last-child,.input-group-btn:first-child>.btn-group:not(:first-child)>.btn,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group .form-control:last-child{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{font-size:0;white-space:nowrap}.input-group-btn,.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:active,.input-group-btn>.btn:focus,.input-group-btn>.btn:hover{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{z-index:2;margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav:after,.nav:before{content:" ";display:table}.nav:after{clear:both}.nav>li,.nav>li>a{position:relative;display:block}.nav>li>a{padding:10px 15px}.nav>li>a:focus,.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#777}.nav>li.disabled>a:focus,.nav>li.disabled>a:hover{color:#777;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:focus,.nav .open>a:hover{background-color:#eee;border-color:#67808c}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:3px 3px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:focus,.nav-tabs>li.active>a:hover{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:3px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:focus,.nav-pills>li.active>a:hover{color:#fff;background-color:#67808c}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified,.nav-tabs.nav-justified{width:100%}.nav-justified>li,.nav-tabs.nav-justified>li{float:none}.nav-justified>li>a,.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li,.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a,.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified,.nav-tabs.nav-justified{border-bottom:0}.nav-tabs-justified>li>a,.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:3px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a,.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:3px 3px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:focus,.nav-tabs-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:focus,.nav-tabs.nav-justified>.active>a:hover{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:after,.navbar:before{content:" ";display:table}.navbar:after{clear:both}@media (min-width:768px){.navbar{border-radius:3px}}.navbar-header:after,.navbar-header:before{content:" ";display:table}.navbar-header:after{clear:both}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1);-webkit-overflow-scrolling:touch}.navbar-collapse:after,.navbar-collapse:before{content:" ";display:table}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse{padding-left:0;padding-right:0}}.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:340px}@media (max-device-width:480px) and (orientation:landscape){.navbar-fixed-bottom .navbar-collapse,.navbar-fixed-top .navbar-collapse{max-height:200px}}.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container-fluid>.navbar-collapse,.container-fluid>.navbar-header,.container>.navbar-collapse,.container>.navbar-header{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-bottom,.navbar-fixed-top{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-bottom,.navbar-fixed-top{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px;height:50px}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-brand>img{display:block}@media (min-width:768px){.navbar>.container-fluid .navbar-brand,.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:3px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu .dropdown-header,.navbar-nav .open .dropdown-menu>li>a{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:focus,.navbar-nav .open .dropdown-menu>li>a:hover{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}}.navbar-form{margin:8px -15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1),0 1px 0 hsla(0,0%,100%,.1)}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .form-control-static{display:inline-block}.navbar-form .input-group{display:inline-table;vertical-align:middle}.navbar-form .input-group .form-control,.navbar-form .input-group .input-group-addon,.navbar-form .input-group .input-group-btn{width:auto}.navbar-form .input-group>.form-control{width:100%}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .checkbox,.navbar-form .radio{display:inline-block;margin-top:0;margin-bottom:0;vertical-align:middle}.navbar-form .checkbox label,.navbar-form .radio label{padding-left:0}.navbar-form .checkbox input[type=checkbox],.navbar-form .radio input[type=radio]{position:relative;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}.navbar-form .form-group:last-child{margin-bottom:0}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;box-shadow:none}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{margin-bottom:0;border-top-right-radius:3px;border-top-left-radius:3px;border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.btn-group-sm>.navbar-btn.btn,.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.btn-group-xs>.navbar-btn.btn,.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important;margin-right:-15px}.navbar-right~.navbar-right{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:focus,.navbar-default .navbar-brand:hover{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-nav>li>a,.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a:focus,.navbar-default .navbar-nav>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:focus,.navbar-default .navbar-nav>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:focus,.navbar-default .navbar-nav>.disabled>a:hover{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:focus,.navbar-default .navbar-toggle:hover{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:focus,.navbar-default .navbar-nav>.open>a:hover{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:focus,.navbar-default .btn-link:hover{color:#333}.navbar-default .btn-link[disabled]:focus,.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:focus,fieldset[disabled] .navbar-default .btn-link:hover{color:#ccc}.navbar-inverse{background-color:#222;border-color:#090909}.navbar-inverse .navbar-brand{color:#9d9d9d}.navbar-inverse .navbar-brand:focus,.navbar-inverse .navbar-brand:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>li>a,.navbar-inverse .navbar-text{color:#9d9d9d}.navbar-inverse .navbar-nav>li>a:focus,.navbar-inverse .navbar-nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:focus,.navbar-inverse .navbar-nav>.active>a:hover{color:#fff;background-color:#090909}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:focus,.navbar-inverse .navbar-nav>.disabled>a:hover{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:focus,.navbar-inverse .navbar-toggle:hover{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:focus,.navbar-inverse .navbar-nav>.open>a:hover{background-color:#090909;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#090909}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#090909}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#9d9d9d}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-color:#090909}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#9d9d9d}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .btn-link{color:#9d9d9d}.navbar-inverse .btn-link:focus,.navbar-inverse .btn-link:hover{color:#fff}.navbar-inverse .btn-link[disabled]:focus,.navbar-inverse .btn-link[disabled]:hover,fieldset[disabled] .navbar-inverse .btn-link:focus,fieldset[disabled] .navbar-inverse .btn-link:hover{color:#444}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:3px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/ ";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#777}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:3px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.428571429;text-decoration:none;color:#67808c;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pagination>li>a:focus,.pagination>li>a:hover,.pagination>li>span:focus,.pagination>li>span:hover{z-index:2;color:#465760;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>a:focus,.pagination>.active>a:hover,.pagination>.active>span,.pagination>.active>span:focus,.pagination>.active>span:hover{z-index:3;color:#fff;background-color:#67808c;border-color:#67808c;cursor:default}.pagination>.disabled>a,.pagination>.disabled>a:focus,.pagination>.disabled>a:hover,.pagination>.disabled>span,.pagination>.disabled>span:focus,.pagination>.disabled>span:hover{color:#777;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px;line-height:1.3333333}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px;line-height:1.5}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:2px;border-top-left-radius:2px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:2px;border-top-right-radius:2px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager:after,.pager:before{content:" ";display:table}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:focus,.pager li>a:hover{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:focus,.pager .disabled>a:hover,.pager .disabled>span{color:#777;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label:empty{display:none}.btn .label{position:relative;top:-1px}a.label:focus,a.label:hover{color:#fff;text-decoration:none;cursor:pointer}.label-default{background-color:#777}.label-default[href]:focus,.label-default[href]:hover{background-color:#5e5e5e}.label-primary{background-color:#67808c}.label-primary[href]:focus,.label-primary[href]:hover{background-color:#51656f}.label-success{background-color:#7ed321}.label-success[href]:focus,.label-success[href]:hover{background-color:#64a71a}.label-info{background-color:#3498db}.label-info[href]:focus,.label-info[href]:hover{background-color:#217dbb}.label-warning{background-color:#f80}.label-warning[href]:focus,.label-warning[href]:hover{background-color:#cc6d00}.label-danger{background-color:#ff6f6f}.label-danger[href]:focus,.label-danger[href]:hover{background-color:#ff3c3c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;color:#fff;line-height:1;vertical-align:middle;white-space:nowrap;text-align:center;background-color:#777;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-group-xs>.btn .badge,.btn-xs .badge{top:0;padding:1px 5px}.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#67808c;background-color:#fff}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}.nav-pills>li>a>.badge{margin-left:3px}a.badge:focus,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.jumbotron{padding-top:30px;padding-bottom:30px;margin-bottom:30px;background-color:#eee}.jumbotron,.jumbotron .h1,.jumbotron h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.jumbotron>hr{border-top-color:#d5d5d5}.container-fluid .jumbotron,.container .jumbotron{border-radius:4px;padding-left:15px;padding-right:15px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container-fluid .jumbotron,.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron .h1,.jumbotron h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:3px;transition:border .2s ease-in-out}.thumbnail>img,.thumbnail a>img{display:block;max-width:100%;height:auto;margin-left:auto;margin-right:auto}.thumbnail .caption{padding:9px;color:#333}a.thumbnail.active,a.thumbnail:focus,a.thumbnail:hover{border-color:#67808c}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:3px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable,.alert-dismissible{padding-right:35px}.alert-dismissable .close,.alert-dismissible .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@keyframes progress-bar-stripes{0%{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:3px;box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#67808c;box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);transition:width .6s ease}.progress-bar-striped,.progress-striped .progress-bar{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent);background-size:40px 40px}.progress-bar.active,.progress.active .progress-bar{animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#7ed321}.progress-striped .progress-bar-success{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent)}.progress-bar-info{background-color:#3498db}.progress-striped .progress-bar-info{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent)}.progress-bar-warning{background-color:#f80}.progress-striped .progress-bar-warning{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent)}.progress-bar-danger{background-color:#ff6f6f}.progress-striped .progress-bar-danger{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent)}.media{margin-top:15px}.media:first-child{margin-top:0}.media,.media-body{zoom:1;overflow:hidden}.media-body{width:10000px}.media-object{display:block}.media-object.img-thumbnail{max-width:none}.media-right,.media>.pull-right{padding-left:10px}.media-left,.media>.pull-left{padding-right:10px}.media-body,.media-left,.media-right{display:table-cell;vertical-align:top}.media-middle{vertical-align:middle}.media-bottom{vertical-align:bottom}.media-heading{margin-top:0;margin-bottom:5px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:3px;border-top-left-radius:3px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}a.list-group-item,button.list-group-item{color:#555}a.list-group-item .list-group-item-heading,button.list-group-item .list-group-item-heading{color:#333}a.list-group-item:focus,a.list-group-item:hover,button.list-group-item:focus,button.list-group-item:hover{text-decoration:none;color:#555;background-color:#f5f5f5}button.list-group-item{width:100%;text-align:left}.list-group-item.disabled,.list-group-item.disabled:focus,.list-group-item.disabled:hover{background-color:#eee;color:#777;cursor:not-allowed}.list-group-item.disabled .list-group-item-heading,.list-group-item.disabled:focus .list-group-item-heading,.list-group-item.disabled:hover .list-group-item-heading{color:inherit}.list-group-item.disabled .list-group-item-text,.list-group-item.disabled:focus .list-group-item-text,.list-group-item.disabled:hover .list-group-item-text{color:#777}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{z-index:2;color:#fff;background-color:#67808c;border-color:#67808c}.list-group-item.active .list-group-item-heading,.list-group-item.active .list-group-item-heading>.small,.list-group-item.active .list-group-item-heading>small,.list-group-item.active:focus .list-group-item-heading,.list-group-item.active:focus .list-group-item-heading>.small,.list-group-item.active:focus .list-group-item-heading>small,.list-group-item.active:hover .list-group-item-heading,.list-group-item.active:hover .list-group-item-heading>.small,.list-group-item.active:hover .list-group-item-heading>small{color:inherit}.list-group-item.active .list-group-item-text,.list-group-item.active:focus .list-group-item-text,.list-group-item.active:hover .list-group-item-text{color:#dbe1e4}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success,button.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading,button.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:focus,a.list-group-item-success:hover,button.list-group-item-success:focus,button.list-group-item-success:hover{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:focus,a.list-group-item-success.active:hover,button.list-group-item-success.active,button.list-group-item-success.active:focus,button.list-group-item-success.active:hover{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info,button.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading,button.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:focus,a.list-group-item-info:hover,button.list-group-item-info:focus,button.list-group-item-info:hover{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:focus,a.list-group-item-info.active:hover,button.list-group-item-info.active,button.list-group-item-info.active:focus,button.list-group-item-info.active:hover{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning,button.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading,button.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:focus,a.list-group-item-warning:hover,button.list-group-item-warning:focus,button.list-group-item-warning:hover{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:focus,a.list-group-item-warning.active:hover,button.list-group-item-warning.active,button.list-group-item-warning.active:focus,button.list-group-item-warning.active:hover{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger,button.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading,button.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:focus,a.list-group-item-danger:hover,button.list-group-item-danger:focus,button.list-group-item-danger:hover{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:focus,a.list-group-item-danger.active:hover,button.list-group-item-danger.active,button.list-group-item-danger.active:focus,button.list-group-item-danger.active:hover{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel,body.status-page .list-group.components{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:3px;box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:15px}.panel-body:after,.panel-body:before{content:" ";display:table}.panel-body:after{clear:both}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:2px;border-top-left-radius:2px}.panel-heading>.dropdown .dropdown-toggle,.panel-title{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px}.panel-title>.small,.panel-title>.small>a,.panel-title>a,.panel-title>small,.panel-title>small>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:2px;border-bottom-left-radius:2px}.panel>.list-group,.panel>.panel-collapse>.list-group,body.status-page .list-group.components>.list-group,body.status-page .list-group.components>.panel-collapse>.list-group{margin-bottom:0}.panel>.list-group .list-group-item,.panel>.panel-collapse>.list-group .list-group-item,body.status-page .list-group.components>.list-group .list-group-item,body.status-page .list-group.components>.panel-collapse>.list-group .list-group-item{border-width:1px 0;border-radius:0}.panel>.list-group:first-child .list-group-item:first-child,.panel>.panel-collapse>.list-group:first-child .list-group-item:first-child,body.status-page .list-group.components>.list-group:first-child .list-group-item:first-child,body.status-page .list-group.components>.panel-collapse>.list-group:first-child .list-group-item:first-child{border-top:0;border-top-right-radius:2px;border-top-left-radius:2px}.panel>.list-group:last-child .list-group-item:last-child,.panel>.panel-collapse>.list-group:last-child .list-group-item:last-child,body.status-page .list-group.components>.list-group:last-child .list-group-item:last-child,body.status-page .list-group.components>.panel-collapse>.list-group:last-child .list-group-item:last-child{border-bottom:0;border-bottom-right-radius:2px;border-bottom-left-radius:2px}.panel>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child,body.status-page .list-group.components>.panel-heading+.panel-collapse>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.list-group+.panel-footer,.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.panel-collapse>.table,.panel>.table,.panel>.table-responsive>.table,body.status-page .list-group.components>.panel-collapse>.table,body.status-page .list-group.components>.table,body.status-page .list-group.components>.table-responsive>.table{margin-bottom:0}.panel>.panel-collapse>.table caption,.panel>.table-responsive>.table caption,.panel>.table caption,body.status-page .list-group.components>.panel-collapse>.table caption,body.status-page .list-group.components>.table-responsive>.table caption,body.status-page .list-group.components>.table caption{padding-left:15px;padding-right:15px}.panel>.table-responsive:first-child>.table:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,.panel>.table:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child,.panel>.table:first-child>thead:first-child>tr:first-child,body.status-page .list-group.components>.table-responsive:first-child>.table:first-child,body.status-page .list-group.components>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child,body.status-page .list-group.components>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child,body.status-page .list-group.components>.table:first-child,body.status-page .list-group.components>.table:first-child>tbody:first-child>tr:first-child,body.status-page .list-group.components>.table:first-child>thead:first-child>tr:first-child{border-top-right-radius:2px;border-top-left-radius:2px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table:first-child>thead:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,body.status-page .list-group.components>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,body.status-page .list-group.components>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child,body.status-page .list-group.components>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:first-child,body.status-page .list-group.components>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,body.status-page .list-group.components>.table:first-child>tbody:first-child>tr:first-child td:first-child,body.status-page .list-group.components>.table:first-child>tbody:first-child>tr:first-child th:first-child,body.status-page .list-group.components>.table:first-child>thead:first-child>tr:first-child td:first-child,body.status-page .list-group.components>.table:first-child>thead:first-child>tr:first-child th:first-child{border-top-left-radius:2px}.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,body.status-page .list-group.components>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,body.status-page .list-group.components>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:last-child,body.status-page .list-group.components>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,body.status-page .list-group.components>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,body.status-page .list-group.components>.table:first-child>tbody:first-child>tr:first-child td:last-child,body.status-page .list-group.components>.table:first-child>tbody:first-child>tr:first-child th:last-child,body.status-page .list-group.components>.table:first-child>thead:first-child>tr:first-child td:last-child,body.status-page .list-group.components>.table:first-child>thead:first-child>tr:first-child th:last-child{border-top-right-radius:2px}.panel>.table-responsive:last-child>.table:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,.panel>.table:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child,body.status-page .list-group.components>.table-responsive:last-child>.table:last-child,body.status-page .list-group.components>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child,body.status-page .list-group.components>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child,body.status-page .list-group.components>.table:last-child,body.status-page .list-group.components>.table:last-child>tbody:last-child>tr:last-child,body.status-page .list-group.components>.table:last-child>tfoot:last-child>tr:last-child{border-bottom-right-radius:2px;border-bottom-left-radius:2px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,body.status-page .list-group.components>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:first-child,body.status-page .list-group.components>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,body.status-page .list-group.components>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,body.status-page .list-group.components>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child,body.status-page .list-group.components>.table:last-child>tbody:last-child>tr:last-child td:first-child,body.status-page .list-group.components>.table:last-child>tbody:last-child>tr:last-child th:first-child,body.status-page .list-group.components>.table:last-child>tfoot:last-child>tr:last-child td:first-child,body.status-page .list-group.components>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:2px}.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,body.status-page .list-group.components>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,body.status-page .list-group.components>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,body.status-page .list-group.components>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,body.status-page .list-group.components>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child,body.status-page .list-group.components>.table:last-child>tbody:last-child>tr:last-child td:last-child,body.status-page .list-group.components>.table:last-child>tbody:last-child>tr:last-child th:last-child,body.status-page .list-group.components>.table:last-child>tfoot:last-child>tr:last-child td:last-child,body.status-page .list-group.components>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:2px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive,.panel>.table+.panel-body,.panel>.table-responsive+.panel-body,body.status-page .list-group.components>.panel-body+.table,body.status-page .list-group.components>.panel-body+.table-responsive,body.status-page .list-group.components>.table+.panel-body,body.status-page .list-group.components>.table-responsive+.panel-body{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child td,.panel>.table>tbody:first-child>tr:first-child th,body.status-page .list-group.components>.table>tbody:first-child>tr:first-child td,body.status-page .list-group.components>.table>tbody:first-child>tr:first-child th{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered,body.status-page .list-group.components>.table-bordered,body.status-page .list-group.components>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,body.status-page .list-group.components>.table-bordered>tbody>tr>td:first-child,body.status-page .list-group.components>.table-bordered>tbody>tr>th:first-child,body.status-page .list-group.components>.table-bordered>tfoot>tr>td:first-child,body.status-page .list-group.components>.table-bordered>tfoot>tr>th:first-child,body.status-page .list-group.components>.table-bordered>thead>tr>td:first-child,body.status-page .list-group.components>.table-bordered>thead>tr>th:first-child,body.status-page .list-group.components>.table-responsive>.table-bordered>tbody>tr>td:first-child,body.status-page .list-group.components>.table-responsive>.table-bordered>tbody>tr>th:first-child,body.status-page .list-group.components>.table-responsive>.table-bordered>tfoot>tr>td:first-child,body.status-page .list-group.components>.table-responsive>.table-bordered>tfoot>tr>th:first-child,body.status-page .list-group.components>.table-responsive>.table-bordered>thead>tr>td:first-child,body.status-page .list-group.components>.table-responsive>.table-bordered>thead>tr>th:first-child{border-left:0}.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,body.status-page .list-group.components>.table-bordered>tbody>tr>td:last-child,body.status-page .list-group.components>.table-bordered>tbody>tr>th:last-child,body.status-page .list-group.components>.table-bordered>tfoot>tr>td:last-child,body.status-page .list-group.components>.table-bordered>tfoot>tr>th:last-child,body.status-page .list-group.components>.table-bordered>thead>tr>td:last-child,body.status-page .list-group.components>.table-bordered>thead>tr>th:last-child,body.status-page .list-group.components>.table-responsive>.table-bordered>tbody>tr>td:last-child,body.status-page .list-group.components>.table-responsive>.table-bordered>tbody>tr>th:last-child,body.status-page .list-group.components>.table-responsive>.table-bordered>tfoot>tr>td:last-child,body.status-page .list-group.components>.table-responsive>.table-bordered>tfoot>tr>th:last-child,body.status-page .list-group.components>.table-responsive>.table-bordered>thead>tr>td:last-child,body.status-page .list-group.components>.table-responsive>.table-bordered>thead>tr>th:last-child{border-right:0}.panel>.table-bordered>tbody>tr:first-child>td,.panel>.table-bordered>tbody>tr:first-child>th,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:first-child>td,.panel>.table-bordered>thead>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:first-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:first-child>td,.panel>.table-responsive>.table-bordered>thead>tr:first-child>th,body.status-page .list-group.components>.table-bordered>tbody>tr:first-child>td,body.status-page .list-group.components>.table-bordered>tbody>tr:first-child>th,body.status-page .list-group.components>.table-bordered>tbody>tr:last-child>td,body.status-page .list-group.components>.table-bordered>tbody>tr:last-child>th,body.status-page .list-group.components>.table-bordered>tfoot>tr:last-child>td,body.status-page .list-group.components>.table-bordered>tfoot>tr:last-child>th,body.status-page .list-group.components>.table-bordered>thead>tr:first-child>td,body.status-page .list-group.components>.table-bordered>thead>tr:first-child>th,body.status-page .list-group.components>.table-responsive>.table-bordered>tbody>tr:first-child>td,body.status-page .list-group.components>.table-responsive>.table-bordered>tbody>tr:first-child>th,body.status-page .list-group.components>.table-responsive>.table-bordered>tbody>tr:last-child>td,body.status-page .list-group.components>.table-responsive>.table-bordered>tbody>tr:last-child>th,body.status-page .list-group.components>.table-responsive>.table-bordered>tfoot>tr:last-child>td,body.status-page .list-group.components>.table-responsive>.table-bordered>tfoot>tr:last-child>th,body.status-page .list-group.components>.table-responsive>.table-bordered>thead>tr:first-child>td,body.status-page .list-group.components>.table-responsive>.table-bordered>thead>tr:first-child>th{border-bottom:0}.panel>.table-responsive,body.status-page .list-group.components>.table-responsive{border:0;margin-bottom:0}.panel-group{margin-bottom:20px}.panel-group .panel,.panel-group body.status-page .list-group.components,body.status-page .panel-group .list-group.components{margin-bottom:0;border-radius:3px}.panel-group .panel+.panel,.panel-group body.status-page .list-group.components+.list-group.components,.panel-group body.status-page .list-group.components+.panel,.panel-group body.status-page .panel+.list-group.components,body.status-page .panel-group .list-group.components+.list-group.components,body.status-page .panel-group .list-group.components+.panel,body.status-page .panel-group .panel+.list-group.components{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse>.list-group,.panel-group .panel-heading+.panel-collapse>.panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ddd}.panel-default>.panel-heading .badge{color:#f5f5f5;background-color:#333}.panel-default>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#67808c}.panel-primary>.panel-heading{color:#fff;background-color:#67808c;border-color:#67808c}.panel-primary>.panel-heading+.panel-collapse>.panel-body{border-top-color:#67808c}.panel-primary>.panel-heading .badge{color:#67808c;background-color:#fff}.panel-primary>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#67808c}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d6e9c6}.panel-success>.panel-heading .badge{color:#dff0d8;background-color:#3c763d}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#bce8f1}.panel-info>.panel-heading .badge{color:#d9edf7;background-color:#31708f}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#faebcc}.panel-warning>.panel-heading .badge{color:#fcf8e3;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ebccd1}.panel-danger>.panel-heading .badge{color:#f2dede;background-color:#a94442}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ebccd1}.embed-responsive{position:relative;display:block;height:0;padding:0;overflow:hidden}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;left:0;bottom:0;height:100%;width:100%;border:0}.embed-responsive-16by9{padding-bottom:56.25%}.embed-responsive-4by3{padding-bottom:75%}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:3px;box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:4px}.well-sm{padding:9px;border-radius:2px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:focus,.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal,.modal-open{overflow:hidden}.modal{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{transform:translateY(-25%);transition:transform .3s ease-out}.modal.in .modal-dialog{transform:translate(0)}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:4px;box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5}.modal-header:after,.modal-header:before{content:" ";display:table}.modal-header:after{clear:both}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:after,.modal-footer:before{content:" ";display:table}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}}@media (min-width:992px){.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1070;display:block;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.428571429;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:12px;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;background-color:#333;border-radius:3px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#333}.tooltip.top-left .tooltip-arrow{right:5px}.tooltip.top-left .tooltip-arrow,.tooltip.top-right .tooltip-arrow{bottom:0;margin-bottom:-5px;border-width:5px 5px 0;border-top-color:#333}.tooltip.top-right .tooltip-arrow{left:5px}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#333}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#333}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#333}.tooltip.bottom-left .tooltip-arrow{top:0;right:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#333}.tooltip.bottom-right .tooltip-arrow{top:0;left:5px;margin-top:-5px;border-width:0 5px 5px;border-bottom-color:#333}.popover{position:absolute;top:0;left:0;z-index:1060;display:none;max-width:276px;padding:1px;font-family:Helvetica Neue,Helvetica,Arial,sans-serif;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.428571429;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;word-wrap:normal;font-size:14px;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:4px;box-shadow:0 5px 10px rgba(0,0,0,.2)}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:3px 3px 0 0}.popover-content{padding:9px 14px}.popover>.arrow,.popover>.arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover>.arrow{border-width:11px}.popover>.arrow:after{border-width:10px;content:""}.popover.top>.arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top>.arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right>.arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right>.arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom>.arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom>.arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left>.arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left>.arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel,.carousel-inner{position:relative}.carousel-inner{overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;transition:left .6s ease-in-out}.carousel-inner>.item>a>img,.carousel-inner>.item>img{display:block;max-width:100%;height:auto;line-height:1}@media (-webkit-transform-3d),all and (transform-3d){.carousel-inner>.item{transition:transform .6s ease-in-out;backface-visibility:hidden;perspective:1000px}.carousel-inner>.item.active.right,.carousel-inner>.item.next{transform:translate3d(100%,0,0);left:0}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{transform:translate3d(-100%,0,0);left:0}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{transform:translateZ(0);left:0}}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6);background-color:transparent}.carousel-control.left{background-image:linear-gradient(90deg,rgba(0,0,0,.5),rgba(0,0,0,.0001));background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:linear-gradient(90deg,rgba(0,0,0,.0001),rgba(0,0,0,.5));background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:focus,.carousel-control:hover{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;top:50%;margin-top:-10px;z-index:5;display:inline-block}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{width:20px;height:20px;line-height:1;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000\9;background-color:transparent}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{width:30px;height:30px;margin-top:-10px;font-size:30px}.carousel-control .glyphicon-chevron-left,.carousel-control .icon-prev{margin-left:-10px}.carousel-control .glyphicon-chevron-right,.carousel-control .icon-next{margin-right:-10px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:after,.clearfix:before{content:" ";display:table}.clearfix:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-lg,.visible-lg-block,.visible-lg-inline,.visible-lg-inline-block,.visible-md,.visible-md-block,.visible-md-inline,.visible-md-inline-block,.visible-sm,.visible-sm-block,.visible-sm-inline,.visible-sm-inline-block,.visible-xs,.visible-xs-block,.visible-xs-inline,.visible-xs-inline-block,body.dashboard .sidebar .sidebar-inner .quick-add-incident i{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table!important}tr.visible-xs{display:table-row!important}td.visible-xs,th.visible-xs{display:table-cell!important}}@media (max-width:767px){.visible-xs-block{display:block!important}}@media (max-width:767px){.visible-xs-inline{display:inline!important}}@media (max-width:767px){.visible-xs-inline-block{display:inline-block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm,body.dashboard .sidebar .sidebar-inner .quick-add-incident i{display:block!important}table.visible-sm{display:table!important}tr.visible-sm{display:table-row!important}td.visible-sm,th.visible-sm{display:table-cell!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-block{display:block!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline{display:inline!important}}@media (min-width:768px) and (max-width:991px){.visible-sm-inline-block{display:inline-block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table!important}tr.visible-md{display:table-row!important}td.visible-md,th.visible-md{display:table-cell!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-block{display:block!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline{display:inline!important}}@media (min-width:992px) and (max-width:1199px){.visible-md-inline-block{display:inline-block!important}}@media (min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table!important}tr.visible-lg{display:table-row!important}td.visible-lg,th.visible-lg{display:table-cell!important}}@media (min-width:1200px){.visible-lg-block{display:block!important}}@media (min-width:1200px){.visible-lg-inline{display:inline!important}}@media (min-width:1200px){.visible-lg-inline-block{display:inline-block!important}}@media (max-width:767px){.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm,body.dashboard .sidebar .bottom-menu-sidebar,body.dashboard .sidebar .sidebar-inner .quick-add-incident span,body.dashboard .sidebar .sidebar-inner>ul>li>a>span{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table!important}tr.visible-print{display:table-row!important}td.visible-print,th.visible-print{display:table-cell!important}}.visible-print-block{display:none!important}@media print{.visible-print-block{display:block!important}}.visible-print-inline{display:none!important}@media print{.visible-print-inline{display:inline!important}}.visible-print-inline-block{display:none!important}@media print{.visible-print-inline-block{display:inline-block!important}}@media print{.hidden-print{display:none!important}}html{position:relative;min-height:100%;-webkit-font-smoothing:antialiased;overflow-y:scroll}body{margin-bottom:60px;padding-bottom:60px}.uppercase{text-transform:uppercase}.margin-top{margin-top:20px}.margin-bottom{margin-bottom:20px}div[role=tabpanel] ul.nav-tabs{border-bottom:1px solid #d5d8d7}div[role=tabpanel] ul.nav-tabs li a{font-weight:400;display:inline-block;padding:10px 25px;border-radius:0;font-size:.9em;letter-spacing:.01em}div[role=tabpanel] .tab-content{border-left:1px solid #d5d8d7;border-bottom:1px solid #d5d8d7;border-right:1px solid #d5d8d7;background-color:#fff}div[role=tabpanel] .tab-content .tab-pane{padding:10px}label{font-size:14px}textarea{resize:none;overflow:auto}.markdown-control{position:relative}.markdown-control:before{position:absolute;display:block;right:0;bottom:0;width:40px;height:40px;font-size:2em;font-family:Ionicons;content:"\f4e6"}.form-control{display:block;width:100%;height:45px;padding:6px 12px;font-size:14px;line-height:1.42857143;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;box-shadow:none!important;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control:focus{border-color:#66afe9}@media (max-width:767px){.component-inline .radio-items{text-align:left}.component-inline .radio-items .radio-inline{margin-left:0;width:100%}}.minicolors-theme-bootstrap .minicolors-swatch{top:9px;left:9px}.well{border-radius:0}.alert{border-radius:4px;background:#f7ca18;border:2px solid #d5ab07}.alert.alert-success{background-color:#7ed321;border:2px solid #64a71a;color:#fff}.alert.alert-success a{color:#fff;font-weight:700}.alert.alert-info{background:#3498db;border:2px solid #217dbb;color:#fff}.alert.alert-info a{color:#fff;font-weight:700}.alert.alert-danger{background:#ff6f6f;border:2px solid #ff3c3c;color:#fff}.alert.alert-danger a{color:#fff;font-weight:700}.panel-danger{border-color:#ff3c3c}.panel-danger>.panel-heading{color:#fff;background-color:#ff6f6f;border-color:#ff3c3c}.panel-danger>.panel-heading+.panel-collapse>.panel-body{border-top-color:#ff3c3c}.panel-danger>.panel-heading .badge{color:#ff6f6f;background-color:#fff}.panel-danger>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#ff3c3c}.panel-success{border-color:#64a71a}.panel-success>.panel-heading{color:#fff;background-color:#7ed321;border-color:#64a71a}.panel-success>.panel-heading+.panel-collapse>.panel-body{border-top-color:#64a71a}.panel-success>.panel-heading .badge{color:#7ed321;background-color:#fff}.panel-success>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#64a71a}.panel-info{border-color:#217dbb}.panel-info>.panel-heading{color:#fff;background-color:#3498db;border-color:#217dbb}.panel-info>.panel-heading+.panel-collapse>.panel-body{border-top-color:#217dbb}.panel-info>.panel-heading .badge{color:#3498db;background-color:#fff}.panel-info>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#217dbb}.panel-warning{border-color:#d5ab07}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#f7ca18;border-color:#d5ab07}.panel-warning>.panel-heading+.panel-collapse>.panel-body{border-top-color:#d5ab07}.panel-warning>.panel-heading .badge{color:#f7ca18;background-color:#8a6d3b}.panel-warning>.panel-footer+.panel-collapse>.panel-body{border-bottom-color:#d5ab07}.btn.btn-default{color:#333;background-image:linear-gradient(180deg,#fff,#f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF',endColorstr='#FFF2F2F2',GradientType=0);border-color:#e6e6e6;border-bottom-color:#ccc;text-shadow:none;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1)}.btn.btn-default.active,.btn.btn-default:active,.btn.btn-default:focus,.btn.btn-default:hover{background-image:linear-gradient(180deg,#fff,#e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF',endColorstr='#FFE6E6E6',GradientType=0);border-color:#ccc;color:#333}.btn.btn-default.disabled,.btn.btn-default.disabled.active,.btn.btn-default.disabled:active,.btn.btn-default.disabled:focus,.btn.btn-default.disabled:hover,.btn.btn-default[disabled],.btn.btn-default[disabled].active,.btn.btn-default[disabled]:active,.btn.btn-default[disabled]:focus,.btn.btn-default[disabled]:hover,fieldset[disabled] .btn.btn-default,fieldset[disabled] .btn.btn-default.active,fieldset[disabled] .btn.btn-default:active,fieldset[disabled] .btn.btn-default:focus,fieldset[disabled] .btn.btn-default:hover{background-color:#fff;border-color:#f2f2f2}.btn.btn-primary{color:#fff;background-image:linear-gradient(180deg,#748c99,#5c727d);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF748C99',endColorstr='#FF5C727D',GradientType=0);border-color:#51656f;border-bottom-color:#3c4a51;text-shadow:none;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1)}.btn.btn-primary.active,.btn.btn-primary:active,.btn.btn-primary:focus,.btn.btn-primary:hover{background-image:linear-gradient(180deg,#67808c,#51656f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF67808C',endColorstr='#FF51656F',GradientType=0);border-color:#3c4a51;color:#fff}.btn.btn-primary.disabled,.btn.btn-primary.disabled.active,.btn.btn-primary.disabled:active,.btn.btn-primary.disabled:focus,.btn.btn-primary.disabled:hover,.btn.btn-primary[disabled],.btn.btn-primary[disabled].active,.btn.btn-primary[disabled]:active,.btn.btn-primary[disabled]:focus,.btn.btn-primary[disabled]:hover,fieldset[disabled] .btn.btn-primary,fieldset[disabled] .btn.btn-primary.active,fieldset[disabled] .btn.btn-primary:active,fieldset[disabled] .btn.btn-primary:focus,fieldset[disabled] .btn.btn-primary:hover{background-color:#67808c;border-color:#5c727d}.btn.btn-success{color:#fff;background-image:linear-gradient(180deg,#8bde2f,#71bd1e);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF8BDE2F',endColorstr='#FF71BD1E',GradientType=0);border-color:#64a71a;border-bottom-color:#497b13;text-shadow:none;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1)}.btn.btn-success.active,.btn.btn-success:active,.btn.btn-success:focus,.btn.btn-success:hover{background-image:linear-gradient(180deg,#7ed321,#64a71a);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF7ED321',endColorstr='#FF64A71A',GradientType=0);border-color:#497b13;color:#fff}.btn.btn-success.disabled,.btn.btn-success.disabled.active,.btn.btn-success.disabled:active,.btn.btn-success.disabled:focus,.btn.btn-success.disabled:hover,.btn.btn-success[disabled],.btn.btn-success[disabled].active,.btn.btn-success[disabled]:active,.btn.btn-success[disabled]:focus,.btn.btn-success[disabled]:hover,fieldset[disabled] .btn.btn-success,fieldset[disabled] .btn.btn-success.active,fieldset[disabled] .btn.btn-success:active,fieldset[disabled] .btn.btn-success:focus,fieldset[disabled] .btn.btn-success:hover{background-color:#7ed321;border-color:#71bd1e}.btn.btn-info{color:#fff;background-image:linear-gradient(180deg,#4aa3df,#258cd1);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF4AA3DF',endColorstr='#FF258CD1',GradientType=0);border-color:#217dbb;border-bottom-color:#196090;text-shadow:none;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1)}.btn.btn-info.active,.btn.btn-info:active,.btn.btn-info:focus,.btn.btn-info:hover{background-image:linear-gradient(180deg,#3498db,#217dbb);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF3498DB',endColorstr='#FF217DBB',GradientType=0);border-color:#196090;color:#fff}.btn.btn-info.disabled,.btn.btn-info.disabled.active,.btn.btn-info.disabled:active,.btn.btn-info.disabled:focus,.btn.btn-info.disabled:hover,.btn.btn-info[disabled],.btn.btn-info[disabled].active,.btn.btn-info[disabled]:active,.btn.btn-info[disabled]:focus,.btn.btn-info[disabled]:hover,fieldset[disabled] .btn.btn-info,fieldset[disabled] .btn.btn-info.active,fieldset[disabled] .btn.btn-info:active,fieldset[disabled] .btn.btn-info:focus,fieldset[disabled] .btn.btn-info:hover{background-color:#3498db;border-color:#258cd1}.btn.btn-warning{color:#fff;background-image:linear-gradient(180deg,#ff941a,#e67a00);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFF941A',endColorstr='#FFE67A00',GradientType=0);border-color:#cc6d00;border-bottom-color:#995200;text-shadow:none;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1)}.btn.btn-warning.active,.btn.btn-warning:active,.btn.btn-warning:focus,.btn.btn-warning:hover{background-image:linear-gradient(180deg,#f80,#cc6d00);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFF8800',endColorstr='#FFCC6D00',GradientType=0);border-color:#995200;color:#fff}.btn.btn-warning.disabled,.btn.btn-warning.disabled.active,.btn.btn-warning.disabled:active,.btn.btn-warning.disabled:focus,.btn.btn-warning.disabled:hover,.btn.btn-warning[disabled],.btn.btn-warning[disabled].active,.btn.btn-warning[disabled]:active,.btn.btn-warning[disabled]:focus,.btn.btn-warning[disabled]:hover,fieldset[disabled] .btn.btn-warning,fieldset[disabled] .btn.btn-warning.active,fieldset[disabled] .btn.btn-warning:active,fieldset[disabled] .btn.btn-warning:focus,fieldset[disabled] .btn.btn-warning:hover{background-color:#f80;border-color:#e67a00}.btn.btn-danger{color:#fff;background-image:linear-gradient(180deg,#ff8989,#ff5656);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFF8989',endColorstr='#FFFF5656',GradientType=0);border-color:#ff3c3c;border-bottom-color:#ff0909;text-shadow:none;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1)}.btn.btn-danger.active,.btn.btn-danger:active,.btn.btn-danger:focus,.btn.btn-danger:hover{background-image:linear-gradient(180deg,#ff6f6f,#ff3c3c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFF6F6F',endColorstr='#FFFF3C3C',GradientType=0);border-color:#ff0909;color:#fff}.btn.btn-danger.disabled,.btn.btn-danger.disabled.active,.btn.btn-danger.disabled:active,.btn.btn-danger.disabled:focus,.btn.btn-danger.disabled:hover,.btn.btn-danger[disabled],.btn.btn-danger[disabled].active,.btn.btn-danger[disabled]:active,.btn.btn-danger[disabled]:focus,.btn.btn-danger[disabled]:hover,fieldset[disabled] .btn.btn-danger,fieldset[disabled] .btn.btn-danger.active,fieldset[disabled] .btn.btn-danger:active,fieldset[disabled] .btn.btn-danger:focus,fieldset[disabled] .btn.btn-danger:hover{background-color:#ff6f6f;border-color:#ff5656}.btn.btn-inverse{color:#fff;background-image:linear-gradient(180deg,#545656,#3a3c3c);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF545656',endColorstr='#FF3A3C3C',GradientType=0);border-color:#2e2f2f;border-bottom-color:#151515;text-shadow:none;box-shadow:inset 0 1px 0 hsla(0,0%,100%,.1)}.btn.btn-inverse.active,.btn.btn-inverse:active,.btn.btn-inverse:focus,.btn.btn-inverse:hover{background-image:linear-gradient(180deg,#474949,#2e2f2f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#FF474949',endColorstr='#FF2E2F2F',GradientType=0);border-color:#151515;color:#fff}.btn.btn-inverse.disabled,.btn.btn-inverse.disabled.active,.btn.btn-inverse.disabled:active,.btn.btn-inverse.disabled:focus,.btn.btn-inverse.disabled:hover,.btn.btn-inverse[disabled],.btn.btn-inverse[disabled].active,.btn.btn-inverse[disabled]:active,.btn.btn-inverse[disabled]:focus,.btn.btn-inverse[disabled]:hover,fieldset[disabled] .btn.btn-inverse,fieldset[disabled] .btn.btn-inverse.active,fieldset[disabled] .btn.btn-inverse:active,fieldset[disabled] .btn.btn-inverse:focus,fieldset[disabled] .btn.btn-inverse:hover{background-color:#474949;border-color:#3a3c3c}.btn-outline{background-color:transparent;background-image:none!important;color:inherit;transition:all .5s}.btn-default.btn-outline{color:#999}.btn-primary.btn-outline{color:#428bca}.btn-success.btn-outline{color:#5cb85c}.btn-info.btn-outline{color:#5bc0de}.btn-warning.btn-outline{color:#f0ad4e}.btn-danger.btn-outline{color:#d9534f}.btn-danger.btn-outline:hover,.btn-info.btn-outline:hover,.btn-primary.btn-outline:hover,.btn-success.btn-outline:hover,.btn-warning.btn-outline:hover{color:#fff}.pager li>a,.pager li>span{border-radius:3px}body.dashboard{font-family:Open Sans,Helvetica Neue,Helvetica,Arial,sans-serif;font-weight:400;font-size:15px;display:table;width:100%;height:100%;table-layout:fixed;line-height:1.42857143;-webkit-font-smoothing:antialiased}body.dashboard .wrapper{padding-left:0;transition:all .5s ease}body.dashboard .wrapper.toggled{padding-left:230px}body.dashboard .wrapper.toggled .sidebar{width:230px}body.dashboard .wrapper.toggled .page-content{position:absolute;margin-right:-230px}@media (min-width:768px) and (max-width:991px){body.dashboard .wrapper{padding-left:80px}}@media (min-width:991px){body.dashboard .wrapper{padding-left:230px}body.dashboard .wrapper.toggled{padding-left:0}body.dashboard .wrapper.toggled .page-content{position:relative;margin-right:0}}body.dashboard .alerts .alert h5{margin-top:5px}body.dashboard .wrapper{width:100%;display:table;height:100%;table-layout:fixed}body.dashboard .navbar{z-index:999;border-radius:0;border:none;border-bottom:1px solid #00695c;background:#009c89;margin:0}body.dashboard .navbar a,body.dashboard .navbar a:active,body.dashboard .navbar a:visited{color:#fff}body.dashboard .navbar a:active:hover,body.dashboard .navbar a:hover,body.dashboard .navbar a:visited:hover{color:#e9e9e9}body.dashboard .navbar .navbar-toggle{margin-top:15px;background:transparent;border-color:transparent}body.dashboard .navbar .navbar-toggle.collapsed span{background-color:#fff}body.dashboard .navbar .navbar-collapse{background:#009c89}body.dashboard .navbar a.navbar-brand{padding:34px 21px;line-height:0;font-size:1.1em;letter-spacing:.04em;font-weight:600;text-transform:uppercase}@media (min-width:991px){body.dashboard .navbar a.navbar-brand span{padding-right:10px}body.dashboard .navbar a.navbar-brand span:before{font-family:FontAwesome;content:"\f060"}}body.dashboard .navbar .nav li a{height:68px;line-height:35px}body.dashboard .sidebar{position:fixed;left:230px;width:0;height:100%;margin-left:-230px;overflow-y:auto;background:#78909c;box-shadow:inset 0 -2px 3px rgba(0,0,0,.25);z-index:1000;transition:all .5s ease}body.dashboard .sidebar .sidebar-inner{position:absolute;top:0;width:230px;margin:0;padding:0;list-style:none}body.dashboard .sidebar .sidebar-inner .profile{text-align:center;padding:20px 10px;margin-bottom:0}body.dashboard .sidebar .sidebar-inner .profile .dropdown-toggle{text-decoration:none}body.dashboard .sidebar .sidebar-inner .profile .dropdown-menu{top:108%}body.dashboard .sidebar .sidebar-inner .profile .avatar{width:60px}body.dashboard .sidebar .sidebar-inner .profile .avatar img{border-radius:50%;width:50px}body.dashboard .sidebar .sidebar-inner .profile .username{word-break:break-all;margin-bottom:0}body.dashboard .sidebar .sidebar-inner .profile a{color:#fff;text-decoration:none}body.dashboard .sidebar .sidebar-inner .quick-add-incident{padding:10px}body.dashboard .sidebar .sidebar-inner ul{clear:both;margin:0;padding:0;list-style:none}body.dashboard .sidebar .sidebar-inner ul li{font-size:.9em}body.dashboard .sidebar .sidebar-inner ul li.active{background:#7e95a0}body.dashboard .sidebar .sidebar-inner ul li.active a{padding-top:14px;padding-bottom:14px;border-top:1px solid #6c818c;border-bottom:1px solid #6c818c;color:#fff}body.dashboard .sidebar .sidebar-inner ul li.active a:focus,body.dashboard .sidebar .sidebar-inner ul li.active a:hover{text-decoration:none}body.dashboard .sidebar .sidebar-inner ul li a{display:block;padding:15px;color:#fff}body.dashboard .sidebar .sidebar-inner ul li a i{font-size:18px;min-width:17px;text-align:center;position:relative;top:1px;margin-right:5px}body.dashboard .sidebar .sidebar-inner ul li a:focus,body.dashboard .sidebar .sidebar-inner ul li a:hover{text-decoration:none}body.dashboard .sidebar .sidebar-inner ul li a span.label{float:right;margin:6px 0}body.dashboard .sidebar .sidebar-inner ul li a span.label.label-info{background-color:#7ed321}body.dashboard .sidebar .sidebar-inner ul li.sub-nav-item a{padding-left:40px}body.dashboard .sidebar .bottom-menu-sidebar{position:fixed;bottom:0;width:230px;z-index:999}body.dashboard .sidebar .bottom-menu-sidebar ul>li{float:left;display:block;width:33.333%;border-right:1px solid #ddd;border-top:1px solid #ddd}body.dashboard .sidebar .bottom-menu-sidebar ul>li a{color:#333;display:block;position:relative;text-align:center;padding:6px 0;background:#fff}@media (min-width:767px){body.dashboard .sidebar{width:230px}body.dashboard .wrapper.toggled .sidebar{width:0}}@media (min-width:768px) and (max-width:991px){body.dashboard .sidebar{width:80px;left:150px;margin-left:-150px}body.dashboard .sidebar .sidebar-inner{width:80px}body.dashboard .sidebar .sidebar-inner .profile .avatar img{width:40px}body.dashboard .sidebar .sidebar-inner .quick-add-incident .btn{padding:3px 6px}body.dashboard .sidebar .sidebar-inner .quick-add-incident i{font-size:20px}body.dashboard .sidebar .sidebar-inner>ul>li>a{text-align:center}body.dashboard .sidebar .sidebar-inner>ul>li>a>i{font-size:25px}}body.dashboard .sidebar-toggler{float:left;padding:10px;position:relative;top:-15px;left:-5px;margin-right:10px;cursor:pointer}body.dashboard .sidebar-toggler i{font-size:25px}body.dashboard .sub-sidebar{left:0;top:0;bottom:0;position:fixed;margin-left:228px;width:22%;background:#f9fdff;border-right:1px solid #e8ecf1}body.dashboard .sub-sidebar h3{margin:0;text-align:center;font-size:19px;padding:30px 0}body.dashboard .sub-sidebar ul.menu{list-style-type:none;padding:0;margin:0}body.dashboard .sub-sidebar ul.menu li a{color:#666;display:block;padding:13px 30px;font-size:15px;transition:all .2s linear;text-decoration:none}body.dashboard .sub-sidebar ul.menu li a.active,body.dashboard .sub-sidebar ul.menu li a:hover{color:#6db81c}body.dashboard .sub-sidebar ul.menu li i{margin-right:5px}body.dashboard .sub-sidebar .sidebar-toggler{position:absolute;top:3px;left:20px;font-size:36px;cursor:pointer}body.dashboard .sub-sidebar+.content-wrapper{top:0;position:relative;margin-left:26%;padding-right:40px!important}@media (max-width:767px){body.dashboard .sub-sidebar{position:relative;margin-left:0;width:100%}body.dashboard .sub-sidebar+.content-wrapper{margin-left:0;padding-left:40px!important;width:100%}}@media (min-width:768px) and (max-width:991px){body.dashboard .sub-sidebar{margin-left:80px;width:25%}body.dashboard .sub-sidebar+.content-wrapper{padding-left:45px!important}}body.dashboard .page-content{width:100%}body.dashboard .page-content .content-wrapper{padding-top:20px;padding-left:40px;padding-right:40px}body.dashboard .page-content .content-wrapper.header-fixed{margin-top:60px}body.dashboard .page-content .header{position:relative;top:0;left:0;color:#333;background-color:#fff;padding:22px 40px;width:100%;height:70px;font-size:1.2em;border-bottom:1px solid #eee;z-index:99}body.dashboard .page-content .header.sub-header{padding:8px 2px;height:50px}body.dashboard .page-content .header.fixed{position:fixed;padding-left:270px}body.dashboard .page-content .header .btn,body.dashboard .page-content .header button,body.dashboard .page-content .header input{position:relative;top:-4px}body.dashboard .page-content .header input{width:20%}.setup-page body.dashboard .page-content .header+.steps,body.dashboard .page-content .header+.row,body.dashboard .page-content .setup-page .header+.steps{margin-top:23px}body.dashboard .page-content .header h3{color:#444;margin-top:0;text-transform:uppercase}body.dashboard .page-content .header .ion,body.dashboard .page-content .header .ion-alert-circled:before,body.dashboard .page-content .header .ion-alert:before,body.dashboard .page-content .header .ion-android-add-circle:before,body.dashboard .page-content .header .ion-android-add:before,body.dashboard .page-content .header .ion-android-alarm-clock:before,body.dashboard .page-content .header .ion-android-alert:before,body.dashboard .page-content .header .ion-android-apps:before,body.dashboard .page-content .header .ion-android-archive:before,body.dashboard .page-content .header .ion-android-arrow-back:before,body.dashboard .page-content .header .ion-android-arrow-down:before,body.dashboard .page-content .header .ion-android-arrow-dropdown-circle:before,body.dashboard .page-content .header .ion-android-arrow-dropdown:before,body.dashboard .page-content .header .ion-android-arrow-dropleft-circle:before,body.dashboard .page-content .header .ion-android-arrow-dropleft:before,body.dashboard .page-content .header .ion-android-arrow-dropright-circle:before,body.dashboard .page-content .header .ion-android-arrow-dropright:before,body.dashboard .page-content .header .ion-android-arrow-dropup-circle:before,body.dashboard .page-content .header .ion-android-arrow-dropup:before,body.dashboard .page-content .header .ion-android-arrow-forward:before,body.dashboard .page-content .header .ion-android-arrow-up:before,body.dashboard .page-content .header .ion-android-attach:before,body.dashboard .page-content .header .ion-android-bar:before,body.dashboard .page-content .header .ion-android-bicycle:before,body.dashboard .page-content .header .ion-android-boat:before,body.dashboard .page-content .header .ion-android-bookmark:before,body.dashboard .page-content .header .ion-android-bulb:before,body.dashboard .page-content .header .ion-android-bus:before,body.dashboard .page-content .header .ion-android-calendar:before,body.dashboard .page-content .header .ion-android-call:before,body.dashboard .page-content .header .ion-android-camera:before,body.dashboard .page-content .header .ion-android-cancel:before,body.dashboard .page-content .header .ion-android-car:before,body.dashboard .page-content .header .ion-android-cart:before,body.dashboard .page-content .header .ion-android-chat:before,body.dashboard .page-content .header .ion-android-checkbox-blank:before,body.dashboard .page-content .header .ion-android-checkbox-outline-blank:before,body.dashboard .page-content .header .ion-android-checkbox-outline:before,body.dashboard .page-content .header .ion-android-checkbox:before,body.dashboard .page-content .header .ion-android-checkmark-circle:before,body.dashboard .page-content .header .ion-android-clipboard:before,body.dashboard .page-content .header .ion-android-close:before,body.dashboard .page-content .header .ion-android-cloud-circle:before,body.dashboard .page-content .header .ion-android-cloud-done:before,body.dashboard .page-content .header .ion-android-cloud-outline:before,body.dashboard .page-content .header .ion-android-cloud:before,body.dashboard .page-content .header .ion-android-color-palette:before,body.dashboard .page-content .header .ion-android-compass:before,body.dashboard .page-content .header .ion-android-contact:before,body.dashboard .page-content .header .ion-android-contacts:before,body.dashboard .page-content .header .ion-android-contract:before,body.dashboard .page-content .header .ion-android-create:before,body.dashboard .page-content .header .ion-android-delete:before,body.dashboard .page-content .header .ion-android-desktop:before,body.dashboard .page-content .header .ion-android-document:before,body.dashboard .page-content .header .ion-android-done-all:before,body.dashboard .page-content .header .ion-android-done:before,body.dashboard .page-content .header .ion-android-download:before,body.dashboard .page-content .header .ion-android-drafts:before,body.dashboard .page-content .header .ion-android-exit:before,body.dashboard .page-content .header .ion-android-expand:before,body.dashboard .page-content .header .ion-android-favorite-outline:before,body.dashboard .page-content .header .ion-android-favorite:before,body.dashboard .page-content .header .ion-android-film:before,body.dashboard .page-content .header .ion-android-folder-open:before,body.dashboard .page-content .header .ion-android-folder:before,body.dashboard .page-content .header .ion-android-funnel:before,body.dashboard .page-content .header .ion-android-globe:before,body.dashboard .page-content .header .ion-android-hand:before,body.dashboard .page-content .header .ion-android-hangout:before,body.dashboard .page-content .header .ion-android-happy:before,body.dashboard .page-content .header .ion-android-home:before,body.dashboard .page-content .header .ion-android-image:before,body.dashboard .page-content .header .ion-android-laptop:before,body.dashboard .page-content .header .ion-android-list:before,body.dashboard .page-content .header .ion-android-locate:before,body.dashboard .page-content .header .ion-android-lock:before,body.dashboard .page-content .header .ion-android-mail:before,body.dashboard .page-content .header .ion-android-map:before,body.dashboard .page-content .header .ion-android-menu:before,body.dashboard .page-content .header .ion-android-microphone-off:before,body.dashboard .page-content .header .ion-android-microphone:before,body.dashboard .page-content .header .ion-android-more-horizontal:before,body.dashboard .page-content .header .ion-android-more-vertical:before,body.dashboard .page-content .header .ion-android-navigate:before,body.dashboard .page-content .header .ion-android-notifications-none:before,body.dashboard .page-content .header .ion-android-notifications-off:before,body.dashboard .page-content .header .ion-android-notifications:before,body.dashboard .page-content .header .ion-android-open:before,body.dashboard .page-content .header .ion-android-options:before,body.dashboard .page-content .header .ion-android-people:before,body.dashboard .page-content .header .ion-android-person-add:before,body.dashboard .page-content .header .ion-android-person:before,body.dashboard .page-content .header .ion-android-phone-landscape:before,body.dashboard .page-content .header .ion-android-phone-portrait:before,body.dashboard .page-content .header .ion-android-pin:before,body.dashboard .page-content .header .ion-android-plane:before,body.dashboard .page-content .header .ion-android-playstore:before,body.dashboard .page-content .header .ion-android-print:before,body.dashboard .page-content .header .ion-android-radio-button-off:before,body.dashboard .page-content .header .ion-android-radio-button-on:before,body.dashboard .page-content .header .ion-android-refresh:before,body.dashboard .page-content .header .ion-android-remove-circle:before,body.dashboard .page-content .header .ion-android-remove:before,body.dashboard .page-content .header .ion-android-restaurant:before,body.dashboard .page-content .header .ion-android-sad:before,body.dashboard .page-content .header .ion-android-search:before,body.dashboard .page-content .header .ion-android-send:before,body.dashboard .page-content .header .ion-android-settings:before,body.dashboard .page-content .header .ion-android-share-alt:before,body.dashboard .page-content .header .ion-android-share:before,body.dashboard .page-content .header .ion-android-star-half:before,body.dashboard .page-content .header .ion-android-star-outline:before,body.dashboard .page-content .header .ion-android-star:before,body.dashboard .page-content .header .ion-android-stopwatch:before,body.dashboard .page-content .header .ion-android-subway:before,body.dashboard .page-content .header .ion-android-sunny:before,body.dashboard .page-content .header .ion-android-sync:before,body.dashboard .page-content .header .ion-android-textsms:before,body.dashboard .page-content .header .ion-android-time:before,body.dashboard .page-content .header .ion-android-train:before,body.dashboard .page-content .header .ion-android-unlock:before,body.dashboard .page-content .header .ion-android-upload:before,body.dashboard .page-content .header .ion-android-volume-down:before,body.dashboard .page-content .header .ion-android-volume-mute:before,body.dashboard .page-content .header .ion-android-volume-off:before,body.dashboard .page-content .header .ion-android-volume-up:before,body.dashboard .page-content .header .ion-android-walk:before,body.dashboard .page-content .header .ion-android-warning:before,body.dashboard .page-content .header .ion-android-watch:before,body.dashboard .page-content .header .ion-android-wifi:before,body.dashboard .page-content .header .ion-aperture:before,body.dashboard .page-content .header .ion-archive:before,body.dashboard .page-content .header .ion-arrow-down-a:before,body.dashboard .page-content .header .ion-arrow-down-b:before,body.dashboard .page-content .header .ion-arrow-down-c:before,body.dashboard .page-content .header .ion-arrow-expand:before,body.dashboard .page-content .header .ion-arrow-graph-down-left:before,body.dashboard .page-content .header .ion-arrow-graph-down-right:before,body.dashboard .page-content .header .ion-arrow-graph-up-left:before,body.dashboard .page-content .header .ion-arrow-graph-up-right:before,body.dashboard .page-content .header .ion-arrow-left-a:before,body.dashboard .page-content .header .ion-arrow-left-b:before,body.dashboard .page-content .header .ion-arrow-left-c:before,body.dashboard .page-content .header .ion-arrow-move:before,body.dashboard .page-content .header .ion-arrow-resize:before,body.dashboard .page-content .header .ion-arrow-return-left:before,body.dashboard .page-content .header .ion-arrow-return-right:before,body.dashboard .page-content .header .ion-arrow-right-a:before,body.dashboard .page-content .header .ion-arrow-right-b:before,body.dashboard .page-content .header .ion-arrow-right-c:before,body.dashboard .page-content .header .ion-arrow-shrink:before,body.dashboard .page-content .header .ion-arrow-swap:before,body.dashboard .page-content .header .ion-arrow-up-a:before,body.dashboard .page-content .header .ion-arrow-up-b:before,body.dashboard .page-content .header .ion-arrow-up-c:before,body.dashboard .page-content .header .ion-asterisk:before,body.dashboard .page-content .header .ion-at:before,body.dashboard .page-content .header .ion-backspace-outline:before,body.dashboard .page-content .header .ion-backspace:before,body.dashboard .page-content .header .ion-bag:before,body.dashboard .page-content .header .ion-battery-charging:before,body.dashboard .page-content .header .ion-battery-empty:before,body.dashboard .page-content .header .ion-battery-full:before,body.dashboard .page-content .header .ion-battery-half:before,body.dashboard .page-content .header .ion-battery-low:before,body.dashboard .page-content .header .ion-beaker:before,body.dashboard .page-content .header .ion-beer:before,body.dashboard .page-content .header .ion-bluetooth:before,body.dashboard .page-content .header .ion-bonfire:before,body.dashboard .page-content .header .ion-bookmark:before,body.dashboard .page-content .header .ion-bowtie:before,body.dashboard .page-content .header .ion-briefcase:before,body.dashboard .page-content .header .ion-bug:before,body.dashboard .page-content .header .ion-calculator:before,body.dashboard .page-content .header .ion-calendar:before,body.dashboard .page-content .header .ion-camera:before,body.dashboard .page-content .header .ion-card:before,body.dashboard .page-content .header .ion-cash:before,body.dashboard .page-content .header .ion-chatbox-working:before,body.dashboard .page-content .header .ion-chatbox:before,body.dashboard .page-content .header .ion-chatboxes:before,body.dashboard .page-content .header .ion-chatbubble-working:before,body.dashboard .page-content .header .ion-chatbubble:before,body.dashboard .page-content .header .ion-chatbubbles:before,body.dashboard .page-content .header .ion-checkmark-circled:before,body.dashboard .page-content .header .ion-checkmark-round:before,body.dashboard .page-content .header .ion-checkmark:before,body.dashboard .page-content .header .ion-chevron-down:before,body.dashboard .page-content .header .ion-chevron-left:before,body.dashboard .page-content .header .ion-chevron-right:before,body.dashboard .page-content .header .ion-chevron-up:before,body.dashboard .page-content .header .ion-clipboard:before,body.dashboard .page-content .header .ion-clock:before,body.dashboard .page-content .header .ion-close-circled:before,body.dashboard .page-content .header .ion-close-round:before,body.dashboard .page-content .header .ion-close:before,body.dashboard .page-content .header .ion-closed-captioning:before,body.dashboard .page-content .header .ion-cloud:before,body.dashboard .page-content .header .ion-code-download:before,body.dashboard .page-content .header .ion-code-working:before,body.dashboard .page-content .header .ion-code:before,body.dashboard .page-content .header .ion-coffee:before,body.dashboard .page-content .header .ion-compass:before,body.dashboard .page-content .header .ion-compose:before,body.dashboard .page-content .header .ion-connection-bars:before,body.dashboard .page-content .header .ion-contrast:before,body.dashboard .page-content .header .ion-crop:before,body.dashboard .page-content .header .ion-cube:before,body.dashboard .page-content .header .ion-disc:before,body.dashboard .page-content .header .ion-document-text:before,body.dashboard .page-content .header .ion-document:before,body.dashboard .page-content .header .ion-drag:before,body.dashboard .page-content .header .ion-earth:before,body.dashboard .page-content .header .ion-easel:before,body.dashboard .page-content .header .ion-edit:before,body.dashboard .page-content .header .ion-egg:before,body.dashboard .page-content .header .ion-eject:before,body.dashboard .page-content .header .ion-email-unread:before,body.dashboard .page-content .header .ion-email:before,body.dashboard .page-content .header .ion-erlenmeyer-flask-bubbles:before,body.dashboard .page-content .header .ion-erlenmeyer-flask:before,body.dashboard .page-content .header .ion-eye-disabled:before,body.dashboard .page-content .header .ion-eye:before,body.dashboard .page-content .header .ion-female:before,body.dashboard .page-content .header .ion-filing:before,body.dashboard .page-content .header .ion-film-marker:before,body.dashboard .page-content .header .ion-fireball:before,body.dashboard .page-content .header .ion-flag:before,body.dashboard .page-content .header .ion-flame:before,body.dashboard .page-content .header .ion-flash-off:before,body.dashboard .page-content .header .ion-flash:before,body.dashboard .page-content .header .ion-folder:before,body.dashboard .page-content .header .ion-fork-repo:before,body.dashboard .page-content .header .ion-fork:before,body.dashboard .page-content .header .ion-forward:before,body.dashboard .page-content .header .ion-funnel:before,body.dashboard .page-content .header .ion-gear-a:before,body.dashboard .page-content .header .ion-gear-b:before,body.dashboard .page-content .header .ion-grid:before,body.dashboard .page-content .header .ion-hammer:before,body.dashboard .page-content .header .ion-happy-outline:before,body.dashboard .page-content .header .ion-happy:before,body.dashboard .page-content .header .ion-headphone:before,body.dashboard .page-content .header .ion-heart-broken:before,body.dashboard .page-content .header .ion-heart:before,body.dashboard .page-content .header .ion-help-buoy:before,body.dashboard .page-content .header .ion-help-circled:before,body.dashboard .page-content .header .ion-help:before,body.dashboard .page-content .header .ion-home:before,body.dashboard .page-content .header .ion-icecream:before,body.dashboard .page-content .header .ion-image:before,body.dashboard .page-content .header .ion-images:before,body.dashboard .page-content .header .ion-information-circled:before,body.dashboard .page-content .header .ion-information:before,body.dashboard .page-content .header .ion-ionic:before,body.dashboard .page-content .header .ion-ios-alarm-outline:before,body.dashboard .page-content .header .ion-ios-alarm:before,body.dashboard .page-content .header .ion-ios-albums-outline:before,body.dashboard .page-content .header .ion-ios-albums:before,body.dashboard .page-content .header .ion-ios-americanfootball-outline:before,body.dashboard .page-content .header .ion-ios-americanfootball:before,body.dashboard .page-content .header .ion-ios-analytics-outline:before,body.dashboard .page-content .header .ion-ios-analytics:before,body.dashboard .page-content .header .ion-ios-arrow-back:before,body.dashboard .page-content .header .ion-ios-arrow-down:before,body.dashboard .page-content .header .ion-ios-arrow-forward:before,body.dashboard .page-content .header .ion-ios-arrow-left:before,body.dashboard .page-content .header .ion-ios-arrow-right:before,body.dashboard .page-content .header .ion-ios-arrow-thin-down:before,body.dashboard .page-content .header .ion-ios-arrow-thin-left:before,body.dashboard .page-content .header .ion-ios-arrow-thin-right:before,body.dashboard .page-content .header .ion-ios-arrow-thin-up:before,body.dashboard .page-content .header .ion-ios-arrow-up:before,body.dashboard .page-content .header .ion-ios-at-outline:before,body.dashboard .page-content .header .ion-ios-at:before,body.dashboard .page-content .header .ion-ios-barcode-outline:before,body.dashboard .page-content .header .ion-ios-barcode:before,body.dashboard .page-content .header .ion-ios-baseball-outline:before,body.dashboard .page-content .header .ion-ios-baseball:before,body.dashboard .page-content .header .ion-ios-basketball-outline:before,body.dashboard .page-content .header .ion-ios-basketball:before,body.dashboard .page-content .header .ion-ios-bell-outline:before,body.dashboard .page-content .header .ion-ios-bell:before,body.dashboard .page-content .header .ion-ios-body-outline:before,body.dashboard .page-content .header .ion-ios-body:before,body.dashboard .page-content .header .ion-ios-bolt-outline:before,body.dashboard .page-content .header .ion-ios-bolt:before,body.dashboard .page-content .header .ion-ios-book-outline:before,body.dashboard .page-content .header .ion-ios-book:before,body.dashboard .page-content .header .ion-ios-bookmarks-outline:before,body.dashboard .page-content .header .ion-ios-bookmarks:before,body.dashboard .page-content .header .ion-ios-box-outline:before,body.dashboard .page-content .header .ion-ios-box:before,body.dashboard .page-content .header .ion-ios-briefcase-outline:before,body.dashboard .page-content .header .ion-ios-briefcase:before,body.dashboard .page-content .header .ion-ios-browsers-outline:before,body.dashboard .page-content .header .ion-ios-browsers:before,body.dashboard .page-content .header .ion-ios-calculator-outline:before,body.dashboard .page-content .header .ion-ios-calculator:before,body.dashboard .page-content .header .ion-ios-calendar-outline:before,body.dashboard .page-content .header .ion-ios-calendar:before,body.dashboard .page-content .header .ion-ios-camera-outline:before,body.dashboard .page-content .header .ion-ios-camera:before,body.dashboard .page-content .header .ion-ios-cart-outline:before,body.dashboard .page-content .header .ion-ios-cart:before,body.dashboard .page-content .header .ion-ios-chatboxes-outline:before,body.dashboard .page-content .header .ion-ios-chatboxes:before,body.dashboard .page-content .header .ion-ios-chatbubble-outline:before,body.dashboard .page-content .header .ion-ios-chatbubble:before,body.dashboard .page-content .header .ion-ios-checkmark-empty:before,body.dashboard .page-content .header .ion-ios-checkmark-outline:before,body.dashboard .page-content .header .ion-ios-checkmark:before,body.dashboard .page-content .header .ion-ios-circle-filled:before,body.dashboard .page-content .header .ion-ios-circle-outline:before,body.dashboard .page-content .header .ion-ios-clock-outline:before,body.dashboard .page-content .header .ion-ios-clock:before,body.dashboard .page-content .header .ion-ios-close-empty:before,body.dashboard .page-content .header .ion-ios-close-outline:before,body.dashboard .page-content .header .ion-ios-close:before,body.dashboard .page-content .header .ion-ios-cloud-download-outline:before,body.dashboard .page-content .header .ion-ios-cloud-download:before,body.dashboard .page-content .header .ion-ios-cloud-outline:before,body.dashboard .page-content .header .ion-ios-cloud-upload-outline:before,body.dashboard .page-content .header .ion-ios-cloud-upload:before,body.dashboard .page-content .header .ion-ios-cloud:before,body.dashboard .page-content .header .ion-ios-cloudy-night-outline:before,body.dashboard .page-content .header .ion-ios-cloudy-night:before,body.dashboard .page-content .header .ion-ios-cloudy-outline:before,body.dashboard .page-content .header .ion-ios-cloudy:before,body.dashboard .page-content .header .ion-ios-cog-outline:before,body.dashboard .page-content .header .ion-ios-cog:before,body.dashboard .page-content .header .ion-ios-color-filter-outline:before,body.dashboard .page-content .header .ion-ios-color-filter:before,body.dashboard .page-content .header .ion-ios-color-wand-outline:before,body.dashboard .page-content .header .ion-ios-color-wand:before,body.dashboard .page-content .header .ion-ios-compose-outline:before,body.dashboard .page-content .header .ion-ios-compose:before,body.dashboard .page-content .header .ion-ios-contact-outline:before,body.dashboard .page-content .header .ion-ios-contact:before,body.dashboard .page-content .header .ion-ios-copy-outline:before,body.dashboard .page-content .header .ion-ios-copy:before,body.dashboard .page-content .header .ion-ios-crop-strong:before,body.dashboard .page-content .header .ion-ios-crop:before,body.dashboard .page-content .header .ion-ios-download-outline:before,body.dashboard .page-content .header .ion-ios-download:before,body.dashboard .page-content .header .ion-ios-drag:before,body.dashboard .page-content .header .ion-ios-email-outline:before,body.dashboard .page-content .header .ion-ios-email:before,body.dashboard .page-content .header .ion-ios-eye-outline:before,body.dashboard .page-content .header .ion-ios-eye:before,body.dashboard .page-content .header .ion-ios-fastforward-outline:before,body.dashboard .page-content .header .ion-ios-fastforward:before,body.dashboard .page-content .header .ion-ios-filing-outline:before,body.dashboard .page-content .header .ion-ios-filing:before,body.dashboard .page-content .header .ion-ios-film-outline:before,body.dashboard .page-content .header .ion-ios-film:before,body.dashboard .page-content .header .ion-ios-flag-outline:before,body.dashboard .page-content .header .ion-ios-flag:before,body.dashboard .page-content .header .ion-ios-flame-outline:before,body.dashboard .page-content .header .ion-ios-flame:before,body.dashboard .page-content .header .ion-ios-flask-outline:before,body.dashboard .page-content .header .ion-ios-flask:before,body.dashboard .page-content .header .ion-ios-flower-outline:before,body.dashboard .page-content .header .ion-ios-flower:before,body.dashboard .page-content .header .ion-ios-folder-outline:before,body.dashboard .page-content .header .ion-ios-folder:before,body.dashboard .page-content .header .ion-ios-football-outline:before,body.dashboard .page-content .header .ion-ios-football:before,body.dashboard .page-content .header .ion-ios-game-controller-a-outline:before,body.dashboard .page-content .header .ion-ios-game-controller-a:before,body.dashboard .page-content .header .ion-ios-game-controller-b-outline:before,body.dashboard .page-content .header .ion-ios-game-controller-b:before,body.dashboard .page-content .header .ion-ios-gear-outline:before,body.dashboard .page-content .header .ion-ios-gear:before,body.dashboard .page-content .header .ion-ios-glasses-outline:before,body.dashboard .page-content .header .ion-ios-glasses:before,body.dashboard .page-content .header .ion-ios-grid-view-outline:before,body.dashboard .page-content .header .ion-ios-grid-view:before,body.dashboard .page-content .header .ion-ios-heart-outline:before,body.dashboard .page-content .header .ion-ios-heart:before,body.dashboard .page-content .header .ion-ios-help-empty:before,body.dashboard .page-content .header .ion-ios-help-outline:before,body.dashboard .page-content .header .ion-ios-help:before,body.dashboard .page-content .header .ion-ios-home-outline:before,body.dashboard .page-content .header .ion-ios-home:before,body.dashboard .page-content .header .ion-ios-infinite-outline:before,body.dashboard .page-content .header .ion-ios-infinite:before,body.dashboard .page-content .header .ion-ios-information-empty:before,body.dashboard .page-content .header .ion-ios-information-outline:before,body.dashboard .page-content .header .ion-ios-information:before,body.dashboard .page-content .header .ion-ios-ionic-outline:before,body.dashboard .page-content .header .ion-ios-keypad-outline:before,body.dashboard .page-content .header .ion-ios-keypad:before,body.dashboard .page-content .header .ion-ios-lightbulb-outline:before,body.dashboard .page-content .header .ion-ios-lightbulb:before,body.dashboard .page-content .header .ion-ios-list-outline:before,body.dashboard .page-content .header .ion-ios-list:before,body.dashboard .page-content .header .ion-ios-location-outline:before,body.dashboard .page-content .header .ion-ios-location:before,body.dashboard .page-content .header .ion-ios-locked-outline:before,body.dashboard .page-content .header .ion-ios-locked:before,body.dashboard .page-content .header .ion-ios-loop-strong:before,body.dashboard .page-content .header .ion-ios-loop:before,body.dashboard .page-content .header .ion-ios-medical-outline:before,body.dashboard .page-content .header .ion-ios-medical:before,body.dashboard .page-content .header .ion-ios-medkit-outline:before,body.dashboard .page-content .header .ion-ios-medkit:before,body.dashboard .page-content .header .ion-ios-mic-off:before,body.dashboard .page-content .header .ion-ios-mic-outline:before,body.dashboard .page-content .header .ion-ios-mic:before,body.dashboard .page-content .header .ion-ios-minus-empty:before,body.dashboard .page-content .header .ion-ios-minus-outline:before,body.dashboard .page-content .header .ion-ios-minus:before,body.dashboard .page-content .header .ion-ios-monitor-outline:before,body.dashboard .page-content .header .ion-ios-monitor:before,body.dashboard .page-content .header .ion-ios-moon-outline:before,body.dashboard .page-content .header .ion-ios-moon:before,body.dashboard .page-content .header .ion-ios-more-outline:before,body.dashboard .page-content .header .ion-ios-more:before,body.dashboard .page-content .header .ion-ios-musical-note:before,body.dashboard .page-content .header .ion-ios-musical-notes:before,body.dashboard .page-content .header .ion-ios-navigate-outline:before,body.dashboard .page-content .header .ion-ios-navigate:before,body.dashboard .page-content .header .ion-ios-nutrition-outline:before,body.dashboard .page-content .header .ion-ios-nutrition:before,body.dashboard .page-content .header .ion-ios-paper-outline:before,body.dashboard .page-content .header .ion-ios-paper:before,body.dashboard .page-content .header .ion-ios-paperplane-outline:before,body.dashboard .page-content .header .ion-ios-paperplane:before,body.dashboard .page-content .header .ion-ios-partlysunny-outline:before,body.dashboard .page-content .header .ion-ios-partlysunny:before,body.dashboard .page-content .header .ion-ios-pause-outline:before,body.dashboard .page-content .header .ion-ios-pause:before,body.dashboard .page-content .header .ion-ios-paw-outline:before,body.dashboard .page-content .header .ion-ios-paw:before,body.dashboard .page-content .header .ion-ios-people-outline:before,body.dashboard .page-content .header .ion-ios-people:before,body.dashboard .page-content .header .ion-ios-person-outline:before,body.dashboard .page-content .header .ion-ios-person:before,body.dashboard .page-content .header .ion-ios-personadd-outline:before,body.dashboard .page-content .header .ion-ios-personadd:before,body.dashboard .page-content .header .ion-ios-photos-outline:before,body.dashboard .page-content .header .ion-ios-photos:before,body.dashboard .page-content .header .ion-ios-pie-outline:before,body.dashboard .page-content .header .ion-ios-pie:before,body.dashboard .page-content .header .ion-ios-pint-outline:before,body.dashboard .page-content .header .ion-ios-pint:before,body.dashboard .page-content .header .ion-ios-play-outline:before,body.dashboard .page-content .header .ion-ios-play:before,body.dashboard .page-content .header .ion-ios-plus-empty:before,body.dashboard .page-content .header .ion-ios-plus-outline:before,body.dashboard .page-content .header .ion-ios-plus:before,body.dashboard .page-content .header .ion-ios-pricetag-outline:before,body.dashboard .page-content .header .ion-ios-pricetag:before,body.dashboard .page-content .header .ion-ios-pricetags-outline:before,body.dashboard .page-content .header .ion-ios-pricetags:before,body.dashboard .page-content .header .ion-ios-printer-outline:before,body.dashboard .page-content .header .ion-ios-printer:before,body.dashboard .page-content .header .ion-ios-pulse-strong:before,body.dashboard .page-content .header .ion-ios-pulse:before,body.dashboard .page-content .header .ion-ios-rainy-outline:before,body.dashboard .page-content .header .ion-ios-rainy:before,body.dashboard .page-content .header .ion-ios-recording-outline:before,body.dashboard .page-content .header .ion-ios-recording:before,body.dashboard .page-content .header .ion-ios-redo-outline:before,body.dashboard .page-content .header .ion-ios-redo:before,body.dashboard .page-content .header .ion-ios-refresh-empty:before,body.dashboard .page-content .header .ion-ios-refresh-outline:before,body.dashboard .page-content .header .ion-ios-refresh:before,body.dashboard .page-content .header .ion-ios-reload:before,body.dashboard .page-content .header .ion-ios-reverse-camera-outline:before,body.dashboard .page-content .header .ion-ios-reverse-camera:before,body.dashboard .page-content .header .ion-ios-rewind-outline:before,body.dashboard .page-content .header .ion-ios-rewind:before,body.dashboard .page-content .header .ion-ios-rose-outline:before,body.dashboard .page-content .header .ion-ios-rose:before,body.dashboard .page-content .header .ion-ios-search-strong:before,body.dashboard .page-content .header .ion-ios-search:before,body.dashboard .page-content .header .ion-ios-settings-strong:before,body.dashboard .page-content .header .ion-ios-settings:before,body.dashboard .page-content .header .ion-ios-shuffle-strong:before,body.dashboard .page-content .header .ion-ios-shuffle:before,body.dashboard .page-content .header .ion-ios-skipbackward-outline:before,body.dashboard .page-content .header .ion-ios-skipbackward:before,body.dashboard .page-content .header .ion-ios-skipforward-outline:before,body.dashboard .page-content .header .ion-ios-skipforward:before,body.dashboard .page-content .header .ion-ios-snowy:before,body.dashboard .page-content .header .ion-ios-speedometer-outline:before,body.dashboard .page-content .header .ion-ios-speedometer:before,body.dashboard .page-content .header .ion-ios-star-half:before,body.dashboard .page-content .header .ion-ios-star-outline:before,body.dashboard .page-content .header .ion-ios-star:before,body.dashboard .page-content .header .ion-ios-stopwatch-outline:before,body.dashboard .page-content .header .ion-ios-stopwatch:before,body.dashboard .page-content .header .ion-ios-sunny-outline:before,body.dashboard .page-content .header .ion-ios-sunny:before,body.dashboard .page-content .header .ion-ios-telephone-outline:before,body.dashboard .page-content .header .ion-ios-telephone:before,body.dashboard .page-content .header .ion-ios-tennisball-outline:before,body.dashboard .page-content .header .ion-ios-tennisball:before,body.dashboard .page-content .header .ion-ios-thunderstorm-outline:before,body.dashboard .page-content .header .ion-ios-thunderstorm:before,body.dashboard .page-content .header .ion-ios-time-outline:before,body.dashboard .page-content .header .ion-ios-time:before,body.dashboard .page-content .header .ion-ios-timer-outline:before,body.dashboard .page-content .header .ion-ios-timer:before,body.dashboard .page-content .header .ion-ios-toggle-outline:before,body.dashboard .page-content .header .ion-ios-toggle:before,body.dashboard .page-content .header .ion-ios-trash-outline:before,body.dashboard .page-content .header .ion-ios-trash:before,body.dashboard .page-content .header .ion-ios-undo-outline:before,body.dashboard .page-content .header .ion-ios-undo:before,body.dashboard .page-content .header .ion-ios-unlocked-outline:before,body.dashboard .page-content .header .ion-ios-unlocked:before,body.dashboard .page-content .header .ion-ios-upload-outline:before,body.dashboard .page-content .header .ion-ios-upload:before,body.dashboard .page-content .header .ion-ios-videocam-outline:before,body.dashboard .page-content .header .ion-ios-videocam:before,body.dashboard .page-content .header .ion-ios-volume-high:before,body.dashboard .page-content .header .ion-ios-volume-low:before,body.dashboard .page-content .header .ion-ios-wineglass-outline:before,body.dashboard .page-content .header .ion-ios-wineglass:before,body.dashboard .page-content .header .ion-ios-world-outline:before,body.dashboard .page-content .header .ion-ios-world:before,body.dashboard .page-content .header .ion-ipad:before,body.dashboard .page-content .header .ion-iphone:before,body.dashboard .page-content .header .ion-ipod:before,body.dashboard .page-content .header .ion-jet:before,body.dashboard .page-content .header .ion-key:before,body.dashboard .page-content .header .ion-knife:before,body.dashboard .page-content .header .ion-laptop:before,body.dashboard .page-content .header .ion-leaf:before,body.dashboard .page-content .header .ion-levels:before,body.dashboard .page-content .header .ion-lightbulb:before,body.dashboard .page-content .header .ion-link:before,body.dashboard .page-content .header .ion-load-a:before,body.dashboard .page-content .header .ion-load-b:before,body.dashboard .page-content .header .ion-load-c:before,body.dashboard .page-content .header .ion-load-d:before,body.dashboard .page-content .header .ion-location:before,body.dashboard .page-content .header .ion-lock-combination:before,body.dashboard .page-content .header .ion-locked:before,body.dashboard .page-content .header .ion-log-in:before,body.dashboard .page-content .header .ion-log-out:before,body.dashboard .page-content .header .ion-loop:before,body.dashboard .page-content .header .ion-magnet:before,body.dashboard .page-content .header .ion-male:before,body.dashboard .page-content .header .ion-man:before,body.dashboard .page-content .header .ion-map:before,body.dashboard .page-content .header .ion-medkit:before,body.dashboard .page-content .header .ion-merge:before,body.dashboard .page-content .header .ion-mic-a:before,body.dashboard .page-content .header .ion-mic-b:before,body.dashboard .page-content .header .ion-mic-c:before,body.dashboard .page-content .header .ion-minus-circled:before,body.dashboard .page-content .header .ion-minus-round:before,body.dashboard .page-content .header .ion-minus:before,body.dashboard .page-content .header .ion-model-s:before,body.dashboard .page-content .header .ion-monitor:before,body.dashboard .page-content .header .ion-more:before,body.dashboard .page-content .header .ion-mouse:before,body.dashboard .page-content .header .ion-music-note:before,body.dashboard .page-content .header .ion-navicon-round:before,body.dashboard .page-content .header .ion-navicon:before,body.dashboard .page-content .header .ion-navigate:before,body.dashboard .page-content .header .ion-network:before,body.dashboard .page-content .header .ion-no-smoking:before,body.dashboard .page-content .header .ion-nuclear:before,body.dashboard .page-content .header .ion-outlet:before,body.dashboard .page-content .header .ion-paintbrush:before,body.dashboard .page-content .header .ion-paintbucket:before,body.dashboard .page-content .header .ion-paper-airplane:before,body.dashboard .page-content .header .ion-paperclip:before,body.dashboard .page-content .header .ion-pause:before,body.dashboard .page-content .header .ion-person-add:before,body.dashboard .page-content .header .ion-person-stalker:before,body.dashboard .page-content .header .ion-person:before,body.dashboard .page-content .header .ion-pie-graph:before,body.dashboard .page-content .header .ion-pin:before,body.dashboard .page-content .header .ion-pinpoint:before,body.dashboard .page-content .header .ion-pizza:before,body.dashboard .page-content .header .ion-plane:before,body.dashboard .page-content .header .ion-planet:before,body.dashboard .page-content .header .ion-play:before,body.dashboard .page-content .header .ion-playstation:before,body.dashboard .page-content .header .ion-plus-circled:before,body.dashboard .page-content .header .ion-plus-round:before,body.dashboard .page-content .header .ion-plus:before,body.dashboard .page-content .header .ion-podium:before,body.dashboard .page-content .header .ion-pound:before,body.dashboard .page-content .header .ion-power:before,body.dashboard .page-content .header .ion-pricetag:before,body.dashboard .page-content .header .ion-pricetags:before,body.dashboard .page-content .header .ion-printer:before,body.dashboard .page-content .header .ion-pull-request:before,body.dashboard .page-content .header .ion-qr-scanner:before,body.dashboard .page-content .header .ion-quote:before,body.dashboard .page-content .header .ion-radio-waves:before,body.dashboard .page-content .header .ion-record:before,body.dashboard .page-content .header .ion-refresh:before,body.dashboard .page-content .header .ion-reply-all:before,body.dashboard .page-content .header .ion-reply:before,body.dashboard .page-content .header .ion-ribbon-a:before,body.dashboard .page-content .header .ion-ribbon-b:before,body.dashboard .page-content .header .ion-sad-outline:before,body.dashboard .page-content .header .ion-sad:before,body.dashboard .page-content .header .ion-scissors:before,body.dashboard .page-content .header .ion-search:before,body.dashboard .page-content .header .ion-settings:before,body.dashboard .page-content .header .ion-share:before,body.dashboard .page-content .header .ion-shuffle:before,body.dashboard .page-content .header .ion-skip-backward:before,body.dashboard .page-content .header .ion-skip-forward:before,body.dashboard .page-content .header .ion-social-android-outline:before,body.dashboard .page-content .header .ion-social-android:before,body.dashboard .page-content .header .ion-social-angular-outline:before,body.dashboard .page-content .header .ion-social-angular:before,body.dashboard .page-content .header .ion-social-apple-outline:before,body.dashboard .page-content .header .ion-social-apple:before,body.dashboard .page-content .header .ion-social-bitcoin-outline:before,body.dashboard .page-content .header .ion-social-bitcoin:before,body.dashboard .page-content .header .ion-social-buffer-outline:before,body.dashboard .page-content .header .ion-social-buffer:before,body.dashboard .page-content .header .ion-social-chrome-outline:before,body.dashboard .page-content .header .ion-social-chrome:before,body.dashboard .page-content .header .ion-social-codepen-outline:before,body.dashboard .page-content .header .ion-social-codepen:before,body.dashboard .page-content .header .ion-social-css3-outline:before,body.dashboard .page-content .header .ion-social-css3:before,body.dashboard .page-content .header .ion-social-designernews-outline:before,body.dashboard .page-content .header .ion-social-designernews:before,body.dashboard .page-content .header .ion-social-dribbble-outline:before,body.dashboard .page-content .header .ion-social-dribbble:before,body.dashboard .page-content .header .ion-social-dropbox-outline:before,body.dashboard .page-content .header .ion-social-dropbox:before,body.dashboard .page-content .header .ion-social-euro-outline:before,body.dashboard .page-content .header .ion-social-euro:before,body.dashboard .page-content .header .ion-social-facebook-outline:before,body.dashboard .page-content .header .ion-social-facebook:before,body.dashboard .page-content .header .ion-social-foursquare-outline:before,body.dashboard .page-content .header .ion-social-foursquare:before,body.dashboard .page-content .header .ion-social-freebsd-devil:before,body.dashboard .page-content .header .ion-social-github-outline:before,body.dashboard .page-content .header .ion-social-github:before,body.dashboard .page-content .header .ion-social-google-outline:before,body.dashboard .page-content .header .ion-social-google:before,body.dashboard .page-content .header .ion-social-googleplus-outline:before,body.dashboard .page-content .header .ion-social-googleplus:before,body.dashboard .page-content .header .ion-social-hackernews-outline:before,body.dashboard .page-content .header .ion-social-hackernews:before,body.dashboard .page-content .header .ion-social-html5-outline:before,body.dashboard .page-content .header .ion-social-html5:before,body.dashboard .page-content .header .ion-social-instagram-outline:before,body.dashboard .page-content .header .ion-social-instagram:before,body.dashboard .page-content .header .ion-social-javascript-outline:before,body.dashboard .page-content .header .ion-social-javascript:before,body.dashboard .page-content .header .ion-social-linkedin-outline:before,body.dashboard .page-content .header .ion-social-linkedin:before,body.dashboard .page-content .header .ion-social-markdown:before,body.dashboard .page-content .header .ion-social-nodejs:before,body.dashboard .page-content .header .ion-social-octocat:before,body.dashboard .page-content .header .ion-social-pinterest-outline:before,body.dashboard .page-content .header .ion-social-pinterest:before,body.dashboard .page-content .header .ion-social-python:before,body.dashboard .page-content .header .ion-social-reddit-outline:before,body.dashboard .page-content .header .ion-social-reddit:before,body.dashboard .page-content .header .ion-social-rss-outline:before,body.dashboard .page-content .header .ion-social-rss:before,body.dashboard .page-content .header .ion-social-sass:before,body.dashboard .page-content .header .ion-social-skype-outline:before,body.dashboard .page-content .header .ion-social-skype:before,body.dashboard .page-content .header .ion-social-snapchat-outline:before,body.dashboard .page-content .header .ion-social-snapchat:before,body.dashboard .page-content .header .ion-social-tumblr-outline:before,body.dashboard .page-content .header .ion-social-tumblr:before,body.dashboard .page-content .header .ion-social-tux:before,body.dashboard .page-content .header .ion-social-twitch-outline:before,body.dashboard .page-content .header .ion-social-twitch:before,body.dashboard .page-content .header .ion-social-twitter-outline:before,body.dashboard .page-content .header .ion-social-twitter:before,body.dashboard .page-content .header .ion-social-usd-outline:before,body.dashboard .page-content .header .ion-social-usd:before,body.dashboard .page-content .header .ion-social-vimeo-outline:before,body.dashboard .page-content .header .ion-social-vimeo:before,body.dashboard .page-content .header .ion-social-whatsapp-outline:before,body.dashboard .page-content .header .ion-social-whatsapp:before,body.dashboard .page-content .header .ion-social-windows-outline:before,body.dashboard .page-content .header .ion-social-windows:before,body.dashboard .page-content .header .ion-social-wordpress-outline:before,body.dashboard .page-content .header .ion-social-wordpress:before,body.dashboard .page-content .header .ion-social-yahoo-outline:before,body.dashboard .page-content .header .ion-social-yahoo:before,body.dashboard .page-content .header .ion-social-yen-outline:before,body.dashboard .page-content .header .ion-social-yen:before,body.dashboard .page-content .header .ion-social-youtube-outline:before,body.dashboard .page-content .header .ion-social-youtube:before,body.dashboard .page-content .header .ion-soup-can-outline:before,body.dashboard .page-content .header .ion-soup-can:before,body.dashboard .page-content .header .ion-speakerphone:before,body.dashboard .page-content .header .ion-speedometer:before,body.dashboard .page-content .header .ion-spoon:before,body.dashboard .page-content .header .ion-star:before,body.dashboard .page-content .header .ion-stats-bars:before,body.dashboard .page-content .header .ion-steam:before,body.dashboard .page-content .header .ion-stop:before,body.dashboard .page-content .header .ion-thermometer:before,body.dashboard .page-content .header .ion-thumbsdown:before,body.dashboard .page-content .header .ion-thumbsup:before,body.dashboard .page-content .header .ion-toggle-filled:before,body.dashboard .page-content .header .ion-toggle:before,body.dashboard .page-content .header .ion-transgender:before,body.dashboard .page-content .header .ion-trash-a:before,body.dashboard .page-content .header .ion-trash-b:before,body.dashboard .page-content .header .ion-trophy:before,body.dashboard .page-content .header .ion-tshirt-outline:before,body.dashboard .page-content .header .ion-tshirt:before,body.dashboard .page-content .header .ion-umbrella:before,body.dashboard .page-content .header .ion-university:before,body.dashboard .page-content .header .ion-unlocked:before,body.dashboard .page-content .header .ion-upload:before,body.dashboard .page-content .header .ion-usb:before,body.dashboard .page-content .header .ion-videocamera:before,body.dashboard .page-content .header .ion-volume-high:before,body.dashboard .page-content .header .ion-volume-low:before,body.dashboard .page-content .header .ion-volume-medium:before,body.dashboard .page-content .header .ion-volume-mute:before,body.dashboard .page-content .header .ion-wand:before,body.dashboard .page-content .header .ion-waterdrop:before,body.dashboard .page-content .header .ion-wifi:before,body.dashboard .page-content .header .ion-wineglass:before,body.dashboard .page-content .header .ion-woman:before,body.dashboard .page-content .header .ion-wrench:before,body.dashboard .page-content .header .ion-xbox:before,body.dashboard .page-content .header .ionicons{margin-right:2px}body.dashboard .page-content .sub-header{font-weight:300;text-transform:uppercase}body.dashboard .page-content .sub-header a{text-transform:none}body.dashboard .page-content .striped-list .striped-list-item{border-bottom:1px solid #f0f0f0;padding:8px 0}body.dashboard .page-content .drag-handle{cursor:move}body.dashboard .page-content .user-grid .user img{border-radius:5px;margin-bottom:15px;border:0}body.dashboard .page-content .user-grid .user .name{font-weight:600}body.dashboard .page-content .user-grid .user .email{color:#444;margin-top:4px}@media (max-width:767px){body.dashboard .page-content .content-wrapper,body.dashboard .page-content .header,body.dashboard .page-content .header.fixed{padding-left:20px;padding-right:20px}}@media (min-width:768px) and (max-width:991px){body.dashboard .page-content .header.fixed{padding-left:120px}}#welcome-modal .modal-dialog{margin-top:65px}#welcome-modal .modal-content .modal-header{border-bottom:0}#welcome-modal .modal-content .modal-body{padding-bottom:50px}#welcome-modal .modal-content .modal-body header{text-align:center;font-weight:600;font-size:22px;color:#444;margin-bottom:23px}#welcome-modal .modal-content .modal-body p{font-size:13px;color:#555;margin:0 auto;width:80%;text-align:center;line-height:20px}#welcome-modal .modal-content .modal-body .go-dashboard{text-align:center;display:block;margin-top:10px}#welcome-modal .modal-content .modal-body .get-started{margin-top:40px}#welcome-modal .modal-content .modal-body .get-started .col-md-4{text-align:center;padding-bottom:50px}#welcome-modal .modal-content .modal-body .get-started .col-md-4 a{color:#666;display:block;margin-top:12px;font-size:13px}#welcome-modal .modal-content .modal-body .get-started .col-md-4 a i{font-size:38px;color:#6db81c;display:block}#welcome-modal .modal-content .modal-body .get-started .col-md-4 a:hover{text-decoration:none;color:#999}body.login .form-bg{border-radius:10px;margin:auto;margin-top:60px;padding:30px;width:320px;border:1px solid rgba(0,0,0,.1);box-shadow:0 20px 30px rgba(0,0,0,.2);background-color:#fff}body.login .logo{margin-bottom:30px}body.login .logo img{margin:0 auto}body.login .login-input{height:45px}body.login i{font-size:22px}body.login .btn.btn-white{background-color:#fff;transition:background-color .5s ease}body.login .btn.btn-white.btn-trans{background-color:transparent;border:1px solid #fff;border-radius:4px;color:#fff}body.login .btn.btn-white.btn-trans:hover{background-color:#fff;color:#7ed321}.setup-page{padding-top:60px}.setup-page .logo{display:block;margin:0 auto 30px}.setup-page .steps{margin:0 auto;border-radius:2px 2px 0 0;margin-bottom:20px}.setup-page .steps .step{padding:20px 0;text-align:center;position:relative;font-size:13px}.setup-page .steps .step:not(:last-child):after{content:'';position:absolute;bottom:31px;left:55%;display:block;height:1px;background:#94a1b8;width:100%}.setup-page .steps .step span{width:23px;height:23px;display:block;position:relative;margin:0 auto;margin-top:13px;border-radius:25px;background:#f0f3f4;border:1px solid #94a1b8;transition:all .2s linear}.setup-page .steps .step.active span{background:#7ed321}.setup-page .setup-success{text-align:center}.setup-page .setup-success i{font-size:47px}.setup-page .setup-success h3{margin-top:25px;font-size:21px;color:#556579}.setup-page .setup-success .btn{margin-top:40px}.component-inline-update{padding-top:8px}.component-inline-update label{display:initial;font-weight:400}.component-group-name{font-size:18px;padding-left:10px}.component-group-other{font-size:18px}.stats-widget{text-align:center;margin-bottom:30px;background-color:#fff;border:1px solid #eee}.stats-widget.full-stats-block .stats-bottom{border-top:0!important;color:#fff;position:relative;margin-top:-1px;z-index:1000}.stats-widget .stats-top{padding:20px}.stats-widget .stats-top>span{display:block;text-align:center}.stats-widget .stats-top>span.stats-value{font-size:24px;font-weight:400}.stats-widget .stats-top>span.stats-label{padding-top:5px;font-size:14px;font-weight:300;color:#777}.stats-widget .stats-body,.stats-widget .stats-chart{margin-top:-20px;padding-top:10px}.stats-widget .stats-body .list-group{border:none;padding-bottom:0;margin-bottom:0}.stats-widget .stats-body .list-group .list-group-item{border-right:none;border-left:none;border-color:#eee}.stats-widget .stats-body .list-group .list-group-item:last-child{border-bottom:none}.stats-widget .stats-bottom{border-top:1px solid #eee;color:#777;padding:12px 10px;text-align:center;background-color:#f9f9f9}.stats-widget .stats-bottom.bg-green{background-color:#7ed321;color:#fff}.stats-widget .stats-bottom.bg-blue{background-color:#3498db;color:#fff}.stats-widget .stats-bottom.bg-red{background-color:#ff6f6f;color:#fff}.stats-widget .stats-bottom.bg-teal{background-color:#0dccc0;color:#fff}ul.messenger,ul.messenger>li{margin:0;padding:0}ul.messenger>li{list-style:none}ul.messenger.messenger-empty{display:none}ul.messenger .messenger-message{overflow:hidden;*zoom:1}ul.messenger .messenger-message.messenger-hidden{display:none}ul.messenger .messenger-message .messenger-actions a,ul.messenger .messenger-message .messenger-phrase{padding-right:5px}ul.messenger .messenger-message .messenger-actions{float:right}ul.messenger .messenger-message .messenger-actions a{cursor:pointer;text-decoration:underline}ul.messenger .messenger-message ol,ul.messenger .messenger-message ul{margin:10px 18px 0}ul.messenger.messenger-fixed{position:fixed;z-index:10000}ul.messenger.messenger-fixed .messenger-message{min-width:0;box-sizing:border-box}ul.messenger.messenger-fixed .message .messenger-actions{float:left}ul.messenger.messenger-fixed.messenger-on-top{top:20px}ul.messenger.messenger-fixed.messenger-on-bottom{bottom:20px}ul.messenger.messenger-fixed.messenger-on-bottom,ul.messenger.messenger-fixed.messenger-on-top{left:50%;width:600px;margin-left:-300px}@media (max-width:960px){ul.messenger.messenger-fixed.messenger-on-bottom,ul.messenger.messenger-fixed.messenger-on-top{left:10%;width:80%;margin-left:0}}ul.messenger.messenger-fixed.messenger-on-bottom.messenger-on-right,ul.messenger.messenger-fixed.messenger-on-top.messenger-on-right{right:20px;left:auto}ul.messenger.messenger-fixed.messenger-on-bottom.messenger-on-left,ul.messenger.messenger-fixed.messenger-on-top.messenger-on-left{left:20px;margin-left:0}ul.messenger.messenger-fixed.messenger-on-left,ul.messenger.messenger-fixed.messenger-on-right{width:350px}ul.messenger.messenger-fixed.messenger-on-left .messenger-actions,ul.messenger.messenger-fixed.messenger-on-right .messenger-actions{float:left}ul.messenger .messenger-spinner{display:none}@keyframes ui-spinner-rotate-right{0%{transform:rotate(0deg)}25%{transform:rotate(180deg)}50%{transform:rotate(180deg)}75%{transform:rotate(1turn)}to{transform:rotate(1turn)}}@keyframes ui-spinner-rotate-left{0%{transform:rotate(0deg)}25%{transform:rotate(0deg)}50%{transform:rotate(180deg)}75%{transform:rotate(180deg)}to{transform:rotate(1turn)}}.messenger-spinner{position:relative;border-radius:100%}ul.messenger.messenger-spinner-active .messenger-spinner .messenger-spinner{display:block}.messenger-spinner .messenger-spinner-side{width:50%;height:100%;overflow:hidden;position:absolute}.messenger-spinner .messenger-spinner-side .messenger-spinner-fill{border-radius:999px;position:absolute;width:100%;height:100%;animation-iteration-count:infinite;animation-timing-function:linear}.messenger-spinner .messenger-spinner-side-left{left:0}.messenger-spinner .messenger-spinner-side-left .messenger-spinner-fill{left:100%;border-top-left-radius:0;border-bottom-left-radius:0;animation-name:ui-spinner-rotate-left;transform-origin:0 50%}.messenger-spinner .messenger-spinner-side-right{left:50%}.messenger-spinner .messenger-spinner-side-right .messenger-spinner-fill{left:-100%;border-top-right-radius:0;border-bottom-right-radius:0;animation-name:ui-spinner-rotate-right;transform-origin:100% 50%}ul.messenger-theme-air{-moz-user-select:none;-webkit-user-select:none;-o-user-select:none;-ms-user-select:none;user-select:none;font-family:Raleway,sans-serif}ul.messenger-theme-air .messenger-message{transition:background-color .4s;border-radius:5px;box-shadow:inset 0 0 0 1px #fff,inset 0 2px #fff,0 0 0 1px rgba(0,0,0,.1),0 1px rgba(0,0,0,.2);border:0;background-color:#fff;position:relative;margin-bottom:1em;font-size:13px;color:#666;font-weight:500;padding:10px 30px 11px 46px}ul.messenger-theme-air .messenger-message:hover{background-color:#fff}ul.messenger-theme-air .messenger-message .messenger-close{position:absolute;top:0;right:0;color:#888;opacity:1;font-weight:700;display:block;font-size:20px;line-height:20px;padding:8px 10px 7px 7px;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}ul.messenger-theme-air .messenger-message .messenger-close:hover{color:#444}ul.messenger-theme-air .messenger-message .messenger-close:active{color:#222}ul.messenger-theme-air .messenger-message .messenger-actions{float:none;margin-top:10px}ul.messenger-theme-air .messenger-message .messenger-actions a{box-shadow:0 0 0 1px rgba(0,0,0,.1),inset 0 1px hsla(0,0%,100%,.05);border-radius:4px;text-decoration:none;display:inline-block;padding:10px;color:#888;margin-right:10px;padding:3px 10px 5px;text-transform:capitalize}ul.messenger-theme-air .messenger-message .messenger-actions a:hover{box-shadow:0 0 0 1px rgba(0,0,0,.1),inset 0 1px hsla(0,0%,100%,.15);color:#444}ul.messenger-theme-air .messenger-message .messenger-actions a:active{box-shadow:0 0 0 1px rgba(0,0,0,.18),inset 0 1px rgba(0,0,0,.05);background:rgba(0,0,0,.04);color:#444}ul.messenger-theme-air .messenger-message .messenger-actions .messenger-phrase{display:none}ul.messenger-theme-air .messenger-message .messenger-message-inner:before{box-shadow:inset 0 1px 3px rgba(0,0,0,.3);border-radius:50%;position:absolute;left:17px;display:block;content:" ";top:50%;margin-top:-8px;height:13px;width:13px;z-index:20}ul.messenger-theme-air .messenger-message.alert-success .messenger-message-inner:before{background-color:#5fca4a}ul.messenger-theme-air .messenger-message.alert-error.messenger-retry-soon .messenger-spinner{width:24px;height:24px;background:transparent}ul.messenger-theme-air .messenger-message.alert-error.messenger-retry-soon .messenger-spinner .messenger-spinner-side .messenger-spinner-fill{background:#dd6a45;animation-duration:20s;opacity:1}ul.messenger-theme-air .messenger-message.alert-error.messenger-retry-soon .messenger-spinner:after{content:"";background:#fff;position:absolute;width:19px;height:19px;border-radius:50%;top:2px;left:2px;display:block}ul.messenger-theme-air .messenger-message.alert-error.messenger-retry-later .messenger-spinner{width:24px;height:24px;background:transparent}ul.messenger-theme-air .messenger-message.alert-error.messenger-retry-later .messenger-spinner .messenger-spinner-side .messenger-spinner-fill{background:#dd6a45;animation-duration:600s;opacity:1}ul.messenger-theme-air .messenger-message.alert-error.messenger-retry-later .messenger-spinner:after{content:"";background:#fff;position:absolute;width:19px;height:19px;border-radius:50%;top:2px;left:2px;display:block}ul.messenger-theme-air .messenger-message.alert-error .messenger-message-inner:before{background-color:#dd6a45}ul.messenger-theme-air .messenger-message.alert-info .messenger-message-inner:before{background-color:#61c4b8}ul.messenger-theme-air .messenger-spinner{display:block;position:absolute;left:12px;top:50%;margin-top:-13px;z-index:999;height:24px;width:24px;z-index:10} - -/*! -Animate.css - http://daneden.me/animate -Licensed under the MIT license - http://opensource.org/licenses/MIT -Copyright (c) 2015 Daniel Eden -*/.animated.infinite{animation-iteration-count:infinite}.animated.bounceIn,.animated.bounceOut,.animated.flipOutX,.animated.flipOutY{animation-duration:.75s}body{-webkit-backface-visibility:hidden}.animated{animation-duration:1s;animation-fill-mode:both}.animated.hinge{animation-duration:2s}.bootstrap-datetimepicker-widget{list-style:none}.bootstrap-datetimepicker-widget.dropdown-menu{margin:2px 0;padding:4px;width:19em}@media (min-width:768px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}@media (min-width:992px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}@media (min-width:1200px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}.bootstrap-datetimepicker-widget.dropdown-menu:after,.bootstrap-datetimepicker-widget.dropdown-menu:before{content:'';display:inline-block;position:absolute}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:before{border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);top:-7px;left:7px}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after{border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;top:-6px;left:8px}.bootstrap-datetimepicker-widget.dropdown-menu.top:before{border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);bottom:-7px;left:6px}.bootstrap-datetimepicker-widget.dropdown-menu.top:after{border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #fff;bottom:-6px;left:7px}.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:after{left:auto;right:7px}.bootstrap-datetimepicker-widget .list-unstyled{margin:0}.bootstrap-datetimepicker-widget a[data-action]{padding:6px 0}.bootstrap-datetimepicker-widget a[data-action]:active{box-shadow:none}.bootstrap-datetimepicker-widget .timepicker-hour,.bootstrap-datetimepicker-widget .timepicker-minute,.bootstrap-datetimepicker-widget .timepicker-second{width:54px;font-weight:700;font-size:1.2em;margin:0}.bootstrap-datetimepicker-widget button[data-action]{padding:6px}.bootstrap-datetimepicker-widget .btn[data-action=incrementHours]:after{content:"Increment Hours"}.bootstrap-datetimepicker-widget .btn[data-action=incrementMinutes]:after{content:"Increment Minutes"}.bootstrap-datetimepicker-widget .btn[data-action=decrementHours]:after{content:"Decrement Hours"}.bootstrap-datetimepicker-widget .btn[data-action=decrementMinutes]:after{content:"Decrement Minutes"}.bootstrap-datetimepicker-widget .btn[data-action=showHours]:after{content:"Show Hours"}.bootstrap-datetimepicker-widget .btn[data-action=showMinutes]:after{content:"Show Minutes"}.bootstrap-datetimepicker-widget .btn[data-action=togglePeriod]:after{content:"Toggle AM/PM"}.bootstrap-datetimepicker-widget .btn[data-action=clear]:after{content:"Clear the picker"}.bootstrap-datetimepicker-widget .btn[data-action=today]:after{content:"Set the date to today"}.bootstrap-datetimepicker-widget .picker-switch{text-align:center}.bootstrap-datetimepicker-widget .picker-switch:after{content:"Toggle Date and Time Screens"}.bootstrap-datetimepicker-widget .picker-switch td{padding:0;margin:0;height:auto;width:auto;line-height:inherit}.bootstrap-datetimepicker-widget .picker-switch td span{line-height:2.5;height:2.5em;width:100%}.bootstrap-datetimepicker-widget table{width:100%;margin:0}.bootstrap-datetimepicker-widget table td,.bootstrap-datetimepicker-widget table th{text-align:center;border-radius:3px}.bootstrap-datetimepicker-widget table th{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget table th.picker-switch{width:145px}.bootstrap-datetimepicker-widget table th.disabled,.bootstrap-datetimepicker-widget table th.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget table th.prev:after{content:"Previous Month"}.bootstrap-datetimepicker-widget table th.next:after{content:"Next Month"}.bootstrap-datetimepicker-widget table thead tr:first-child th{cursor:pointer}.bootstrap-datetimepicker-widget table thead tr:first-child th:hover{background:#eee}.bootstrap-datetimepicker-widget table td{height:54px;line-height:54px;width:54px}.bootstrap-datetimepicker-widget table td.cw{font-size:.8em;height:20px;line-height:20px;color:#777}.bootstrap-datetimepicker-widget table td.day{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget table td.day:hover,.bootstrap-datetimepicker-widget table td.hour:hover,.bootstrap-datetimepicker-widget table td.minute:hover,.bootstrap-datetimepicker-widget table td.second:hover{background:#eee;cursor:pointer}.bootstrap-datetimepicker-widget table td.new,.bootstrap-datetimepicker-widget table td.old{color:#777}.bootstrap-datetimepicker-widget table td.today{position:relative}.bootstrap-datetimepicker-widget table td.today:before{content:'';display:inline-block;border:7px solid transparent;border-bottom-color:#7ed321;border-top-color:rgba(0,0,0,.2);position:absolute;bottom:4px;right:4px}.bootstrap-datetimepicker-widget table td.active,.bootstrap-datetimepicker-widget table td.active:hover{background-color:#7ed321;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.bootstrap-datetimepicker-widget table td.active.today:before{border-bottom-color:#fff}.bootstrap-datetimepicker-widget table td.disabled,.bootstrap-datetimepicker-widget table td.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget table td span{display:inline-block;width:54px;height:54px;line-height:54px;margin:2px 1.5px;cursor:pointer;border-radius:3px}.bootstrap-datetimepicker-widget table td span:hover{background:#eee}.bootstrap-datetimepicker-widget table td span.active{background-color:#7ed321;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.bootstrap-datetimepicker-widget table td span.old{color:#777}.bootstrap-datetimepicker-widget table td span.disabled,.bootstrap-datetimepicker-widget table td span.disabled:hover{background:none;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget.usetwentyfour td.hour{height:27px;line-height:27px}.input-group.date .input-group-addon{cursor:pointer}.strengthify-wrapper>*{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);opacity:0;transition:all .5s ease-in-out}.strengthify-wrapper{position:relative}.strengthify-bg,.strengthify-container,.strengthify-separator,.strengthify-wrapper{height:8px}.strengthify-bg,.strengthify-container{display:block;position:absolute;width:100%}.strengthify-bg{background-color:#eee}.strengthify-separator{display:inline-block;position:absolute;background-color:#fff;width:2px;z-index:10}.password-bad{background-color:#ff6f6f}.password-medium{background-color:#f7ca18}.password-good{background-color:#7ed321}.sortable-chosen{border:1px solid #e8e8e8!important;background-color:#f0f3f4}body.status-page{padding-top:40px;font-family:Open Sans,Helvetica Neue,Helvetica,Arial,sans-serif;background-color:#f0f3f4;color:#333;font-size:1.4em;font-weight:400;-webkit-font-smoothing:antialiased}body.status-page.no-padding{padding-top:0!important}body.status-page hr{margin-top:10px;margin-bottom:10px}body.status-page h1,body.status-page h2,body.status-page h3,body.status-page h4,body.status-page h5{margin-bottom:20px}body.status-page img{box-sizing:border-box}body.status-page img.emoji{height:20px;width:20px;vertical-align:middle;max-width:none}body.status-page p,body.status-page strong{color:#333}body.status-page .tooltip .tooltip-inner{padding:8px 12px;font-size:14px;word-wrap:break-word}body.status-page .help-icon{cursor:help}body.status-page .text-component-1,body.status-page .text-success{color:#7ed321}body.status-page .text-component-2,body.status-page .text-info{color:#3498db}body.status-page .text-alert,body.status-page .text-component-3{color:#f7ca18}body.status-page .text-component-4,body.status-page .text-danger{color:#ff6f6f}body.status-page .container{max-width:960px}body.status-page .page-header{margin-top:10px}body.status-page .app-banner{margin-bottom:30px}body.status-page .about-app{margin-bottom:40px}body.status-page .about-app p{font-size:1.2em}body.status-page .alert{font-size:1.2em;font-weight:600}body.status-page .timeline .content-wrapper{margin-top:40px;margin-bottom:40px}body.status-page .timeline h3{margin-top:30px;margin-bottom:40px;font-size:22px}body.status-page .timeline h3 small{margin-left:15px}body.status-page .timeline .list-group.components .panel-body h1,body.status-page .timeline .panel .panel-body h1{margin-top:0;margin-bottom:4px;font-size:2em}body.status-page .timeline .list-group.components .panel-body h2,body.status-page .timeline .panel .panel-body h2{margin-top:0;margin-bottom:4px;font-size:1.8em}body.status-page .timeline .list-group.components .panel-body h3,body.status-page .timeline .panel .panel-body h3{margin-top:0;margin-bottom:4px;font-size:1.6em}body.status-page .timeline .list-group.components .panel-body h4,body.status-page .timeline .panel .panel-body h4{margin-top:0;margin-bottom:4px;font-size:1.4em}body.status-page .timeline .list-group.components .panel-body h5,body.status-page .timeline .panel .panel-body h5{margin-top:0;margin-bottom:4px;font-size:1.2em}body.status-page .timeline .list-group.components .panel-body p,body.status-page .timeline .panel .panel-body p{margin:0}body.status-page .timeline .moment{width:100%;padding-bottom:10px;position:relative}body.status-page .timeline .moment.first:before{top:-5px}body.status-page .timeline .moment:before{content:'';position:absolute;left:26px;top:-5px;width:2px;height:100%;background:#7266ba}body.status-page .timeline .moment .status-icon{background:#fff;width:35px;height:35px;border-radius:50%;border:1px solid #e8e8e8;position:absolute;left:25px;top:14px}body.status-page .timeline .moment .status-icon .icon{position:absolute;top:7px;left:11px}body.status-page .timeline .moment .status-icon .icon.ion-alert{left:15px}body.status-page .timeline .moment .status-icon.status-0{color:#b23f73}body.status-page .timeline .moment .status-icon.status-1{color:#f80}body.status-page .timeline .moment .status-icon.status-2{color:#f7ca18}body.status-page .timeline .moment .status-icon.status-3{color:#3498db}body.status-page .timeline .moment .status-icon.status-4{color:#7ed321}body.status-page .timeline .moment.last:before{background:#fff}body.status-page .timeline .moment .list-group.components,body.status-page .timeline .moment .panel{margin:0;border-radius:2px}body.status-page .timeline .moment .panel-message.list-group.components,body.status-page .timeline .moment .panel.panel-message{border:1px solid #e8e8e8}body.status-page .timeline .moment .panel-message.list-group.components .date,body.status-page .timeline .moment .panel.panel-message .date{color:#949494}body.status-page .timeline .moment .panel-message.list-group.components:before,body.status-page .timeline .moment .panel.panel-message:before{position:absolute;top:16px;left:1px;display:inline-block;border-top:15px solid transparent;border-left:0 solid #e8e8e8;border-right:15px solid #e8e8e8;border-bottom:15px solid transparent;content:" "}body.status-page .timeline .moment .panel-message.list-group.components:after,body.status-page .timeline .moment .panel.panel-message:after{position:absolute;top:17px;left:2px;display:inline-block;border-top:14px solid transparent;border-left:0 solid #fff;border-right:14px solid #fff;border-bottom:14px solid transparent;content:" "}body.status-page .timeline .moment .list-group.components .panel-heading strong,body.status-page .timeline .moment .panel .panel-heading strong{font-size:1.1em}body.status-page .timeline .moment .list-group.components .panel-body,body.status-page .timeline .moment .panel .panel-body{border-top:1px solid #eee}body.status-page .timeline .moment .list-group.components .panel-body p,body.status-page .timeline .moment .panel .panel-body p{font-size:1.1em}body.status-page .timeline .moment .list-group.components .panel-body p:not(:last-child),body.status-page .timeline .moment .panel .panel-body p:not(:last-child){margin-bottom:10px}@media (max-width:767px){body.status-page .timeline .moment .content{width:100%}}body.status-page .list-group{padding-left:0}body.status-page .list-group .list-group-item{border-radius:0;background-color:#fff;border:1px solid #e8e8e8;font-size:1.1em;padding:15px}body.status-page .list-group .list-group-item a{font-weight:400}body.status-page .list-group .list-group-item h4{margin:0;font-weight:400;max-width:90%}body.status-page .list-group .list-group-item p,body.status-page .list-group .list-group-item time{margin-bottom:0;line-height:1.3em}body.status-page .list-group .list-group-item.group-name{background-color:#e8e8e8;padding-top:.6em;padding-bottom:.6em;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body.status-page .list-group .list-group-item.break{padding:1px;background-color:#f0f3f4}body.status-page .list-group.components{border-color:#e8e8e8}body.status-page .list-group.components:last-child{margin-bottom:30px}body.status-page .list-group.components+.components{margin-top:5px}body.status-page .list-group.components p{margin-bottom:10px}body.status-page .list-group.components .badge{color:transparent}body.status-page .list-group.components a{color:#333!important}body.status-page footer{position:absolute;width:100%;bottom:0;height:60px;padding:30px 0 60px;border-top:1px solid #e8e8e8;color:#666;font-size:13px;line-height:30px;text-align:center;text-shadow:0 1px 0 hsla(0,0%,100%,.5)}body.status-page footer .btn{text-shadow:none}body.status-page footer .icons a.icon-link{display:inline-block;min-width:30px;height:30px;border-radius:3px;background-color:#666;text-align:center;color:#e8e8e8;transition:all .15s;padding:0 10px}body.status-page footer .icons a.icon-link.rss{background-color:#f80}body.status-page footer .icons a.icon-link:hover{text-decoration:none;background-color:#4d4d4d}body.status-page footer .list-inline>li{padding-right:0}@media (min-width:768px){body.status-page footer{text-align:left}body.status-page footer .list-inline{text-align:right}body.status-page footer .list-inline>li{padding-right:0}body.status-page footer .icons{margin-top:0;text-align:right}}body.status-page .section-components,body.status-page .section-metrics,body.status-page .section-scheduled,body.status-page .section-timeline{margin-top:40px}body.status-page .navbar-custom{padding-top:10px;padding-bottom:10px;width:100%;border-radius:0;margin-bottom:10px}body.status-page .navbar-custom a.navbar-brand{font-size:30px;font-weight:600}body.status-page .navbar-custom .navbar-nav li a{color:#333;font-size:1.7rem}body.status-page .navbar-custom .navbar-nav li a:hover{background-color:transparent}body.error-page{background-color:#f3f3f4}body.error-page .middle-box{height:400px;width:400px;position:absolute;top:50%;left:50%;margin-top:-250px;margin-left:-200px;z-index:100}body.error-page .middle-box h1{font-size:9em}body.error-page h3.font-bold{font-weight:600} \ No newline at end of file diff --git a/public/build/dist/js/all-41ed801435.js b/public/build/dist/js/all-41ed801435.js deleted file mode 100644 index d6ac5ecab38..00000000000 --- a/public/build/dist/js/all-41ed801435.js +++ /dev/null @@ -1,21 +0,0 @@ -function askConfirmation(e){swal({type:"warning",title:"Confirm your action",text:"Are you sure you want to do this?",confirmButtonText:"Yes",confirmButtonColor:"#FF6F6F",showCancelButton:!0},function(){e()})}if(function(e,t){"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){function n(e){var t=!!e&&"length"in e&&e.length,n=ae.type(e);return"function"!==n&&!ae.isWindow(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}function i(e,t,n){if(ae.isFunction(t))return ae.grep(e,function(e,i){return!!t.call(e,i,e)!==n});if(t.nodeType)return ae.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(me.test(t))return ae.filter(t,e,n);t=ae.filter(t,e)}return ae.grep(e,function(e){return K.call(t,e)>-1!==n})}function r(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}function a(e){var t={};return ae.each(e.match(Me)||[],function(e,n){t[n]=!0}),t}function o(){G.removeEventListener("DOMContentLoaded",o),e.removeEventListener("load",o),ae.ready()}function s(){this.expando=ae.expando+s.uid++}function l(e,t,n){var i;if(void 0===n&&1===e.nodeType)if(i="data-"+t.replace(Ye,"-$&").toLowerCase(),n=e.getAttribute(i),"string"==typeof n){try{n="true"===n||"false"!==n&&("null"===n?null:+n+""===n?+n:Te.test(n)?ae.parseJSON(n):n)}catch(r){}De.set(e,t,n)}else n=void 0;return n}function u(e,t,n,i){var r,a=1,o=20,s=i?function(){return i.cur()}:function(){return ae.css(e,t,"")},l=s(),u=n&&n[3]||(ae.cssNumber[t]?"":"px"),d=(ae.cssNumber[t]||"px"!==u&&+l)&&Ce.exec(ae.css(e,t));if(d&&d[3]!==u){u=u||d[3],n=n||[],d=+l||1;do a=a||".5",d/=a,ae.style(e,t,d+u);while(a!==(a=s()/l)&&1!==a&&--o)}return n&&(d=+d||+l||0,r=n[1]?d+(n[1]+1)*n[2]:+n[2],i&&(i.unit=u,i.start=d,i.end=r)),r}function d(e,t){var n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[];return void 0===t||t&&ae.nodeName(e,t)?ae.merge([e],n):n}function c(e,t){for(var n=0,i=e.length;n-1)r&&r.push(a);else if(u=ae.contains(a.ownerDocument,a),o=d(f.appendChild(a),"script"),u&&c(o),n)for(h=0;a=o[h++];)Ee.test(a.type||"")&&n.push(a);return f}function f(){return!0}function p(){return!1}function m(){try{return G.activeElement}catch(e){}}function _(e,t,n,i,r,a){var o,s;if("object"==typeof t){"string"!=typeof n&&(i=i||n,n=void 0);for(s in t)_(e,s,n,i,t[s],a);return e}if(null==i&&null==r?(r=n,i=n=void 0):null==r&&("string"==typeof n?(r=i,i=void 0):(r=i,i=n,n=void 0)),r===!1)r=p;else if(!r)return e;return 1===a&&(o=r,r=function(e){return ae().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=ae.guid++)),e.each(function(){ae.event.add(this,t,r,i,n)})}function g(e,t){return ae.nodeName(e,"table")&&ae.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function y(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function v(e){var t=$e.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function b(e,t){var n,i,r,a,o,s,l,u;if(1===t.nodeType){if(xe.hasData(e)&&(a=xe.access(e),o=xe.set(t,a),u=a.events)){delete o.handle,o.events={};for(r in u)for(n=0,i=u[r].length;n1&&"string"==typeof m&&!ie.checkClone&&Be.test(m))return e.each(function(r){var a=e.eq(r);_&&(t[0]=m.call(this,r,a.html())),w(a,t,n,i)});if(f&&(r=h(t,e[0].ownerDocument,!1,e,i),a=r.firstChild,1===r.childNodes.length&&(r=a),a||i)){for(o=ae.map(d(r,"script"),y),s=o.length;c")).appendTo(t.documentElement),t=qe[0].contentDocument,t.write(),t.close(),n=L(e,t),qe.detach()),Ue[e]=n),n}function D(e,t,n){var i,r,a,o,s=e.style;return n=n||Xe(e),o=n?n.getPropertyValue(t)||n[t]:void 0,""!==o&&void 0!==o||ae.contains(e.ownerDocument,e)||(o=ae.style(e,t)),n&&!ie.pixelMarginRight()&&Ge.test(o)&&Je.test(t)&&(i=s.width,r=s.minWidth,a=s.maxWidth,s.minWidth=s.maxWidth=s.width=o,o=n.width,s.width=i,s.minWidth=r,s.maxWidth=a),void 0!==o?o+"":o}function T(e,t){return{get:function(){return e()?void delete this.get:(this.get=t).apply(this,arguments)}}}function Y(e){if(e in it)return e;for(var t=e[0].toUpperCase()+e.slice(1),n=nt.length;n--;)if(e=nt[n]+t,e in it)return e}function S(e,t,n){var i=Ce.exec(t);return i?Math.max(0,i[2]-(n||0))+(i[3]||"px"):t}function C(e,t,n,i,r){for(var a=n===(i?"border":"content")?4:"width"===t?1:0,o=0;a<4;a+=2)"margin"===n&&(o+=ae.css(e,n+He[a],!0,r)),i?("content"===n&&(o-=ae.css(e,"padding"+He[a],!0,r)),"margin"!==n&&(o-=ae.css(e,"border"+He[a]+"Width",!0,r))):(o+=ae.css(e,"padding"+He[a],!0,r),"padding"!==n&&(o+=ae.css(e,"border"+He[a]+"Width",!0,r)));return o}function H(e,t,n){var i=!0,r="width"===t?e.offsetWidth:e.offsetHeight,a=Xe(e),o="border-box"===ae.css(e,"boxSizing",!1,a);if(r<=0||null==r){if(r=D(e,t,a),(r<0||null==r)&&(r=e.style[t]),Ge.test(r))return r;i=o&&(ie.boxSizingReliable()||r===e.style[t]),r=parseFloat(r)||0}return r+C(e,t,n||(o?"border":"content"),i,a)+"px"}function A(e,t){for(var n,i,r,a=[],o=0,s=e.length;o=0&&n=0},isPlainObject:function(e){var t;if("object"!==ae.type(e)||e.nodeType||ae.isWindow(e))return!1;if(e.constructor&&!ne.call(e,"constructor")&&!ne.call(e.constructor.prototype||{},"isPrototypeOf"))return!1;for(t in e);return void 0===t||ne.call(e,t)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?ee[te.call(e)]||"object":typeof e},globalEval:function(e){var t,n=eval;e=ae.trim(e),e&&(1===e.indexOf("use strict")?(t=G.createElement("script"),t.text=e,G.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(se,"ms-").replace(le,ue)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t){var i,r=0;if(n(e))for(i=e.length;rw.cacheLength&&delete e[t.shift()],e[n+" "]=i}var t=[];return e}function i(e){return e[W]=!0,e}function r(e){var t=A.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function a(e,t){for(var n=e.split("|"),i=n.length;i--;)w.attrHandle[n[i]]=t}function o(e,t){var n=t&&e,i=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||U)-(~e.sourceIndex||U);if(i)return i;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function l(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function u(e){return i(function(t){return t=+t,i(function(n,i){for(var r,a=e([],n.length,t),o=a.length;o--;)n[r=a[o]]&&(n[r]=!(i[r]=n[r]))})})}function d(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function c(){}function h(e){for(var t=0,n=e.length,i="";t1?function(t,n,i){for(var r=e.length;r--;)if(!e[r](t,n,i))return!1;return!0}:e[0]}function m(e,n,i){for(var r=0,a=n.length;r-1&&(i[u]=!(o[u]=c))}}else v=_(v===o?v.splice(p,v.length):v),a?a(null,o,v,l):Z.apply(o,v)})}function y(e){for(var t,n,i,r=e.length,a=w.relative[e[0].type],o=a||w.relative[" "],s=a?1:0,l=f(function(e){return e===t},o,!0),u=f(function(e){return ee(t,e)>-1},o,!0),d=[function(e,n,i){var r=!a&&(i||n!==Y)||((t=n).nodeType?l(e,n,i):u(e,n,i));return t=null,r}];s1&&p(d),s>1&&h(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(se,"$1"),n,s0,a=e.length>0,o=function(i,o,s,l,u){var d,c,h,f=0,p="0",m=i&&[],g=[],y=Y,v=i||a&&w.find.TAG("*",u),b=N+=null==y?1:Math.random()||.1,M=v.length;for(u&&(Y=o===A||o||u);p!==M&&null!=(d=v[p]);p++){if(a&&d){for(c=0,o||d.ownerDocument===A||(H(d),s=!P);h=e[c++];)if(h(d,o||A,s)){l.push(d);break}u&&(N=b)}r&&((d=!h&&d)&&f--,i&&m.push(d))}if(f+=p,r&&p!==f){for(c=0;h=n[c++];)h(m,g,o,s);if(i){if(f>0)for(;p--;)m[p]||g[p]||(g[p]=X.call(l));g=_(g)}Z.apply(l,g),u&&!i&&g.length>0&&f+n.length>1&&t.uniqueSort(l)}return u&&(N=b,Y=y),m};return r?i(o):o}var b,M,w,k,L,x,D,T,Y,S,C,H,A,j,P,E,I,F,O,W="sizzle"+1*new Date,R=e.document,N=0,z=0,B=n(),$=n(),V=n(),q=function(e,t){return e===t&&(C=!0),0},U=1<<31,J={}.hasOwnProperty,G=[],X=G.pop,Q=G.push,Z=G.push,K=G.slice,ee=function(e,t){for(var n=0,i=e.length;n+~]|"+ne+")"+ne+"*"),de=new RegExp("="+ne+"*([^\\]'\"]*?)"+ne+"*\\]","g"),ce=new RegExp(ae),he=new RegExp("^"+ie+"$"),fe={ID:new RegExp("^#("+ie+")"),CLASS:new RegExp("^\\.("+ie+")"),TAG:new RegExp("^("+ie+"|[*])"),ATTR:new RegExp("^"+re),PSEUDO:new RegExp("^"+ae),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ne+"*(even|odd|(([+-]|)(\\d*)n|)"+ne+"*(?:([+-]|)"+ne+"*(\\d+)|))"+ne+"*\\)|)","i"),bool:new RegExp("^(?:"+te+")$","i"),needsContext:new RegExp("^"+ne+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ne+"*((?:-\\d)?\\d*)"+ne+"*\\)|)(?=[^-]|$)","i")},pe=/^(?:input|select|textarea|button)$/i,me=/^h\d$/i,_e=/^[^{]+\{\s*\[native \w/,ge=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ye=/[+~]/,ve=/'|\\/g,be=new RegExp("\\\\([\\da-f]{1,6}"+ne+"?|("+ne+")|.)","ig"),Me=function(e,t,n){var i="0x"+t-65536;return i!==i||n?t:i<0?String.fromCharCode(i+65536):String.fromCharCode(i>>10|55296,1023&i|56320)},we=function(){H()};try{Z.apply(G=K.call(R.childNodes),R.childNodes),G[R.childNodes.length].nodeType}catch(ke){Z={apply:G.length?function(e,t){Q.apply(e,K.call(t))}:function(e,t){for(var n=e.length,i=0;e[n++]=t[i++];);e.length=n-1}}}M=t.support={},L=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},H=t.setDocument=function(e){var t,n,i=e?e.ownerDocument||e:R;return i!==A&&9===i.nodeType&&i.documentElement?(A=i,j=A.documentElement,P=!L(A),(n=A.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",we,!1):n.attachEvent&&n.attachEvent("onunload",we)),M.attributes=r(function(e){return e.className="i",!e.getAttribute("className")}),M.getElementsByTagName=r(function(e){return e.appendChild(A.createComment("")),!e.getElementsByTagName("*").length}),M.getElementsByClassName=_e.test(A.getElementsByClassName),M.getById=r(function(e){return j.appendChild(e).id=W,!A.getElementsByName||!A.getElementsByName(W).length}),M.getById?(w.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&P){var n=t.getElementById(e);return n?[n]:[]}},w.filter.ID=function(e){var t=e.replace(be,Me);return function(e){return e.getAttribute("id")===t}}):(delete w.find.ID,w.filter.ID=function(e){var t=e.replace(be,Me);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}}),w.find.TAG=M.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):M.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,i=[],r=0,a=t.getElementsByTagName(e);if("*"===e){for(;n=a[r++];)1===n.nodeType&&i.push(n);return i}return a},w.find.CLASS=M.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&P)return t.getElementsByClassName(e)},I=[],E=[],(M.qsa=_e.test(A.querySelectorAll))&&(r(function(e){j.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&E.push("[*^$]="+ne+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||E.push("\\["+ne+"*(?:value|"+te+")"),e.querySelectorAll("[id~="+W+"-]").length||E.push("~="),e.querySelectorAll(":checked").length||E.push(":checked"),e.querySelectorAll("a#"+W+"+*").length||E.push(".#.+[+~]")}),r(function(e){var t=A.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&E.push("name"+ne+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||E.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),E.push(",.*:")})),(M.matchesSelector=_e.test(F=j.matches||j.webkitMatchesSelector||j.mozMatchesSelector||j.oMatchesSelector||j.msMatchesSelector))&&r(function(e){M.disconnectedMatch=F.call(e,"div"),F.call(e,"[s!='']:x"),I.push("!=",ae)}),E=E.length&&new RegExp(E.join("|")),I=I.length&&new RegExp(I.join("|")),t=_e.test(j.compareDocumentPosition),O=t||_e.test(j.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,i=t&&t.parentNode;return e===i||!(!i||1!==i.nodeType||!(n.contains?n.contains(i):e.compareDocumentPosition&&16&e.compareDocumentPosition(i)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},q=t?function(e,t){if(e===t)return C=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n?n:(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!M.sortDetached&&t.compareDocumentPosition(e)===n?e===A||e.ownerDocument===R&&O(R,e)?-1:t===A||t.ownerDocument===R&&O(R,t)?1:S?ee(S,e)-ee(S,t):0:4&n?-1:1)}:function(e,t){if(e===t)return C=!0,0;var n,i=0,r=e.parentNode,a=t.parentNode,s=[e],l=[t];if(!r||!a)return e===A?-1:t===A?1:r?-1:a?1:S?ee(S,e)-ee(S,t):0;if(r===a)return o(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)l.unshift(n);for(;s[i]===l[i];)i++;return i?o(s[i],l[i]):s[i]===R?-1:l[i]===R?1:0},A):A},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==A&&H(e),n=n.replace(de,"='$1']"),M.matchesSelector&&P&&!V[n+" "]&&(!I||!I.test(n))&&(!E||!E.test(n)))try{var i=F.call(e,n);if(i||M.disconnectedMatch||e.document&&11!==e.document.nodeType)return i}catch(r){}return t(n,A,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==A&&H(e),O(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==A&&H(e);var n=w.attrHandle[t.toLowerCase()],i=n&&J.call(w.attrHandle,t.toLowerCase())?n(e,t,!P):void 0;return void 0!==i?i:M.attributes||!P?e.getAttribute(t):(i=e.getAttributeNode(t))&&i.specified?i.value:null},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],i=0,r=0;if(C=!M.detectDuplicates,S=!M.sortStable&&e.slice(0),e.sort(q),C){for(;t=e[r++];)t===e[r]&&(i=n.push(r));for(;i--;)e.splice(n[i],1)}return S=null,e},k=t.getText=function(e){var t,n="",i=0,r=e.nodeType;if(r){if(1===r||9===r||11===r){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=k(e)}else if(3===r||4===r)return e.nodeValue}else for(;t=e[i++];)n+=k(t);return n},w=t.selectors={cacheLength:50,createPseudo:i,match:fe,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(be,Me),e[3]=(e[3]||e[4]||e[5]||"").replace(be,Me),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||t.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return fe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&ce.test(n)&&(t=x(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(be,Me).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=B[e+" "];return t||(t=new RegExp("(^|"+ne+")"+e+"("+ne+"|$)"))&&B(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,n,i){return function(r){var a=t.attr(r,e);return null==a?"!="===n:!n||(a+="","="===n?a===i:"!="===n?a!==i:"^="===n?i&&0===a.indexOf(i):"*="===n?i&&a.indexOf(i)>-1:"$="===n?i&&a.slice(-i.length)===i:"~="===n?(" "+a.replace(oe," ")+" ").indexOf(i)>-1:"|="===n&&(a===i||a.slice(0,i.length+1)===i+"-"))}},CHILD:function(e,t,n,i,r){var a="nth"!==e.slice(0,3),o="last"!==e.slice(-4),s="of-type"===t;return 1===i&&0===r?function(e){return!!e.parentNode}:function(t,n,l){var u,d,c,h,f,p,m=a!==o?"nextSibling":"previousSibling",_=t.parentNode,g=s&&t.nodeName.toLowerCase(),y=!l&&!s,v=!1;if(_){if(a){for(;m;){for(h=t;h=h[m];)if(s?h.nodeName.toLowerCase()===g:1===h.nodeType)return!1;p=m="only"===e&&!p&&"nextSibling"}return!0}if(p=[o?_.firstChild:_.lastChild],o&&y){for(h=_,c=h[W]||(h[W]={}),d=c[h.uniqueID]||(c[h.uniqueID]={}),u=d[e]||[],f=u[0]===N&&u[1],v=f&&u[2],h=f&&_.childNodes[f];h=++f&&h&&h[m]||(v=f=0)||p.pop();)if(1===h.nodeType&&++v&&h===t){d[e]=[N,f,v];break}}else if(y&&(h=t,c=h[W]||(h[W]={}),d=c[h.uniqueID]||(c[h.uniqueID]={}),u=d[e]||[],f=u[0]===N&&u[1],v=f),v===!1)for(;(h=++f&&h&&h[m]||(v=f=0)||p.pop())&&((s?h.nodeName.toLowerCase()!==g:1!==h.nodeType)||!++v||(y&&(c=h[W]||(h[W]={}),d=c[h.uniqueID]||(c[h.uniqueID]={}),d[e]=[N,v]),h!==t)););return v-=r,v===i||v%i===0&&v/i>=0}}},PSEUDO:function(e,n){var r,a=w.pseudos[e]||w.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return a[W]?a(n):a.length>1?(r=[e,e,"",n],w.setFilters.hasOwnProperty(e.toLowerCase())?i(function(e,t){for(var i,r=a(e,n),o=r.length;o--;)i=ee(e,r[o]),e[i]=!(t[i]=r[o])}):function(e){return a(e,0,r)}):a}},pseudos:{not:i(function(e){var t=[],n=[],r=D(e.replace(se,"$1"));return r[W]?i(function(e,t,n,i){for(var a,o=r(e,null,i,[]),s=e.length;s--;)(a=o[s])&&(e[s]=!(t[s]=a))}):function(e,i,a){return t[0]=e,r(t,null,a,n),t[0]=null,!n.pop()}}),has:i(function(e){return function(n){return t(e,n).length>0}}),contains:i(function(e){return e=e.replace(be,Me),function(t){return(t.textContent||t.innerText||k(t)).indexOf(e)>-1}}),lang:i(function(e){return he.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(be,Me).toLowerCase(),function(t){var n;do if(n=P?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===j},focus:function(e){return e===A.activeElement&&(!A.hasFocus||A.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!w.pseudos.empty(e)},header:function(e){return me.test(e.nodeName)},input:function(e){return pe.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase()); -},first:u(function(){return[0]}),last:u(function(e,t){return[t-1]}),eq:u(function(e,t,n){return[n<0?n+t:n]}),even:u(function(e,t){for(var n=0;n=0;)e.push(i);return e}),gt:u(function(e,t,n){for(var i=n<0?n+t:n;++i2&&"ID"===(o=a[0]).type&&M.getById&&9===t.nodeType&&P&&w.relative[a[1].type]){if(t=(w.find.ID(o.matches[0].replace(be,Me),t)||[])[0],!t)return n;u&&(t=t.parentNode),e=e.slice(a.shift().value.length)}for(r=fe.needsContext.test(e)?0:a.length;r--&&(o=a[r],!w.relative[s=o.type]);)if((l=w.find[s])&&(i=l(o.matches[0].replace(be,Me),ye.test(a[0].type)&&d(t.parentNode)||t))){if(a.splice(r,1),e=i.length&&h(a),!e)return Z.apply(n,i),n;break}}return(u||D(e,c))(i,t,!P,n,!t||ye.test(e)&&d(t.parentNode)||t),n},M.sortStable=W.split("").sort(q).join("")===W,M.detectDuplicates=!!C,H(),M.sortDetached=r(function(e){return 1&e.compareDocumentPosition(A.createElement("div"))}),r(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||a("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),M.attributes&&r(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||a("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),r(function(e){return null==e.getAttribute("disabled")})||a(te,function(e,t,n){var i;if(!n)return e[t]===!0?t.toLowerCase():(i=e.getAttributeNode(t))&&i.specified?i.value:null}),t}(e);ae.find=de,ae.expr=de.selectors,ae.expr[":"]=ae.expr.pseudos,ae.uniqueSort=ae.unique=de.uniqueSort,ae.text=de.getText,ae.isXMLDoc=de.isXML,ae.contains=de.contains;var ce=function(e,t,n){for(var i=[],r=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(r&&ae(e).is(n))break;i.push(e)}return i},he=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},fe=ae.expr.match.needsContext,pe=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,me=/^.[^:#\[\.,]*$/;ae.filter=function(e,t,n){var i=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===i.nodeType?ae.find.matchesSelector(i,e)?[i]:[]:ae.find.matches(e,ae.grep(t,function(e){return 1===e.nodeType}))},ae.fn.extend({find:function(e){var t,n=this.length,i=[],r=this;if("string"!=typeof e)return this.pushStack(ae(e).filter(function(){for(t=0;t1?ae.unique(i):i),i.selector=this.selector?this.selector+" "+e:e,i},filter:function(e){return this.pushStack(i(this,e||[],!1))},not:function(e){return this.pushStack(i(this,e||[],!0))},is:function(e){return!!i(this,"string"==typeof e&&fe.test(e)?ae(e):e||[],!1).length}});var _e,ge=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,ye=ae.fn.init=function(e,t,n){var i,r;if(!e)return this;if(n=n||_e,"string"==typeof e){if(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:ge.exec(e),!i||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof ae?t[0]:t,ae.merge(this,ae.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:G,!0)),pe.test(i[1])&&ae.isPlainObject(t))for(i in t)ae.isFunction(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return r=G.getElementById(i[2]),r&&r.parentNode&&(this.length=1,this[0]=r),this.context=G,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):ae.isFunction(e)?void 0!==n.ready?n.ready(e):e(ae):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),ae.makeArray(e,this))};ye.prototype=ae.fn,_e=ae(G);var ve=/^(?:parents|prev(?:Until|All))/,be={children:!0,contents:!0,next:!0,prev:!0};ae.fn.extend({has:function(e){var t=ae(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&ae.find.matchesSelector(n,e))){a.push(n);break}return this.pushStack(a.length>1?ae.uniqueSort(a):a)},index:function(e){return e?"string"==typeof e?K.call(ae(e),this[0]):K.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(ae.uniqueSort(ae.merge(this.get(),ae(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),ae.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return ce(e,"parentNode")},parentsUntil:function(e,t,n){return ce(e,"parentNode",n)},next:function(e){return r(e,"nextSibling")},prev:function(e){return r(e,"previousSibling")},nextAll:function(e){return ce(e,"nextSibling")},prevAll:function(e){return ce(e,"previousSibling")},nextUntil:function(e,t,n){return ce(e,"nextSibling",n)},prevUntil:function(e,t,n){return ce(e,"previousSibling",n)},siblings:function(e){return he((e.parentNode||{}).firstChild,e)},children:function(e){return he(e.firstChild)},contents:function(e){return e.contentDocument||ae.merge([],e.childNodes)}},function(e,t){ae.fn[e]=function(n,i){var r=ae.map(this,t,n);return"Until"!==e.slice(-5)&&(i=n),i&&"string"==typeof i&&(r=ae.filter(i,r)),this.length>1&&(be[e]||ae.uniqueSort(r),ve.test(e)&&r.reverse()),this.pushStack(r)}});var Me=/\S+/g;ae.Callbacks=function(e){e="string"==typeof e?a(e):ae.extend({},e);var t,n,i,r,o=[],s=[],l=-1,u=function(){for(r=e.once,i=t=!0;s.length;l=-1)for(n=s.shift();++l-1;)o.splice(n,1),n<=l&&l--}),this},has:function(e){return e?ae.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return r=s=[],o=n="",this},disabled:function(){return!o},lock:function(){return r=s=[],n||(o=n=""),this},locked:function(){return!!r},fireWith:function(e,n){return r||(n=n||[],n=[e,n.slice?n.slice():n],s.push(n),t||u()),this},fire:function(){return d.fireWith(this,arguments),this},fired:function(){return!!i}};return d},ae.extend({Deferred:function(e){var t=[["resolve","done",ae.Callbacks("once memory"),"resolved"],["reject","fail",ae.Callbacks("once memory"),"rejected"],["notify","progress",ae.Callbacks("memory")]],n="pending",i={state:function(){return n},always:function(){return r.done(arguments).fail(arguments),this},then:function(){var e=arguments;return ae.Deferred(function(n){ae.each(t,function(t,a){var o=ae.isFunction(e[t])&&e[t];r[a[1]](function(){var e=o&&o.apply(this,arguments);e&&ae.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[a[0]+"With"](this===i?n.promise():this,o?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?ae.extend(e,i):i}},r={};return i.pipe=i.then,ae.each(t,function(e,a){var o=a[2],s=a[3];i[a[1]]=o.add,s&&o.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),r[a[0]]=function(){return r[a[0]+"With"](this===r?i:this,arguments),this},r[a[0]+"With"]=o.fireWith}),i.promise(r),e&&e.call(r,r),r},when:function(e){var t,n,i,r=0,a=X.call(arguments),o=a.length,s=1!==o||e&&ae.isFunction(e.promise)?o:0,l=1===s?e:ae.Deferred(),u=function(e,n,i){return function(r){n[e]=this,i[e]=arguments.length>1?X.call(arguments):r,i===t?l.notifyWith(n,i):--s||l.resolveWith(n,i)}};if(o>1)for(t=new Array(o),n=new Array(o),i=new Array(o);r0||(we.resolveWith(G,[ae]),ae.fn.triggerHandler&&(ae(G).triggerHandler("ready"),ae(G).off("ready"))))}}),ae.ready.promise=function(t){return we||(we=ae.Deferred(),"complete"===G.readyState||"loading"!==G.readyState&&!G.documentElement.doScroll?e.setTimeout(ae.ready):(G.addEventListener("DOMContentLoaded",o),e.addEventListener("load",o))),we.promise(t)},ae.ready.promise();var ke=function(e,t,n,i,r,a,o){var s=0,l=e.length,u=null==n;if("object"===ae.type(n)){r=!0;for(s in n)ke(e,t,s,n[s],!0,a,o)}else if(void 0!==i&&(r=!0,ae.isFunction(i)||(o=!0),u&&(o?(t.call(e,i),t=null):(u=t,t=function(e,t,n){return u.call(ae(e),n)})),t))for(;s-1&&void 0!==n&&De.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){De.remove(this,e)})}}),ae.extend({queue:function(e,t,n){var i;if(e)return t=(t||"fx")+"queue",i=xe.get(e,t),n&&(!i||ae.isArray(n)?i=xe.access(e,t,ae.makeArray(n)):i.push(n)),i||[]},dequeue:function(e,t){t=t||"fx";var n=ae.queue(e,t),i=n.length,r=n.shift(),a=ae._queueHooks(e,t),o=function(){ae.dequeue(e,t)};"inprogress"===r&&(r=n.shift(),i--),r&&("fx"===t&&n.unshift("inprogress"),delete a.stop,r.call(e,o,a)),!i&&a&&a.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return xe.get(e,n)||xe.access(e,n,{empty:ae.Callbacks("once memory").add(function(){xe.remove(e,[t+"queue",n])})})}}),ae.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length",""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};Ie.optgroup=Ie.option,Ie.tbody=Ie.tfoot=Ie.colgroup=Ie.caption=Ie.thead,Ie.th=Ie.td;var Fe=/<|&#?\w+;/;!function(){var e=G.createDocumentFragment(),t=e.appendChild(G.createElement("div")),n=G.createElement("input");n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),t.appendChild(n),ie.checkClone=t.cloneNode(!0).cloneNode(!0).lastChild.checked,t.innerHTML="",ie.noCloneChecked=!!t.cloneNode(!0).lastChild.defaultValue}();var Oe=/^key/,We=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Re=/^([^.]*)(?:\.(.+)|)/;ae.event={global:{},add:function(e,t,n,i,r){var a,o,s,l,u,d,c,h,f,p,m,_=xe.get(e);if(_)for(n.handler&&(a=n,n=a.handler,r=a.selector),n.guid||(n.guid=ae.guid++),(l=_.events)||(l=_.events={}),(o=_.handle)||(o=_.handle=function(t){return"undefined"!=typeof ae&&ae.event.triggered!==t.type?ae.event.dispatch.apply(e,arguments):void 0}),t=(t||"").match(Me)||[""],u=t.length;u--;)s=Re.exec(t[u])||[],f=m=s[1],p=(s[2]||"").split(".").sort(),f&&(c=ae.event.special[f]||{},f=(r?c.delegateType:c.bindType)||f,c=ae.event.special[f]||{},d=ae.extend({type:f,origType:m,data:i,handler:n,guid:n.guid,selector:r,needsContext:r&&ae.expr.match.needsContext.test(r),namespace:p.join(".")},a),(h=l[f])||(h=l[f]=[],h.delegateCount=0,c.setup&&c.setup.call(e,i,p,o)!==!1||e.addEventListener&&e.addEventListener(f,o)),c.add&&(c.add.call(e,d),d.handler.guid||(d.handler.guid=n.guid)),r?h.splice(h.delegateCount++,0,d):h.push(d),ae.event.global[f]=!0)},remove:function(e,t,n,i,r){var a,o,s,l,u,d,c,h,f,p,m,_=xe.hasData(e)&&xe.get(e);if(_&&(l=_.events)){for(t=(t||"").match(Me)||[""],u=t.length;u--;)if(s=Re.exec(t[u])||[],f=m=s[1],p=(s[2]||"").split(".").sort(),f){for(c=ae.event.special[f]||{},f=(i?c.delegateType:c.bindType)||f,h=l[f]||[],s=s[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),o=a=h.length;a--;)d=h[a],!r&&m!==d.origType||n&&n.guid!==d.guid||s&&!s.test(d.namespace)||i&&i!==d.selector&&("**"!==i||!d.selector)||(h.splice(a,1),d.selector&&h.delegateCount--,c.remove&&c.remove.call(e,d));o&&!h.length&&(c.teardown&&c.teardown.call(e,p,_.handle)!==!1||ae.removeEvent(e,f,_.handle),delete l[f])}else for(f in l)ae.event.remove(e,f+t[u],n,i,!0);ae.isEmptyObject(l)&&xe.remove(e,"handle events")}},dispatch:function(e){e=ae.event.fix(e);var t,n,i,r,a,o=[],s=X.call(arguments),l=(xe.get(this,"events")||{})[e.type]||[],u=ae.event.special[e.type]||{};if(s[0]=e,e.delegateTarget=this,!u.preDispatch||u.preDispatch.call(this,e)!==!1){for(o=ae.event.handlers.call(this,e,l),t=0;(r=o[t++])&&!e.isPropagationStopped();)for(e.currentTarget=r.elem,n=0;(a=r.handlers[n++])&&!e.isImmediatePropagationStopped();)e.rnamespace&&!e.rnamespace.test(a.namespace)||(e.handleObj=a,e.data=a.data,i=((ae.event.special[a.origType]||{}).handle||a.handler).apply(r.elem,s),void 0!==i&&(e.result=i)===!1&&(e.preventDefault(),e.stopPropagation()));return u.postDispatch&&u.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,i,r,a,o=[],s=t.delegateCount,l=e.target;if(s&&l.nodeType&&("click"!==e.type||isNaN(e.button)||e.button<1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&(l.disabled!==!0||"click"!==e.type)){for(i=[],n=0;n-1:ae.find(r,this,null,[l]).length),i[r]&&i.push(a);i.length&&o.push({elem:l,handlers:i})}return s]*)\/>/gi,ze=/\s*$/g;ae.extend({htmlPrefilter:function(e){return e.replace(Ne,"<$1>")},clone:function(e,t,n){var i,r,a,o,s=e.cloneNode(!0),l=ae.contains(e.ownerDocument,e);if(!(ie.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||ae.isXMLDoc(e)))for(o=d(s),a=d(e),i=0,r=a.length;i0&&c(o,!l&&d(e,"script")),s},cleanData:function(e){for(var t,n,i,r=ae.event.special,a=0;void 0!==(n=e[a]);a++)if(Le(n)){if(t=n[xe.expando]){if(t.events)for(i in t.events)r[i]?ae.event.remove(n,i):ae.removeEvent(n,i,t.handle);n[xe.expando]=void 0}n[De.expando]&&(n[De.expando]=void 0)}}}),ae.fn.extend({domManip:w,detach:function(e){return k(this,e,!0)},remove:function(e){return k(this,e)},text:function(e){return ke(this,function(e){return void 0===e?ae.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return w(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=g(this,e);t.appendChild(e)}})},prepend:function(){return w(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=g(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return w(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return w(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(ae.cleanData(d(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return ae.clone(this,e,t)})},html:function(e){return ke(this,function(e){var t=this[0]||{},n=0,i=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!ze.test(e)&&!Ie[(Pe.exec(e)||["",""])[1].toLowerCase()]){e=ae.htmlPrefilter(e);try{for(;n1)},show:function(){return A(this,!0)},hide:function(){return A(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Ae(this)?ae(this).show():ae(this).hide()})}}),ae.Tween=j,j.prototype={constructor:j,init:function(e,t,n,i,r,a){this.elem=e,this.prop=n,this.easing=r||ae.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=i,this.unit=a||(ae.cssNumber[n]?"":"px")},cur:function(){var e=j.propHooks[this.prop];return e&&e.get?e.get(this):j.propHooks._default.get(this)},run:function(e){var t,n=j.propHooks[this.prop];return this.options.duration?this.pos=t=ae.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):j.propHooks._default.set(this),this}},j.prototype.init.prototype=j.prototype,j.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=ae.css(e.elem,e.prop,""),t&&"auto"!==t?t:0)},set:function(e){ae.fx.step[e.prop]?ae.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[ae.cssProps[e.prop]]&&!ae.cssHooks[e.prop]?e.elem[e.prop]=e.now:ae.style(e.elem,e.prop,e.now+e.unit)}}},j.propHooks.scrollTop=j.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},ae.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},ae.fx=j.prototype.init,ae.fx.step={};var rt,at,ot=/^(?:toggle|show|hide)$/,st=/queueHooks$/;ae.Animation=ae.extend(W,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return u(n.elem,e,Ce.exec(t),n),n}]},tweener:function(e,t){ae.isFunction(e)?(t=e,e=["*"]):e=e.match(Me);for(var n,i=0,r=e.length;i1)},removeAttr:function(e){return this.each(function(){ae.removeAttr(this,e)})}}),ae.extend({attr:function(e,t,n){var i,r,a=e.nodeType;if(3!==a&&8!==a&&2!==a)return"undefined"==typeof e.getAttribute?ae.prop(e,t,n):(1===a&&ae.isXMLDoc(e)||(t=t.toLowerCase(),r=ae.attrHooks[t]||(ae.expr.match.bool.test(t)?lt:void 0)),void 0!==n?null===n?void ae.removeAttr(e,t):r&&"set"in r&&void 0!==(i=r.set(e,n,t))?i:(e.setAttribute(t,n+""),n):r&&"get"in r&&null!==(i=r.get(e,t))?i:(i=ae.find.attr(e,t),null==i?void 0:i))},attrHooks:{type:{set:function(e,t){if(!ie.radioValue&&"radio"===t&&ae.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,i,r=0,a=t&&t.match(Me);if(a&&1===e.nodeType)for(;n=a[r++];)i=ae.propFix[n]||n,ae.expr.match.bool.test(n)&&(e[i]=!1),e.removeAttribute(n)}}),lt={set:function(e,t,n){return t===!1?ae.removeAttr(e,n):e.setAttribute(n,n),n}},ae.each(ae.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ut[t]||ae.find.attr;ut[t]=function(e,t,i){var r,a;return i||(a=ut[t],ut[t]=r,r=null!=n(e,t,i)?t.toLowerCase():null,ut[t]=a),r}});var dt=/^(?:input|select|textarea|button)$/i,ct=/^(?:a|area)$/i;ae.fn.extend({prop:function(e,t){return ke(this,ae.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[ae.propFix[e]||e]})}}),ae.extend({prop:function(e,t,n){var i,r,a=e.nodeType;if(3!==a&&8!==a&&2!==a)return 1===a&&ae.isXMLDoc(e)||(t=ae.propFix[t]||t,r=ae.propHooks[t]),void 0!==n?r&&"set"in r&&void 0!==(i=r.set(e,n,t))?i:e[t]=n:r&&"get"in r&&null!==(i=r.get(e,t))?i:e[t]},propHooks:{tabIndex:{get:function(e){var t=ae.find.attr(e,"tabindex");return t?parseInt(t,10):dt.test(e.nodeName)||ct.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),ie.optSelected||(ae.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),ae.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){ae.propFix[this.toLowerCase()]=this});var ht=/[\t\r\n\f]/g;ae.fn.extend({addClass:function(e){var t,n,i,r,a,o,s,l=0;if(ae.isFunction(e))return this.each(function(t){ae(this).addClass(e.call(this,t,R(this)))});if("string"==typeof e&&e)for(t=e.match(Me)||[];n=this[l++];)if(r=R(n),i=1===n.nodeType&&(" "+r+" ").replace(ht," ")){for(o=0;a=t[o++];)i.indexOf(" "+a+" ")<0&&(i+=a+" ");s=ae.trim(i),r!==s&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,i,r,a,o,s,l=0;if(ae.isFunction(e))return this.each(function(t){ae(this).removeClass(e.call(this,t,R(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof e&&e)for(t=e.match(Me)||[];n=this[l++];)if(r=R(n),i=1===n.nodeType&&(" "+r+" ").replace(ht," ")){for(o=0;a=t[o++];)for(;i.indexOf(" "+a+" ")>-1;)i=i.replace(" "+a+" "," ");s=ae.trim(i),r!==s&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):ae.isFunction(e)?this.each(function(n){ae(this).toggleClass(e.call(this,n,R(this),t),t)}):this.each(function(){var t,i,r,a;if("string"===n)for(i=0,r=ae(this),a=e.match(Me)||[];t=a[i++];)r.hasClass(t)?r.removeClass(t):r.addClass(t);else void 0!==e&&"boolean"!==n||(t=R(this),t&&xe.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||e===!1?"":xe.get(this,"__className__")||""))})},hasClass:function(e){var t,n,i=0;for(t=" "+e+" ";n=this[i++];)if(1===n.nodeType&&(" "+R(n)+" ").replace(ht," ").indexOf(t)>-1)return!0;return!1}});var ft=/\r/g,pt=/[\x20\t\r\n\f]+/g;ae.fn.extend({val:function(e){var t,n,i,r=this[0];{if(arguments.length)return i=ae.isFunction(e),this.each(function(n){var r;1===this.nodeType&&(r=i?e.call(this,n,ae(this).val()):e,null==r?r="":"number"==typeof r?r+="":ae.isArray(r)&&(r=ae.map(r,function(e){return null==e?"":e+""})),t=ae.valHooks[this.type]||ae.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&void 0!==t.set(this,r,"value")||(this.value=r))});if(r)return t=ae.valHooks[r.type]||ae.valHooks[r.nodeName.toLowerCase()],t&&"get"in t&&void 0!==(n=t.get(r,"value"))?n:(n=r.value,"string"==typeof n?n.replace(ft,""):null==n?"":n)}}}),ae.extend({valHooks:{option:{get:function(e){var t=ae.find.attr(e,"value");return null!=t?t:ae.trim(ae.text(e)).replace(pt," ")}},select:{get:function(e){for(var t,n,i=e.options,r=e.selectedIndex,a="select-one"===e.type||r<0,o=a?null:[],s=a?r+1:i.length,l=r<0?s:a?r:0;l-1)&&(n=!0);return n||(e.selectedIndex=-1),a}}}}),ae.each(["radio","checkbox"],function(){ae.valHooks[this]={set:function(e,t){if(ae.isArray(t))return e.checked=ae.inArray(ae(e).val(),t)>-1}},ie.checkOn||(ae.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var mt=/^(?:focusinfocus|focusoutblur)$/;ae.extend(ae.event,{trigger:function(t,n,i,r){var a,o,s,l,u,d,c,h=[i||G],f=ne.call(t,"type")?t.type:t,p=ne.call(t,"namespace")?t.namespace.split("."):[];if(o=s=i=i||G,3!==i.nodeType&&8!==i.nodeType&&!mt.test(f+ae.event.triggered)&&(f.indexOf(".")>-1&&(p=f.split("."),f=p.shift(),p.sort()),u=f.indexOf(":")<0&&"on"+f,t=t[ae.expando]?t:new ae.Event(f,"object"==typeof t&&t),t.isTrigger=r?2:3,t.namespace=p.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:ae.makeArray(n,[t]),c=ae.event.special[f]||{},r||!c.trigger||c.trigger.apply(i,n)!==!1)){if(!r&&!c.noBubble&&!ae.isWindow(i)){for(l=c.delegateType||f,mt.test(l+f)||(o=o.parentNode);o;o=o.parentNode)h.push(o),s=o;s===(i.ownerDocument||G)&&h.push(s.defaultView||s.parentWindow||e)}for(a=0;(o=h[a++])&&!t.isPropagationStopped();)t.type=a>1?l:c.bindType||f,d=(xe.get(o,"events")||{})[t.type]&&xe.get(o,"handle"),d&&d.apply(o,n),d=u&&o[u],d&&d.apply&&Le(o)&&(t.result=d.apply(o,n),t.result===!1&&t.preventDefault());return t.type=f,r||t.isDefaultPrevented()||c._default&&c._default.apply(h.pop(),n)!==!1||!Le(i)||u&&ae.isFunction(i[f])&&!ae.isWindow(i)&&(s=i[u],s&&(i[u]=null),ae.event.triggered=f,i[f](),ae.event.triggered=void 0,s&&(i[u]=s)),t.result}},simulate:function(e,t,n){var i=ae.extend(new ae.Event,n,{type:e,isSimulated:!0});ae.event.trigger(i,null,t)}}),ae.fn.extend({trigger:function(e,t){return this.each(function(){ae.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return ae.event.trigger(e,t,n,!0)}}),ae.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){ae.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),ae.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),ie.focusin="onfocusin"in e,ie.focusin||ae.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){ae.event.simulate(t,e.target,ae.event.fix(e))};ae.event.special[t]={setup:function(){var i=this.ownerDocument||this,r=xe.access(i,t);r||i.addEventListener(e,n,!0),xe.access(i,t,(r||0)+1)},teardown:function(){var i=this.ownerDocument||this,r=xe.access(i,t)-1;r?xe.access(i,t,r):(i.removeEventListener(e,n,!0),xe.remove(i,t))}}});var _t=e.location,gt=ae.now(),yt=/\?/;ae.parseJSON=function(e){return JSON.parse(e+"")},ae.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(i){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||ae.error("Invalid XML: "+t),n};var vt=/#.*$/,bt=/([?&])_=[^&]*/,Mt=/^(.*?):[ \t]*([^\r\n]*)$/gm,wt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,kt=/^(?:GET|HEAD)$/,Lt=/^\/\//,xt={},Dt={},Tt="*/".concat("*"),Yt=G.createElement("a");Yt.href=_t.href,ae.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:_t.href,type:"GET",isLocal:wt.test(_t.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Tt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":ae.parseJSON,"text xml":ae.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?B(B(e,ae.ajaxSettings),t):B(ae.ajaxSettings,e)},ajaxPrefilter:N(xt),ajaxTransport:N(Dt),ajax:function(t,n){function i(t,n,i,s){var u,c,y,v,M,k=n;2!==b&&(b=2,l&&e.clearTimeout(l),r=void 0,o=s||"",w.readyState=t>0?4:0,u=t>=200&&t<300||304===t,i&&(v=$(h,w,i)),v=V(h,v,w,u),u?(h.ifModified&&(M=w.getResponseHeader("Last-Modified"),M&&(ae.lastModified[a]=M),M=w.getResponseHeader("etag"),M&&(ae.etag[a]=M)),204===t||"HEAD"===h.type?k="nocontent":304===t?k="notmodified":(k=v.state,c=v.data,y=v.error,u=!y)):(y=k,!t&&k||(k="error",t<0&&(t=0))),w.status=t,w.statusText=(n||k)+"",u?m.resolveWith(f,[c,k,w]):m.rejectWith(f,[w,k,y]),w.statusCode(g),g=void 0,d&&p.trigger(u?"ajaxSuccess":"ajaxError",[w,h,u?c:y]),_.fireWith(f,[w,k]),d&&(p.trigger("ajaxComplete",[w,h]),--ae.active||ae.event.trigger("ajaxStop")))}"object"==typeof t&&(n=t,t=void 0),n=n||{};var r,a,o,s,l,u,d,c,h=ae.ajaxSetup({},n),f=h.context||h,p=h.context&&(f.nodeType||f.jquery)?ae(f):ae.event,m=ae.Deferred(),_=ae.Callbacks("once memory"),g=h.statusCode||{},y={},v={},b=0,M="canceled",w={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!s)for(s={};t=Mt.exec(o);)s[t[1].toLowerCase()]=t[2];t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?o:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return b||(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(b<2)for(t in e)g[t]=[g[t],e[t]];else w.always(e[w.status]);return this},abort:function(e){var t=e||M;return r&&r.abort(t),i(0,t),this}};if(m.promise(w).complete=_.add,w.success=w.done,w.error=w.fail,h.url=((t||h.url||_t.href)+"").replace(vt,"").replace(Lt,_t.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=ae.trim(h.dataType||"*").toLowerCase().match(Me)||[""],null==h.crossDomain){u=G.createElement("a");try{u.href=h.url,u.href=u.href,h.crossDomain=Yt.protocol+"//"+Yt.host!=u.protocol+"//"+u.host}catch(k){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=ae.param(h.data,h.traditional)),z(xt,h,n,w),2===b)return w;d=ae.event&&h.global,d&&0===ae.active++&&ae.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!kt.test(h.type),a=h.url,h.hasContent||(h.data&&(a=h.url+=(yt.test(a)?"&":"?")+h.data,delete h.data),h.cache===!1&&(h.url=bt.test(a)?a.replace(bt,"$1_="+gt++):a+(yt.test(a)?"&":"?")+"_="+gt++)),h.ifModified&&(ae.lastModified[a]&&w.setRequestHeader("If-Modified-Since",ae.lastModified[a]),ae.etag[a]&&w.setRequestHeader("If-None-Match",ae.etag[a])),(h.data&&h.hasContent&&h.contentType!==!1||n.contentType)&&w.setRequestHeader("Content-Type",h.contentType),w.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+Tt+"; q=0.01":""):h.accepts["*"]);for(c in h.headers)w.setRequestHeader(c,h.headers[c]);if(h.beforeSend&&(h.beforeSend.call(f,w,h)===!1||2===b))return w.abort();M="abort";for(c in{success:1,error:1,complete:1})w[c](h[c]);if(r=z(Dt,h,n,w)){if(w.readyState=1,d&&p.trigger("ajaxSend",[w,h]),2===b)return w;h.async&&h.timeout>0&&(l=e.setTimeout(function(){w.abort("timeout")},h.timeout));try{b=1,r.send(y,i)}catch(k){if(!(b<2))throw k;i(-1,k)}}else i(-1,"No Transport");return w},getJSON:function(e,t,n){return ae.get(e,t,n,"json")},getScript:function(e,t){return ae.get(e,void 0,t,"script")}}),ae.each(["get","post"],function(e,t){ae[t]=function(e,n,i,r){return ae.isFunction(n)&&(r=r||i,i=n,n=void 0),ae.ajax(ae.extend({url:e,type:t,dataType:r,data:n,success:i},ae.isPlainObject(e)&&e))}}),ae._evalUrl=function(e){return ae.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},ae.fn.extend({wrapAll:function(e){var t;return ae.isFunction(e)?this.each(function(t){ae(this).wrapAll(e.call(this,t))}):(this[0]&&(t=ae(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return ae.isFunction(e)?this.each(function(t){ae(this).wrapInner(e.call(this,t))}):this.each(function(){var t=ae(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=ae.isFunction(e);return this.each(function(n){ae(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){ae.nodeName(this,"body")||ae(this).replaceWith(this.childNodes)}).end()}}),ae.expr.filters.hidden=function(e){return!ae.expr.filters.visible(e)},ae.expr.filters.visible=function(e){return e.offsetWidth>0||e.offsetHeight>0||e.getClientRects().length>0};var St=/%20/g,Ct=/\[\]$/,Ht=/\r?\n/g,At=/^(?:submit|button|image|reset|file)$/i,jt=/^(?:input|select|textarea|keygen)/i;ae.param=function(e,t){var n,i=[],r=function(e,t){t=ae.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(void 0===t&&(t=ae.ajaxSettings&&ae.ajaxSettings.traditional),ae.isArray(e)||e.jquery&&!ae.isPlainObject(e))ae.each(e,function(){r(this.name,this.value)});else for(n in e)q(n,e[n],t,r);return i.join("&").replace(St,"+")},ae.fn.extend({serialize:function(){return ae.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=ae.prop(this,"elements");return e?ae.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!ae(this).is(":disabled")&&jt.test(this.nodeName)&&!At.test(e)&&(this.checked||!je.test(e))}).map(function(e,t){var n=ae(this).val();return null==n?null:ae.isArray(n)?ae.map(n,function(e){return{name:t.name,value:e.replace(Ht,"\r\n")}}):{name:t.name,value:n.replace(Ht,"\r\n")}}).get()}}),ae.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(t){}};var Pt={0:200,1223:204},Et=ae.ajaxSettings.xhr();ie.cors=!!Et&&"withCredentials"in Et,ie.ajax=Et=!!Et,ae.ajaxTransport(function(t){var n,i;if(ie.cors||Et&&!t.crossDomain)return{send:function(r,a){var o,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(o in t.xhrFields)s[o]=t.xhrFields[o];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||r["X-Requested-With"]||(r["X-Requested-With"]="XMLHttpRequest");for(o in r)s.setRequestHeader(o,r[o]);n=function(e){return function(){n&&(n=i=s.onload=s.onerror=s.onabort=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?a(0,"error"):a(s.status,s.statusText):a(Pt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),i=s.onerror=n("error"),void 0!==s.onabort?s.onabort=i:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&i()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(l){if(n)throw l}},abort:function(){n&&n()}}}),ae.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return ae.globalEval(e),e}}}),ae.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),ae.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,r){t=ae(" diff --git a/resources/assets/js/components/Setup.vue b/resources/assets/js/components/Setup.vue new file mode 100644 index 00000000000..160dc08d8da --- /dev/null +++ b/resources/assets/js/components/Setup.vue @@ -0,0 +1,54 @@ + diff --git a/resources/assets/js/components/dashboard/Dashboard.vue b/resources/assets/js/components/dashboard/Dashboard.vue new file mode 100644 index 00000000000..0d6aa73f8ce --- /dev/null +++ b/resources/assets/js/components/dashboard/Dashboard.vue @@ -0,0 +1,26 @@ + diff --git a/resources/assets/js/components/dashboard/InviteTeam.vue b/resources/assets/js/components/dashboard/InviteTeam.vue new file mode 100644 index 00000000000..fcfb203dc37 --- /dev/null +++ b/resources/assets/js/components/dashboard/InviteTeam.vue @@ -0,0 +1,31 @@ + diff --git a/resources/assets/js/components/dashboard/ReportIncident.vue b/resources/assets/js/components/dashboard/ReportIncident.vue new file mode 100644 index 00000000000..4813d7eb185 --- /dev/null +++ b/resources/assets/js/components/dashboard/ReportIncident.vue @@ -0,0 +1,45 @@ + diff --git a/resources/assets/js/components/dashboard/ReportSchedule.vue b/resources/assets/js/components/dashboard/ReportSchedule.vue new file mode 100644 index 00000000000..406f5a3f31b --- /dev/null +++ b/resources/assets/js/components/dashboard/ReportSchedule.vue @@ -0,0 +1,30 @@ + diff --git a/resources/assets/js/components/dashboard/UpdateIncident.vue b/resources/assets/js/components/dashboard/UpdateIncident.vue new file mode 100644 index 00000000000..cc96bcdf928 --- /dev/null +++ b/resources/assets/js/components/dashboard/UpdateIncident.vue @@ -0,0 +1,30 @@ + diff --git a/resources/assets/js/components/status-page/Metric.vue b/resources/assets/js/components/status-page/Metric.vue new file mode 100644 index 00000000000..e4452c8055a --- /dev/null +++ b/resources/assets/js/components/status-page/Metric.vue @@ -0,0 +1,198 @@ + + + diff --git a/resources/assets/js/password-strength.js b/resources/assets/js/password-strength.js deleted file mode 100644 index 1471b980a61..00000000000 --- a/resources/assets/js/password-strength.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Combine jQuery and zxcvbn to create a password strength meter. - * Based on : strengthify https://github.com/kabum/strengthify - */ -(function($) { - $.fn.strengthify = function(paramOptions) { - var me = this, - defaults = { - zxcvbn: 'https://cdnjs.cloudflare.com/ajax/libs/zxcvbn/2.0.2/zxcvbn.min.js' - }, - options = $.extend(defaults, paramOptions); - - // Add elements to the DOM - $('.strengthify-wrapper') - .append('
') - .append('
') - .append('
') - .append('
') - .append('
'); - - $.ajax({ - cache: true, - dataType: 'script', - url: options.zxcvbn - }).done(function() { - me.bind('keyup input', function() { - var password = $(this).val(), - // Hide strengthigy if no input is provided - opacity = (password === '') ? 0 : 1, - // Calculate result - result = zxcvbn(password), - css = '', - // cache jQuery selections - $container = $('.strengthify-container'), - $wrapper = $('.strengthify-wrapper'); - - $wrapper.children().css( - 'opacity', - opacity - ).css( - '-ms-filter', - '"progid:DXImageTransform.Microsoft.Alpha(Opacity=' + opacity * 100 + ')"' - ); - - // Style strengthify bar - // possible scores: 0, 1, 2, 3, 4 - switch (result.score) { - case 0: - case 1: - css = 'password-bad'; - break; - case 2: - css = 'password-medium'; - break; - case 3: - case 4: - css = 'password-good'; - break; - } - - $container - .attr('class', css + ' strengthify-container') - // possible scores: 0, 1, 2, 3, 4 - .css( - 'width', - // if score is '0' it will be changed to '1' to - // not hide strengthify if the password is extremely weak - ((result.score === 0 ? 1 : result.score) * 25) + '%' - ); - - // Reset state for empty string password - if (password === '') { - $container.css('width', 0); - } - }); - }); - - return me; - }; -}(jQuery)); diff --git a/resources/assets/sass/_helpers.scss b/resources/assets/sass/_helpers.scss index ace84e4fa00..716ae1348c0 100644 --- a/resources/assets/sass/_helpers.scss +++ b/resources/assets/sass/_helpers.scss @@ -9,3 +9,12 @@ .margin-bottom { margin-bottom: 20px; } + +.no-select { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} diff --git a/resources/assets/sass/_vendors.scss b/resources/assets/sass/_vendors.scss new file mode 100644 index 00000000000..11049477c7f --- /dev/null +++ b/resources/assets/sass/_vendors.scss @@ -0,0 +1,36 @@ +@import "palette"; + +$ionicons-font-path: "../../../fonts" !default; +@import "./node_modules/ionicons/scss/ionicons"; +@import "./node_modules/github-markdown-css/github-markdown"; + +@import "modules/bootstrap"; +@import "plugins/flatpickr"; + +html { + position: relative; + min-height: 100%; + -webkit-font-smoothing: antialiased; + // always show up-down scrollbar to prevent content from jumping left/right + // depending on whether the page is taller than 100% of viewport height + overflow-y: scroll; +} + +body { + margin-bottom: 60px; + padding-bottom: 60px; +} + +@import "helpers"; + +// Module overrides +@import "modules/tabs"; +@import "modules/forms"; +@import "modules/well"; +@import "modules/alerts"; +@import "modules/panels"; +@import "modules/btns"; +@import "modules/pager"; + +// Error pages can have their own overrides. +@import "errors"; diff --git a/resources/assets/sass/app.scss b/resources/assets/sass/app.scss index 2396f6a2f0c..fba0d5d48d9 100644 --- a/resources/assets/sass/app.scss +++ b/resources/assets/sass/app.scss @@ -1,57 +1,7 @@ -@import "palette"; - -$ionicons-font-path: "../../../fonts" !default; -@import "./node_modules/ionicons/scss/ionicons"; - -@import "modules/bootstrap"; - -html { - position: relative; - min-height: 100%; - -webkit-font-smoothing: antialiased; - // always show up-down scrollbar to prevent content from jumping left/right - // depending on whether the page is taller than 100% of viewport height - overflow-y: scroll; -} - -body { - margin-bottom: 60px; - padding-bottom: 60px; -} - -@import "helpers"; - -// Module overrides -@import "modules/tabs"; -@import "modules/forms"; -@import "modules/well"; -@import "modules/alerts"; -@import "modules/panels"; -@import "modules/btns"; -@import "modules/pager"; - -// Styles for partials -@import "partials/base"; -@import "partials/wrapper"; -@import "partials/navbar"; -@import "partials/sidebar"; -@import "partials/content"; -@import "partials/modals"; - -// Styles for specific page -@import "pages/login"; -@import "pages/setup"; -@import "pages/dashboard"; +@import "vendors"; // Styles for plugins -@import "plugins/messenger"; -@import "plugins/animate"; -@import "plugins/bootstrap-datetimepicker/bootstrap-datetimepicker"; -@import "plugins/password-strength"; -@import "plugins/sortable"; +@import "plugins/sweetalert"; // Status Page will need to override certain styles. -@import "status-page"; - -// Error pages can have their own overrides. -@import "errors"; +@import "status-page/status-page"; diff --git a/resources/assets/sass/dashboard.scss b/resources/assets/sass/dashboard.scss new file mode 100644 index 00000000000..56ec6c5168a --- /dev/null +++ b/resources/assets/sass/dashboard.scss @@ -0,0 +1,26 @@ +@import "vendors"; + +// Vendors for sDshboard. +@import "./node_modules/jquery-minicolors/jquery.minicolors"; + +// Styles for partials +@import "dashboard/partials/base"; +@import "dashboard/partials/wrapper"; +@import "dashboard/partials/navbar"; +@import "dashboard/partials/sidebar"; +@import "dashboard/partials/content"; +@import "dashboard/partials/modals"; + +// Styles for specific page +@import "dashboard/pages/login"; +@import "dashboard/pages/setup"; +@import "dashboard/pages/dashboard"; + +// Styles for plugins +/*! purgecss start ignore */ +@import "plugins/jquery.minicolors"; +@import "plugins/sweetalert"; +@import "plugins/messenger"; +@import "plugins/animate"; +@import "plugins/sortable"; +/*! purgecss end ignore */ diff --git a/resources/assets/sass/pages/_dashboard.scss b/resources/assets/sass/dashboard/pages/_dashboard.scss similarity index 64% rename from resources/assets/sass/pages/_dashboard.scss rename to resources/assets/sass/dashboard/pages/_dashboard.scss index f8be49b63d8..018299c933b 100644 --- a/resources/assets/sass/pages/_dashboard.scss +++ b/resources/assets/sass/dashboard/pages/_dashboard.scss @@ -8,12 +8,16 @@ } .component-group-name{ - font-size: 18px; - padding-left: 10px; + font-size: 18px; + padding-left: 10px; } .component-group-other{ - font-size: 18px; + font-size: 18px; +} + +.list-group-item.group-name:hover { + cursor: pointer; } @import "modules/stats"; diff --git a/resources/assets/sass/pages/_login.scss b/resources/assets/sass/dashboard/pages/_login.scss similarity index 100% rename from resources/assets/sass/pages/_login.scss rename to resources/assets/sass/dashboard/pages/_login.scss diff --git a/resources/assets/sass/pages/_setup.scss b/resources/assets/sass/dashboard/pages/_setup.scss similarity index 98% rename from resources/assets/sass/pages/_setup.scss rename to resources/assets/sass/dashboard/pages/_setup.scss index c04e7cf50dc..6bf8718662a 100644 --- a/resources/assets/sass/pages/_setup.scss +++ b/resources/assets/sass/dashboard/pages/_setup.scss @@ -40,6 +40,7 @@ -ms-transition: all 0.2s linear; -o-transition: all 0.2s linear; transition: all 0.2s linear; + z-index: 10; } &.active { diff --git a/resources/assets/sass/partials/_base.scss b/resources/assets/sass/dashboard/partials/_base.scss similarity index 100% rename from resources/assets/sass/partials/_base.scss rename to resources/assets/sass/dashboard/partials/_base.scss diff --git a/resources/assets/sass/partials/_content.scss b/resources/assets/sass/dashboard/partials/_content.scss similarity index 96% rename from resources/assets/sass/partials/_content.scss rename to resources/assets/sass/dashboard/partials/_content.scss index 683e2ce615c..fa7ab4c8d92 100644 --- a/resources/assets/sass/partials/_content.scss +++ b/resources/assets/sass/dashboard/partials/_content.scss @@ -8,6 +8,9 @@ body.dashboard { &.header-fixed { margin-top: 60px; } + textarea[name="stylesheet"] { + resize: vertical; + } } .header { position: relative; diff --git a/resources/assets/sass/partials/_modals.scss b/resources/assets/sass/dashboard/partials/_modals.scss similarity index 100% rename from resources/assets/sass/partials/_modals.scss rename to resources/assets/sass/dashboard/partials/_modals.scss diff --git a/resources/assets/sass/partials/_navbar.scss b/resources/assets/sass/dashboard/partials/_navbar.scss similarity index 100% rename from resources/assets/sass/partials/_navbar.scss rename to resources/assets/sass/dashboard/partials/_navbar.scss diff --git a/resources/assets/sass/partials/_sidebar.scss b/resources/assets/sass/dashboard/partials/_sidebar.scss similarity index 88% rename from resources/assets/sass/partials/_sidebar.scss rename to resources/assets/sass/dashboard/partials/_sidebar.scss index 3cfed0bc801..84f6cff8b68 100644 --- a/resources/assets/sass/partials/_sidebar.scss +++ b/resources/assets/sass/dashboard/partials/_sidebar.scss @@ -6,7 +6,7 @@ body.dashboard { height: 100%; margin-left: -$sidebar-normal-width; overflow-y: auto; - background: $sidebar-background-color; + background: $cachet-base-dark; @include box-shadow($sidebar-border-shadow); z-index: 1000; -webkit-transition: all 0.5s ease; @@ -21,6 +21,7 @@ body.dashboard { margin: 0; padding: 0; list-style: none; + padding-bottom: 64px; /* Ensure the sidebar isn't being covered by the bottom links */ .profile { text-align: center; @@ -66,13 +67,20 @@ body.dashboard { li { font-size: $sidebar-text-size; + &:focus, + &:hover { + background: lighten($cachet-base-dark, 5%) !important; + } &.active { - background: lighten($sidebar-background-color, 2%); + background: lighten($cachet-base-dark, 10%); + &:hover { + background: lighten($cachet-base-dark, 15%) !important; + } a { padding-top: 14px; padding-bottom: 14px; - border-top: 1px solid #6c818c; - border-bottom: 1px solid #6c818c; + border-top: 1px solid $cachet-gray-darker; + border-bottom: 1px solid $cachet-gray-darker; color: $sidebar-text-active-color; &:focus, &:hover { @@ -100,9 +108,9 @@ body.dashboard { span { &.label { float: right; - margin: 6px 0; + margin: 3px 0; &.label-info { - background-color: $cachet-primary; + background-color: $cachet-secondary; } } } @@ -125,7 +133,7 @@ body.dashboard { @extend .hidden-sm; position: fixed; bottom: 0; - width: 230px; + width: 235px; z-index: 999; ul > li { float: left; @@ -204,14 +212,19 @@ body.dashboard { position: fixed; margin-left: 228px; width: 22%; - background: #f9fdff; + background: #F0F3F4; border-right: 1px solid #E8ECF1; h3 { margin: 0; text-align: center; font-size: 19px; - padding: 30px 0; + padding: 30px 15px 15px 15px; + } + + hr { + margin-top: 5px; + margin-bottom: 5px; } ul.menu { diff --git a/resources/assets/sass/partials/_wrapper.scss b/resources/assets/sass/dashboard/partials/_wrapper.scss similarity index 100% rename from resources/assets/sass/partials/_wrapper.scss rename to resources/assets/sass/dashboard/partials/_wrapper.scss diff --git a/resources/assets/sass/modules/_bootstrap.scss b/resources/assets/sass/modules/_bootstrap.scss index 3b24971b688..5bb97f68612 100644 --- a/resources/assets/sass/modules/_bootstrap.scss +++ b/resources/assets/sass/modules/_bootstrap.scss @@ -19,33 +19,33 @@ @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/buttons"; // Components -@import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/component-animations"; +// @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/component-animations"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/dropdowns"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/button-groups"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/input-groups"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/navs"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/navbar"; -@import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/breadcrumbs"; -@import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/pagination"; +// @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/breadcrumbs"; +// @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/pagination"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/pager"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/labels"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/badges"; -@import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/jumbotron"; -@import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/thumbnails"; +// @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/jumbotron"; +// @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/thumbnails"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/alerts"; -@import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/progress-bars"; -@import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/media"; +// @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/progress-bars"; +// @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/media"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/list-group"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/panels"; -@import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/responsive-embed"; +// @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/responsive-embed"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/wells"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/close"; // Components w/ JavaScript @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/modals"; @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/tooltip"; -@import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/popovers"; -@import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/carousel"; +// @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/popovers"; +// @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/carousel"; // Utility classes @import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/utilities"; diff --git a/resources/assets/sass/modules/_btns.scss b/resources/assets/sass/modules/_btns.scss index c245ceb5b57..54d28a36015 100644 --- a/resources/assets/sass/modules/_btns.scss +++ b/resources/assets/sass/modules/_btns.scss @@ -1,18 +1,17 @@ @mixin pretty-buttons($color, $background, $text-shadow: none) { color: $color; - @include gradient-vertical(lighten($background, 5%), darken($background, 5%), 0%, 100%); - border-color: darken($background, 10%); - border-bottom-color: darken($background, 20%); - text-shadow: $text-shadow; - @include box-shadow(inset 0 1px 0 rgba(255, 255, 255, .1)); + background: $background; + border: solid 1px darken($background, 10%); &:hover, &:focus, &:active, &.active { - @include gradient-vertical(darken($background, 0), darken($background, 10%), 0%, 100%); - border-color: darken($background, 20%); + background: darken($background, 5%); + border-color: darken($background, 10%); color: $color; + outline: none; + outline-offset: 0; } &.disabled, @@ -23,34 +22,34 @@ &:focus, &:active, &.active { - background-color: $background; - border-color: darken($background, 5%); + background-color: lighten($background, 5%); + border-color: darken($background, 10%); } } } .btn { - &.btn-default { - @include pretty-buttons($btn-default-color, $btn-default-bg); - } - &.btn-primary { - @include pretty-buttons($btn-primary-color, $btn-primary-bg); - } - &.btn-success { - @include pretty-buttons($btn-success-color, $btn-success-bg); - } - &.btn-info { - @include pretty-buttons($btn-info-color, $btn-info-bg); - } - &.btn-warning { - @include pretty-buttons($btn-warning-color, $btn-warning-bg); - } - &.btn-danger { - @include pretty-buttons($btn-danger-color, $btn-danger-bg); - } - &.btn-inverse { - @include pretty-buttons(white, #474949); - } + &.btn-default { + @include pretty-buttons($btn-default-color, $btn-default-bg); + } + &.btn-primary { + @include pretty-buttons($btn-primary-color, $btn-primary-bg); + } + &.btn-success { + @include pretty-buttons($btn-success-color, $btn-success-bg); + } + &.btn-info { + @include pretty-buttons($btn-info-color, $btn-info-bg); + } + &.btn-warning { + @include pretty-buttons($btn-warning-color, $btn-warning-bg); + } + &.btn-danger { + @include pretty-buttons($btn-danger-color, $btn-danger-bg); + } + &.btn-inverse { + @include pretty-buttons(white, #474949); + } } .btn-outline { diff --git a/resources/assets/sass/modules/_variables.scss b/resources/assets/sass/modules/_variables.scss index 3b68fbccfcb..87c774fd579 100644 --- a/resources/assets/sass/modules/_variables.scss +++ b/resources/assets/sass/modules/_variables.scss @@ -15,7 +15,7 @@ $tooltip-bg: #333 !default; $tooltip-opacity: .9 !default; $base-background-color: #f1f1f1; -$base-font-family: "Open Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif; +$base-font-family: -apple-system, BlinkMacSystemFont, "Open Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif; $base-font-weight: 400; $base-letter-spacing: 0.08em; $base-font-size: 15px; @@ -34,6 +34,6 @@ $sidebar-border-shadow: inset 0px -2px 3px rgba(0,0,0,0.25); $sidebar-text-size: 0.9em; $sidebar-text-color: #ffffff; $sidebar-text-active-color: #ffffff; -$sidebar-normal-width: 230px; +$sidebar-normal-width: 235px; $sidebar-phone-width: 75%; $sidebar-active-color: #00695C; diff --git a/resources/assets/sass/plugins/_flatpickr.scss b/resources/assets/sass/plugins/_flatpickr.scss new file mode 100644 index 00000000000..0ad2ad755c8 --- /dev/null +++ b/resources/assets/sass/plugins/_flatpickr.scss @@ -0,0 +1,63 @@ +/*! purgecss start ignore */ +@import "./node_modules/flatpickr/dist/flatpickr"; + +.flatpickr-calendar { + width: auto; + min-width: 293.75px; + padding: rem-calc(10); + &.open { + z-index: 4 !important; + } + .flatpickr-month { + min-height: 30px; + } + .flatpickr-prev-month, + .flatpickr-current-month, + .flatpickr-next-month { + padding: 0; + display: flex !important; + justify-content: center; + align-items: center; + height: 100%; + } + .flatpickr-prev-month, + .flatpickr-next-month { + border-radius: 1rem; + padding: 0.5rem; + &:hover { + background-color: $cachet-gray-light; + svg { + color: rgba(0, 0, 0, 0.9); + fill: rgba(0, 0, 0, 0.9); + } + } + } + .flatpickr-current-month { + .cur-month { + margin-left: 1rem; + &:hover { + background: transparent; + } + } + } + .flatpickr-day { + line-height: 36px; + &:hover { + background-color: $cachet-gray-light; + border-color: $cachet-gray-light; + } + } + .numInputWrapper { + width: 4rem; + margin-left: 0.5rem; + .numInput { + padding: 0; + box-shadow: none; + } + } +} + +.flatpickr-time { + text-align: left; +} +/*! purgecss end ignore */ diff --git a/resources/assets/sass/plugins/_jquery.minicolors.scss b/resources/assets/sass/plugins/_jquery.minicolors.scss new file mode 100644 index 00000000000..47dffa5ecfa --- /dev/null +++ b/resources/assets/sass/plugins/_jquery.minicolors.scss @@ -0,0 +1,278 @@ +.minicolors { + position: relative; +} + +.minicolors-sprite { + background-image: url(data:image/png;base64,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); +} + +.minicolors-no-data-uris .minicolors-sprite { + background-image: url(jquery.minicolors.png); +} + +.minicolors-swatch { + position: absolute; + vertical-align: middle; + background-position: -80px 0; + border: solid 1px #ccc; + cursor: text; + padding: 0; + margin: 0; + display: inline-block; +} + +.minicolors-swatch-color { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.minicolors input[type=hidden] + .minicolors-swatch { + width: 28px; + position: static; + cursor: pointer; +} + +.minicolors input[type=hidden][disabled] + .minicolors-swatch { + cursor: default; +} + +/* Panel */ +.minicolors-panel { + position: absolute; + width: 173px; + height: 152px; + background: white; + border: solid 1px #CCC; + box-shadow: 0 0 20px rgba(0, 0, 0, .2); + z-index: 99999; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; + display: none; +} + +.minicolors-panel.minicolors-visible { + display: block; +} + +/* Panel positioning */ +.minicolors-position-top .minicolors-panel { + top: -154px; +} + +.minicolors-position-right .minicolors-panel { + right: 0; +} + +.minicolors-position-bottom .minicolors-panel { + top: auto; +} + +.minicolors-position-left .minicolors-panel { + left: 0; +} + +.minicolors-with-opacity .minicolors-panel { + width: 194px; +} + +.minicolors .minicolors-grid { + position: absolute; + top: 1px; + left: 1px; + width: 150px; + height: 150px; + background-position: -120px 0; + cursor: crosshair; +} + +.minicolors .minicolors-grid-inner { + position: absolute; + top: 0; + left: 0; + width: 150px; + height: 150px; +} + +.minicolors-slider-saturation .minicolors-grid { + background-position: -420px 0; +} + +.minicolors-slider-saturation .minicolors-grid-inner { + background-position: -270px 0; + background-image: inherit; +} + +.minicolors-slider-brightness .minicolors-grid { + background-position: -570px 0; +} + +.minicolors-slider-brightness .minicolors-grid-inner { + background-color: black; +} + +.minicolors-slider-wheel .minicolors-grid { + background-position: -720px 0; +} + +.minicolors-slider, +.minicolors-opacity-slider { + position: absolute; + top: 1px; + left: 152px; + width: 20px; + height: 150px; + background-color: white; + background-position: 0 0; + cursor: row-resize; +} + +.minicolors-slider-saturation .minicolors-slider { + background-position: -60px 0; +} + +.minicolors-slider-brightness .minicolors-slider { + background-position: -20px 0; +} + +.minicolors-slider-wheel .minicolors-slider { + background-position: -20px 0; +} + +.minicolors-opacity-slider { + left: 173px; + background-position: -40px 0; + display: none; +} + +.minicolors-with-opacity .minicolors-opacity-slider { + display: block; +} + +/* Pickers */ +.minicolors-grid .minicolors-picker { + position: absolute; + top: 70px; + left: 70px; + width: 12px; + height: 12px; + border: solid 1px black; + border-radius: 10px; + margin-top: -6px; + margin-left: -6px; + background: none; +} + +.minicolors-grid .minicolors-picker > div { + position: absolute; + top: 0; + left: 0; + width: 8px; + height: 8px; + border-radius: 8px; + border: solid 2px white; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; +} + +.minicolors-picker { + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 2px; + background: white; + border: solid 1px black; + margin-top: -2px; + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; + box-sizing: content-box; +} + +/* Inline controls */ +.minicolors-inline { + display: inline-block; +} + +.minicolors-inline .minicolors-input { + display: none !important; +} + +.minicolors-inline .minicolors-panel { + position: relative; + top: auto; + left: auto; + box-shadow: none; + z-index: auto; + display: inline-block; +} + +/* Default theme */ +.minicolors-theme-default .minicolors-swatch { + top: 5px; + left: 5px; + width: 18px; + height: 18px; +} +.minicolors-theme-default.minicolors-position-right .minicolors-swatch { + left: auto; + right: 5px; +} +.minicolors-theme-default.minicolors { + width: auto; + display: inline-block; +} +.minicolors-theme-default .minicolors-input { + height: 20px; + width: auto; + display: inline-block; + padding-left: 26px; +} +.minicolors-theme-default.minicolors-position-right .minicolors-input { + padding-right: 26px; + padding-left: inherit; +} + +/* Bootstrap theme */ +.minicolors-theme-bootstrap .minicolors-swatch { + z-index: 2; + top: 3px; + left: 3px; + width: 28px; + height: 28px; + border-radius: 3px; +} +.minicolors-theme-bootstrap .minicolors-swatch-color { + border-radius: inherit; +} +.minicolors-theme-bootstrap.minicolors-position-right .minicolors-swatch { + left: auto; + right: 3px; +} +.minicolors-theme-bootstrap .minicolors-input { + float: none; + padding-left: 44px; +} +.minicolors-theme-bootstrap.minicolors-position-right .minicolors-input { + padding-right: 44px; + padding-left: 12px; +} +.minicolors-theme-bootstrap .minicolors-input.input-lg + .minicolors-swatch { + top: 4px; + left: 4px; + width: 37px; + height: 37px; + border-radius: 5px; +} +.minicolors-theme-bootstrap .minicolors-input.input-sm + .minicolors-swatch { + width: 24px; + height: 24px; +} +.input-group .minicolors-theme-bootstrap:not(:first-child) .minicolors-input { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} diff --git a/resources/assets/sass/plugins/_messenger.scss b/resources/assets/sass/plugins/_messenger.scss index 7202539f19a..f0bde3db09b 100644 --- a/resources/assets/sass/plugins/_messenger.scss +++ b/resources/assets/sass/plugins/_messenger.scss @@ -346,7 +346,6 @@ ul.messenger-theme-air .messenger-message .messenger-actions a { border-radius: 4px; text-decoration: none; display: inline-block; - padding: 10px; color: #888888; margin-right: 10px; padding: 3px 10px 5px; @@ -452,7 +451,6 @@ ul.messenger-theme-air .messenger-spinner { left: 12px; top: 50%; margin-top: -13px; - z-index: 999; height: 24px; width: 24px; z-index: 10; diff --git a/resources/assets/sass/plugins/_password-strength.scss b/resources/assets/sass/plugins/_password-strength.scss deleted file mode 100644 index c0f18003d03..00000000000 --- a/resources/assets/sass/plugins/_password-strength.scss +++ /dev/null @@ -1,46 +0,0 @@ -.strengthify-wrapper > * { - -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; - filter: alpha(opacity=0); - opacity: 0; - -webkit-transition:all .5s ease-in-out; - -moz-transition:all .5s ease-in-out; - transition:all .5s ease-in-out; -} - -.strengthify-wrapper { - position: relative; -} - -.strengthify-bg, .strengthify-container, .strengthify-wrapper, .strengthify-separator { - height: 8px; -} - -.strengthify-bg, .strengthify-container { - display: block; - position: absolute; - width: 100%; -} - -.strengthify-bg { - background-color: #eeeeee; -} - -.strengthify-separator { - display: inline-block; - position: absolute; - background-color: #ffffff; - width: 2px; - z-index: 10; -} - -.password-bad { - background-color: $cachet-red; -} - -.password-medium { - background-color: $cachet-yellow; -} - -.password-good { - background-color: $cachet-green; -} diff --git a/resources/assets/sass/plugins/_sweetalert.scss b/resources/assets/sass/plugins/_sweetalert.scss new file mode 100644 index 00000000000..067e41ae8e3 --- /dev/null +++ b/resources/assets/sass/plugins/_sweetalert.scss @@ -0,0 +1,5 @@ +@import "./node_modules/sweetalert2/src/sweetalert2"; + +.swal2-modal button { + margin-right: 8px; +} diff --git a/resources/assets/sass/plugins/bootstrap-datetimepicker/bootstrap-datetimepicker.scss b/resources/assets/sass/plugins/bootstrap-datetimepicker/bootstrap-datetimepicker.scss deleted file mode 100644 index ceef1388e07..00000000000 --- a/resources/assets/sass/plugins/bootstrap-datetimepicker/bootstrap-datetimepicker.scss +++ /dev/null @@ -1,329 +0,0 @@ -// Import boostrap variables including default color palette and fonts -@import "./node_modules/bootstrap-sass/assets/stylesheets/bootstrap/_variables"; - -.bootstrap-datetimepicker-widget { - list-style: none; - - &.dropdown-menu { - margin: 2px 0; - padding: 4px; - width: 19em; - - &.timepicker-sbs { - @media (min-width: $screen-sm-min) { - width: 38em; - } - - @media (min-width: $screen-md-min) { - width: 38em; - } - - @media (min-width: $screen-lg-min) { - width: 38em; - } - } - - &:before, &:after { - content: ''; - display: inline-block; - position: absolute; - } - - &.bottom { - &:before { - border-left: 7px solid transparent; - border-right: 7px solid transparent; - border-bottom: 7px solid #ccc; - border-bottom-color: rgba(0, 0, 0, 0.2); - top: -7px; - left: 7px; - } - - &:after { - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-bottom: 6px solid white; - top: -6px; - left: 8px; - } - } - - &.top { - &:before { - border-left: 7px solid transparent; - border-right: 7px solid transparent; - border-top: 7px solid #ccc; - border-top-color: rgba(0, 0, 0, 0.2); - bottom: -7px; - left: 6px; - } - - &:after { - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-top: 6px solid white; - bottom: -6px; - left: 7px; - } - } - - &.pull-right { - &:before { - left: auto; - right: 6px; - } - - &:after { - left: auto; - right: 7px; - } - } - } - - .list-unstyled { - margin: 0; - } - - a[data-action] { - padding: 6px 0; - } - - a[data-action]:active { - box-shadow: none; - } - - .timepicker-hour, .timepicker-minute, .timepicker-second { - width: 54px; - font-weight: bold; - font-size: 1.2em; - margin: 0; - } - - button[data-action] { - padding: 6px; - } - - .btn[data-action="incrementHours"]::after { - @extend .sr-only; - content: "Increment Hours"; - } - - .btn[data-action="incrementMinutes"]::after { - @extend .sr-only; - content: "Increment Minutes"; - } - - .btn[data-action="decrementHours"]::after { - @extend .sr-only; - content: "Decrement Hours"; - } - - .btn[data-action="decrementMinutes"]::after { - @extend .sr-only; - content: "Decrement Minutes"; - } - - .btn[data-action="showHours"]::after { - @extend .sr-only; - content: "Show Hours"; - } - - .btn[data-action="showMinutes"]::after { - @extend .sr-only; - content: "Show Minutes"; - } - - .btn[data-action="togglePeriod"]::after { - @extend .sr-only; - content: "Toggle AM/PM"; - } - - .btn[data-action="clear"]::after { - @extend .sr-only; - content: "Clear the picker"; - } - - .btn[data-action="today"]::after { - @extend .sr-only; - content: "Set the date to today"; - } - - .picker-switch { - text-align: center; - - &::after { - @extend .sr-only; - content: "Toggle Date and Time Screens"; - } - - td { - padding: 0; - margin: 0; - height: auto; - width: auto; - line-height: inherit; - - span { - line-height: 2.5; - height: 2.5em; - width: 100%; - } - } - } - - table { - width: 100%; - margin: 0; - - - & td, - & th { - text-align: center; - border-radius: $border-radius-base; - } - - & th { - height: 20px; - line-height: 20px; - width: 20px; - - &.picker-switch { - width: 145px; - } - - &.disabled, - &.disabled:hover { - background: none; - color: $gray-light; - cursor: not-allowed; - } - - &.prev::after { - @extend .sr-only; - content: "Previous Month"; - } - - &.next::after { - @extend .sr-only; - content: "Next Month"; - } - } - - & thead tr:first-child th { - cursor: pointer; - - &:hover { - background: $gray-lighter; - } - } - - & td { - height: 54px; - line-height: 54px; - width: 54px; - - &.cw { - font-size: .8em; - height: 20px; - line-height: 20px; - color: $gray-light; - } - - &.day { - height: 20px; - line-height: 20px; - width: 20px; - } - - &.day:hover, - &.hour:hover, - &.minute:hover, - &.second:hover { - background: $gray-lighter; - cursor: pointer; - } - - &.old, - &.new { - color: $gray-light; - } - - &.today { - position: relative; - - &:before { - content: ''; - display: inline-block; - border: 0 0 7px 7px solid transparent; - border-bottom-color: $cachet-primary; - border-top-color: rgba(0, 0, 0, 0.2); - position: absolute; - bottom: 4px; - right: 4px; - } - } - - &.active, - &.active:hover { - background-color: $cachet-primary; - color: $btn-primary-color; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - } - - &.active.today:before { - border-bottom-color: #fff; - } - - &.disabled, - &.disabled:hover { - background: none; - color: $gray-light; - cursor: not-allowed; - } - - span { - display: inline-block; - width: 54px; - height: 54px; - line-height: 54px; - margin: 2px 1.5px; - cursor: pointer; - border-radius: $border-radius-base; - - &:hover { - background: $gray-lighter; - } - - &.active { - background-color: $cachet-primary; - color: $btn-primary-color; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); - } - - &.old { - color: $gray-light; - } - - &.disabled, - &.disabled:hover { - background: none; - color: $gray-light; - cursor: not-allowed; - } - } - } - } - - &.usetwentyfour { - td.hour { - height: 27px; - line-height: 27px; - } - } -} - -.input-group.date { - & .input-group-addon { - cursor: pointer; - } -} diff --git a/resources/assets/sass/_status-page.scss b/resources/assets/sass/status-page/_status-page.scss similarity index 94% rename from resources/assets/sass/_status-page.scss rename to resources/assets/sass/status-page/_status-page.scss index 1e8360d3496..0045eb14939 100644 --- a/resources/assets/sass/_status-page.scss +++ b/resources/assets/sass/status-page/_status-page.scss @@ -36,6 +36,7 @@ body.status-page { } .tooltip { + background-color: black; .tooltip-inner { padding: 8px 12px; font-size: 14px; @@ -226,6 +227,8 @@ body.status-page { } .panel-heading { + padding-top: 1em; + padding-bottom: 1.4em; strong { font-size: 1.1em; } @@ -272,8 +275,21 @@ body.status-page { } p, time { + &:not(:last-child) { + margin-bottom: 10px; + } + } + + time { margin-bottom: 0; - line-height: 1.3em; + } + + i.icon { + font-size: 21px; + line-height: 24px; + text-align: center; + display: inline-block; + min-width: 20px; } &.group-name { @@ -410,4 +426,8 @@ body.status-page { } } } + //Display inline the incident update message. + .incident-update-item > p { + display: inline-block; + } } diff --git a/resources/lang/af-ZA/cachet.php b/resources/lang/af-ZA/cachet.php new file mode 100644 index 00000000000..df402fad21c --- /dev/null +++ b/resources/lang/af-ZA/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operasioneel', + 2 => 'Prestasieprobleme', + 3 => 'Gedeeltelike Onderbreking', + 4 => 'Groot Onderbreking', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Hou Dop', + 4 => 'Opgelos', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Afgelope 12 Uur', + 'weekly' => 'Weekliks', + 'monthly' => 'Maandeliks', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Teken aan', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Bestuur Subskripsies', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Teken Aan', + 'username' => 'Username', + 'email' => 'EPos', + 'password' => 'Wagwoord', + 'success' => 'U rekening is geskep.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Maak toe', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Teken aan', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Tuiste', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'Aangaande Hierdie Webwerf', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/af-ZA/dashboard.php b/resources/lang/af-ZA/dashboard.php new file mode 100644 index 00000000000..0171d325601 --- /dev/null +++ b/resources/lang/af-ZA/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Span', + 'member' => 'Lid', + 'profile' => 'Profiel', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Spanlid bygevoeg.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Instellings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Tema', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Teken In', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Teken Uit', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/af-ZA/forms.php b/resources/lang/af-ZA/forms.php new file mode 100644 index 00000000000..320b27e0319 --- /dev/null +++ b/resources/lang/af-ZA/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'EPos', + 'username' => 'Username', + 'password' => 'Wagwoord', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Kies taal', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'EPos', + 'password' => 'Wagwoord', + '2fauth' => 'Authentication Code', + 'invalid' => 'Ongeldige gebruikernaam of wagwoord', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Komponente', + 'component_status' => 'Component Status', + 'message' => 'Boodskap', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Templaat', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Boodskap', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Templaat', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Beskrywing', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Beskrywing', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Beskrywing', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'EPos', + 'password' => 'Wagwoord', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Teken Aan', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/af-ZA/notifications.php b/resources/lang/af-ZA/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/af-ZA/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/af-ZA/pagination.php b/resources/lang/af-ZA/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/af-ZA/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/af-ZA/setup.php b/resources/lang/af-ZA/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/af-ZA/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/af-ZA/validation.php b/resources/lang/af-ZA/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/af-ZA/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/af/cachet.php b/resources/lang/af/cachet.php index dbec2f73f5b..b91a62b5d89 100644 --- a/resources/lang/af/cachet.php +++ b/resources/lang/af/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/af/forms.php b/resources/lang/af/forms.php index e706de8a2a2..360ec491d85 100644 --- a/resources/lang/af/forms.php +++ b/resources/lang/af/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Name', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/ar-SA/cachet.php b/resources/lang/ar-SA/cachet.php new file mode 100644 index 00000000000..ee7f1620c83 --- /dev/null +++ b/resources/lang/ar-SA/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1] النظام يواجه مشاكل|[2,Inf] بعض الأنظمة تواجه مشاكل', + 'major' => '[0,1] النظام يواجه مشاكل أساسية|[2,Inf] بعض الأنظمة تواجه مشاكل أساسية', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/ar-SA/dashboard.php b/resources/lang/ar-SA/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/ar-SA/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/ar-SA/forms.php b/resources/lang/ar-SA/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/ar-SA/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/ar-SA/notifications.php b/resources/lang/ar-SA/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/ar-SA/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/ar-SA/pagination.php b/resources/lang/ar-SA/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/ar-SA/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/ar-SA/setup.php b/resources/lang/ar-SA/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/ar-SA/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/ar-SA/validation.php b/resources/lang/ar-SA/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/ar-SA/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/ar/cachet.php b/resources/lang/ar/cachet.php index f8a1cd83bae..0e018fef925 100644 --- a/resources/lang/ar/cachet.php +++ b/resources/lang/ar/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/ar/forms.php b/resources/lang/ar/forms.php index e706de8a2a2..360ec491d85 100644 --- a/resources/lang/ar/forms.php +++ b/resources/lang/ar/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Name', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/ca-ES/cachet.php b/resources/lang/ca-ES/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/ca-ES/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/ca-ES/dashboard.php b/resources/lang/ca-ES/dashboard.php new file mode 100644 index 00000000000..0abd74e465e --- /dev/null +++ b/resources/lang/ca-ES/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Els membres de l\'equip podran afegir i modificar tant components com incidències.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/ca-ES/forms.php b/resources/lang/ca-ES/forms.php new file mode 100644 index 00000000000..68d0be799ee --- /dev/null +++ b/resources/lang/ca-ES/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'Heu d\'habilitar les galetes (cookies) per poder iniciar sessió.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Farciment (padding) del banner', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/ca-ES/notifications.php b/resources/lang/ca-ES/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/ca-ES/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/ca-ES/pagination.php b/resources/lang/ca-ES/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/ca-ES/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/ca-ES/setup.php b/resources/lang/ca-ES/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/ca-ES/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/ca-ES/validation.php b/resources/lang/ca-ES/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/ca-ES/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/ca/cachet.php b/resources/lang/ca/cachet.php index 8546c0efaf8..c113ee71805 100644 --- a/resources/lang/ca/cachet.php +++ b/resources/lang/ca/cachet.php @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/ca/forms.php b/resources/lang/ca/forms.php index ed4941dcb79..16f3923af04 100644 --- a/resources/lang/ca/forms.php +++ b/resources/lang/ca/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Nom', 'template' => 'Plantilla', - 'twig' => 'Les plantilles d\'incidents poden fer ús del llenguatge de plantilles Twig.', + 'twig' => 'Les plantilles d\'incidents poden fer ús del llenguatge de plantilles Twig.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Identificador de lloc del Piwik', ], 'localization' => [ - 'site-timezone' => 'Seleccioneu el fus horari', - 'site-locale' => 'Idioma del lloc', - 'date-format' => 'Format de la data', - 'incident-date-format' => 'Format del fus horari dels incidents', + 'site-timezone' => 'Seleccioneu el fus horari', + 'site-locale' => 'Idioma del lloc', + 'date-format' => 'Format de la data', + 'incident-date-format' => 'Format del fus horari dels incidents', ], 'security' => [ 'allowed-domains' => 'Dominis permesos', diff --git a/resources/lang/cs-CZ/cachet.php b/resources/lang/cs-CZ/cachet.php new file mode 100644 index 00000000000..6a3d3b46dfc --- /dev/null +++ b/resources/lang/cs-CZ/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Poslední aktualizace :timestamp', + 'status' => [ + 0 => 'Neznámý', + 1 => 'V provozu', + 2 => 'Problémy s výkonem', + 3 => 'Částečný výpadek', + 4 => 'Závažný výpadek', + ], + 'group' => [ + 'other' => 'Ostatní služby', + ], + 'select_all' => 'Označit vše', + 'deselect_all' => 'Odznačit vše', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Nejsou nahlášeny žádné incidenty', + 'past' => 'Minulé incidenty', + 'stickied' => 'Připnuté incidenty', + 'scheduled' => 'Plánovaná odstávka', + 'scheduled_at' => ', plánované na :timestamp', + 'posted' => 'Přidáno :timestamp od :username', + 'posted_at' => 'Publikováno :timestamp', + 'status' => [ + 1 => 'Zkoumání příčiny', + 2 => 'Problém identifikován', + 3 => 'Sledování', + 4 => 'Opraveno', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Blížící se', + 1 => 'Probíhající', + 2 => 'Hotovo', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1] Služba je v provozu|[2,*]Všechny služby fungují bez problémů', + 'bad' => '[0,1] Služba má problémy|[2,Inf] Některá ze služeb má problémy', + 'major' => '[0,1] Služba má celkový výpadek|[2,Inf] Některé služby mají celkový výpadek', + ], + + 'api' => [ + 'regenerate' => 'Obnovit API klíč', + 'revoke' => 'Zrušit API klíč', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Během poslední hodiny', + 'hourly' => 'Posledních 12 hodin', + 'weekly' => 'Týden', + 'monthly' => 'Měsíc', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Přihlaste se změnám stavu a aktualizacím incidentů', + 'unsubscribe' => 'Odhlásit odběr', + 'button' => 'Přihlásit', + 'manage_subscription' => 'Spravovat odběry', + 'manage' => [ + 'notifications' => 'Oznámení', + 'notifications_for' => 'Spravujte oznámení pro', + 'no_subscriptions' => 'Aktuálně jsi přihlášen(a) ke všem upozorněním.', + 'update_subscription' => 'Aktualizovat odběry', + 'my_subscriptions' => 'Aktuálně jsi přihlášen(a) k následujícím upozorněním.', + 'manage_at_link' => 'Spravovat odběry na :link', + ], + 'email' => [ + 'manage_subscription' => 'Poslali jsme Vám e-mail, prosím klikněte na odkaz pro správu odběru', + 'subscribe' => 'Přihlásit se k zasílání upozornění e-mailem.', + 'subscribed' => 'Proběhlo přihlášení k e-mailovým upozorněním, potvrďte ho prosím na vašem e-mailu.', + 'updated-subscribe' => 'Úspěšně jste aktualizovali své odběry.', + 'verified' => 'E-mail pro zasílání upozornění byl ověřen. Děkujeme!', + 'manage' => 'Spravovat e-mailové odběry', + 'unsubscribe' => 'Odhlásit z odběru e-mailových upozornění.', + 'unsubscribed' => 'Odběr e-mailových upozornění byl zrušen.', + 'failure' => 'Došlo k chybě při nastavení odběru e-mailů.', + 'already-subscribed' => 'Nelze přihlásit k odběru :email, protože je již přihlášen.', + ], + ], + + 'signup' => [ + 'title' => 'Registrovat se', + 'username' => 'Uživatelské jméno', + 'email' => 'E-mail', + 'password' => 'Heslo', + 'success' => 'Tvůj účet byl vytvořen.', + 'failure' => 'Něco je špatně, nelze se registrovat.', + ], + + 'system' => [ + 'update' => 'Je k dispozici nová verze Cachet. Jak provést update najdeš zde!', + ], + + // Modal + 'modal' => [ + 'close' => 'Zavřít', + 'subscribe' => [ + 'title' => 'Přihlásit se k odběru upozornění', + 'body' => 'Zadej svůj email pro odběr upozornění této služby. Pokud již odebíráš upozornění, budeš nadále dostávat emaily pro tuto službu.', + 'button' => 'Přihlásit', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Podrobnosti a aktuální informace o událost :name, ke které došlo :date', + 'schedule' => 'Podrobnosti o plánované údržbě :name od :startDate', + 'subscribe' => 'Přihlaste se k odběru :app, abyste obdrželi aktualizace o událostech a plánované údržbě', + 'overview' => 'Držte krok s nejnovějšími aktualizacemi od: app.', + ], + ], + + // Other + 'home' => 'Hlavní stránka', + 'powered_by' => 'Vytvořeno pomocí Cachet.', + 'timezone' => 'Časová zóna je :timezone.', + 'about_this_site' => 'O tomto webu', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Kanál stavů', + +]; diff --git a/resources/lang/cs-CZ/dashboard.php b/resources/lang/cs-CZ/dashboard.php new file mode 100644 index 00000000000..14b725e1d9f --- /dev/null +++ b/resources/lang/cs-CZ/dashboard.php @@ -0,0 +1,304 @@ + 'Řídicí panel', + 'writeable_settings' => 'Nelze zapisovat do složky nastavení Cachet. Ujistěte se, že web server může zapisovat do ./bootstrap/cachet.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidenty & Plán odstávek', + 'incidents' => 'Incidenty', + 'logged' => '{0}Nejsou hlášeny žádné incidenty, dobrá práce.|[1]Zapsali jste jeden incident.|[2,*]Nahlásili jste :count incidentů.', + 'incident-create-template' => 'Vytvořit šablonu', + 'incident-templates' => 'Šablony incidentů', + 'updates' => [ + 'title' => 'Aktualizace incidentu :incident', + 'count' => '{0}žádné aktualizace |[1]jedna aktualizace |[2]dvě aktualizace | [3, *] Několik aktualizací', + 'add' => [ + 'title' => 'Vytvořit novou zprávu k události', + 'success' => 'Vaše aktualizace incidentu byla vytvořena.', + 'failure' => 'Při aktualizaci incidentu se něco pokazilo.', + ], + 'edit' => [ + 'title' => 'Editovat aktualizace incidentu', + 'success' => 'Událost byla aktualizována.', + 'failure' => 'Při aktualizaci incidentu se něco pokazilo', + ], + ], + 'reported_by' => 'Nahlášeno :timestamp od :user', + 'add' => [ + 'title' => 'Nahlásit incident', + 'success' => 'Incident byl přidán.', + 'failure' => 'Došlo k chybě při přidávání události, opakujte akci.', + ], + 'edit' => [ + 'title' => 'Upravit incident', + 'success' => 'Incident aktualizován.', + 'failure' => 'Došlo k chybě při editaci události, opakujte akci.', + ], + 'delete' => [ + 'success' => 'Událost byla odstraněna a už se nebude zobrazovat na stavové stránce.', + 'failure' => 'Událost se nepodařilo smazat, opakujte akci.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Šablony incidentů', + 'add' => [ + 'title' => 'Vytvořit šablonu incidentu', + 'message' => 'Měli byste přidat šablonu události.', + 'success' => 'Byla vytvořena nová šablona události.', + 'failure' => 'Se šablonou události se něco pokazilo.', + ], + 'edit' => [ + 'title' => 'Upravit šablonu', + 'success' => 'Šablona události byla aktualizována.', + 'failure' => 'Při aktualizaci šablony incidentu se něco pokazilo', + ], + 'delete' => [ + 'success' => 'Šablona události byla smazána.', + 'failure' => 'Šablonu události se nepodařilo smazat, opakujte akci.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Plánovaná odstávka', + 'logged' => '{0}Žádná údržba není v plánu, dobrá práce.|[1]Naplánovali jste jednu údržbu.|[2,*]Jsou v plánu :count údržby.', + 'scheduled_at' => 'Naplánováno na :timestamp', + 'add' => [ + 'title' => 'Přidat plánovanou odstávku', + 'success' => 'Odstávka byla přidána.', + 'failure' => 'Něco se pokazilo při přidávání odstávky, zkus to znova.', + ], + 'edit' => [ + 'title' => 'Upravit naplánovanou odstávku', + 'success' => 'Odstávka byla aktualizovaná!', + 'failure' => 'Něco se pokazilo při úpravě odstávky, zkus to znova.', + ], + 'delete' => [ + 'success' => 'Plánovaná odstávka byla smazána a nebude se zobrazovat na hlavní stránce.', + 'failure' => 'Plánovaná odstávka nemohla být smazána, zkus to znova.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Služby', + 'component_statuses' => 'Stavy služeb', + 'listed_group' => 'Seskupeno podle :name', + 'add' => [ + 'title' => 'Přidat službu', + 'message' => 'Měli byste přidat službu.', + 'success' => 'Služba vytvořena.', + 'failure' => 'Něco se pokazilo se skupinou služby, zkus to znova.', + ], + 'edit' => [ + 'title' => 'Upravit službu', + 'success' => 'Služba byla aktualizována.', + 'failure' => 'Něco se pokazilo se skupinou služby, zkus to znova.', + ], + 'delete' => [ + 'success' => 'Služba byla smazána!', + 'failure' => 'Služba nemůže být odstraněna, opakujte akci.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Skupina služeb|Skupiny služeb', + 'no_components' => 'Můžete přidat skupinu služeb.', + 'add' => [ + 'title' => 'Přidat skupinu služeb', + 'success' => 'Skupina služeb byla přidána.', + 'failure' => 'Něco se pokazilo se skupinou služby, zkus to znova.', + ], + 'edit' => [ + 'title' => 'Upravit skupinu komponent', + 'success' => 'Skupina služeb byla aktualizována.', + 'failure' => 'Něco se pokazilo se skupinou služby, zkus to znova.', + ], + 'delete' => [ + 'success' => 'Skupina služeb byla smazána!', + 'failure' => 'Skupina komponent nemohla být smazána, zkus to znova.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metriky', + 'add' => [ + 'title' => 'Vytvořit metriku', + 'message' => 'Měli byste přidat metriku.', + 'success' => 'Metrika vytvořena.', + 'failure' => 'Něco se pokazilo s metrikou, zkus to znova.', + ], + 'edit' => [ + 'title' => 'Upravit metriku', + 'success' => 'Metrika aktualizována.', + 'failure' => 'Něco se pokazilo s metrikou, zkus to znova.', + ], + 'delete' => [ + 'success' => 'Měření bylo smazáno a už se nebude zobrazovat na stavové stránce.', + 'failure' => 'Měření nemohlo být odstraněno, opakujte akci.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Odběratelé', + 'description' => 'Pokud dojde ke vzniku incidentu nebo služby, odběratelé obdrží aktualizace e-mailem.', + 'description_disabled' => 'Chcete-li použít tuto funkci, potřebujete povolit uživatelům registraci pro oznámení.', + 'verified' => 'Ověřeno', + 'not_verified' => 'Neověřeno', + 'subscriber' => ': e-mail, přihlášen: datum', + 'no_subscriptions' => 'Přihlášeno k zasílání všech aktualizací', + 'global' => 'Globálně odebírané', + 'add' => [ + 'title' => 'Přidat nového odběratele', + 'success' => 'Odběratel přidán.', + 'failure' => 'Něco se pokazilo při přidávání odběratele, opakujte akci.', + 'help' => 'Zadejte každého odběratele na nový řádek.', + ], + 'edit' => [ + 'title' => 'Aktualizovat odeběratele', + 'success' => 'Odběratel aktualizován.', + 'failure' => 'Něco se pokazilo při úpravě odběratele, zkus to znova.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Tým', + 'member' => 'Člen', + 'profile' => 'Profil', + 'description' => 'Členové týmu budou schopni přidat nebo upravit komponenty a incidenty.', + 'add' => [ + 'title' => 'Přidat nového člena týmu', + 'success' => 'Nový člen týmu byl přidán.', + 'failure' => 'Člena týmu se nezdařilo přidat, opakujte akci.', + ], + 'edit' => [ + 'title' => 'Aktualizovat profil', + 'success' => 'Profil byl aktualizován.', + 'failure' => 'Něco se pokazilo při aktualizaci profilu, zkus to znova.', + ], + 'delete' => [ + 'success' => 'Člen týmu byl smazán a již nebude mít přístup do řídícího panelu!', + 'failure' => 'Člena týmu se nezdařilo přidat, opakujte akci.', + ], + 'invite' => [ + 'title' => 'Pozvat nového člena týmu', + 'success' => 'Pozvánka byla odeslána', + 'failure' => 'Pozvánka nemohla být odeslána, zkus to znova.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Nastavení', + 'app-setup' => [ + 'app-setup' => 'Nastavení aplikace', + 'images-only' => 'Nahrány mohou být pouze obrázky.', + 'too-big' => 'Soubor, který nahráváte, je příliš velký. Nahrajte obrázek menší než :velikost', + ], + 'analytics' => [ + 'analytics' => 'Monitoring přístupů', + ], + 'log' => [ + 'log' => 'Záznamy', + ], + 'localization' => [ + 'localization' => 'Lokální nastavení', + ], + 'customization' => [ + 'customization' => 'Vlastní nastavení', + 'header' => 'Vlastní hlavička HTML', + 'footer' => 'Vlastní zápatí HTML', + ], + 'mail' => [ + 'mail' => 'E-Mail', + 'test' => 'Vyzkoušet', + 'email' => [ + 'subject' => 'Testovací oznámení z Cachet', + 'body' => 'Toto je testovací oznámení z Cachet.', + ], + ], + 'security' => [ + 'security' => 'Zabezpečení', + 'two-factor' => 'Uživatelé bez dvoufaktorového ověřování', + ], + 'stylesheet' => [ + 'stylesheet' => 'Šablona stylů', + ], + 'theme' => [ + 'theme' => 'Nastavení vzhledu', + ], + 'edit' => [ + 'success' => 'Nastavení uložena.', + 'failure' => 'Nastavení nelze uložit.', + ], + 'credits' => [ + 'credits' => 'Autoři', + 'contributors' => 'Přispěvatelé', + 'license' => 'Cachet je open-sourcový projekt pod BSD-3-licencí, vydávaný Alt Three Services Limited.', + 'backers-title' => 'Podporovatelé a sponzoři', + 'backers' => 'Pokud chcete podpořit další vývoj aplikace, běžte se podívat na kampaň Cachet Patreon.', + 'thank-you' => 'Děkujeme každému z :count přispěvatelů.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Přihlášení', + 'logged_in' => 'Jste přihlášeni.', + 'welcome' => 'Vítejte zpátky!', + 'two-factor' => 'Zadejte prosím váš token.', + ], + + // Sidebar footer + 'help' => 'Nápověda', + 'status_page' => 'Stavová stránka', + 'logout' => 'Odhlásit', + + // Notifications + 'notifications' => [ + 'notifications' => 'Oznámení', + 'awesome' => 'Vynikající.', + 'whoops' => 'Jejda.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Podpořit Cachet', + 'support_subtitle' => 'Mrkněte na náš Patreon page!', + 'news' => 'Poslední novinky', + 'news_subtitle' => 'Získat nejnovější aktualizace', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Vítej na tvé nové Status stránce, :username!', + 'message' => 'Vaše stavová stránka je téměř připravena! Možná budete chtít upravit další nastavení', + 'close' => 'Přejít rovnou do řídícího panelu', + 'steps' => [ + 'component' => 'Vytvoření komponent', + 'incident' => 'Vytvoření incidentů', + 'customize' => 'Přizpůsobit', + 'team' => 'Přidat uživatele', + 'api' => 'Vygenerovat API token', + 'two-factor' => 'Dvoufaktorové ověření', + ], + ], + +]; diff --git a/resources/lang/cs-CZ/forms.php b/resources/lang/cs-CZ/forms.php new file mode 100644 index 00000000000..364e9fc81ce --- /dev/null +++ b/resources/lang/cs-CZ/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'E-mail', + 'username' => 'Uživatelské jméno', + 'password' => 'Heslo', + 'site_name' => 'Název webu', + 'site_domain' => 'Doména webu', + 'site_timezone' => 'Vyberte vaše časové pásmo', + 'site_locale' => 'Vyberte svůj jazyk', + 'enable_google2fa' => 'Povolit dvoufaktorové ověřování Google', + 'cache_driver' => 'Ovladač cache', + 'queue_driver' => 'Řadič fronty', + 'session_driver' => 'Ovladač sezení', + 'mail_driver' => 'Ovladač pro e-mail', + 'mail_host' => 'Host pro Mail', + 'mail_address' => 'Adresa Mailu', + 'mail_username' => 'Uživatelské jméno pro Mail účet', + 'mail_password' => 'Heslo pro Mail účet', + ], + + // Login form fields + 'login' => [ + 'login' => 'Uživatelské jméno nebo e-mail', + 'email' => 'E-mail', + 'password' => 'Heslo', + '2fauth' => 'Ověřovací kód', + 'invalid' => 'Nesprávné uživatelské jméno nebo heslo', + 'invalid-token' => 'Neplatný token', + 'cookies' => 'Pro přihlášení je třeba povolit soubory cookie.', + 'rate-limit' => 'Překročen limit.', + 'remember_me' => 'Zůstat přihlášený', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Jméno', + 'status' => 'Stav', + 'component' => 'Komponenta', + 'component_status' => 'Stavy služeb', + 'message' => 'Zpráva', + 'message-help' => 'Můžete také použít Markdown.', + 'occurred_at' => 'Kdy došlo k incidentu?', + 'notify_subscribers' => 'Oznámit odběratelům?', + 'notify_disabled' => 'Z důvodu plánované údržby budou oznámení o tomto incidentu nebo jeho součástech potlačena.', + 'visibility' => 'Viditelnost incidentu', + 'stick_status' => 'Připnout událost', + 'stickied' => 'Připnuté', + 'not_stickied' => 'Nepřipnuté', + 'public' => 'Viditelné veřejnosti', + 'logged_in_only' => 'Viditelné pouze pro přihlášené uživatele', + 'templates' => [ + 'name' => 'Jméno', + 'template' => 'Šablona', + 'twig' => 'Šablony pro incidenty mohou používat šablonovací jazyk Twig.', + ], + ], + + 'schedules' => [ + 'name' => 'Jméno', + 'status' => 'Stav', + 'message' => 'Zpráva', + 'message-help' => 'Můžete také použít Markdown.', + 'scheduled_at' => 'Na kdy je naplánovaná údržba?', + 'completed_at' => 'Kdy bude údržba hotová?', + 'templates' => [ + 'name' => 'Jméno', + 'template' => 'Šablona', + 'twig' => 'Šablony pro incidenty mohou používat šablonovací jazyk Twig.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Jméno', + 'status' => 'Stav', + 'group' => 'Skupina', + 'description' => 'Popis', + 'link' => 'Odkaz', + 'tags' => 'Štítky', + 'tags-help' => 'Oddělené čárkou.', + 'enabled' => 'Je služba povolena?', + + 'groups' => [ + 'name' => 'Jméno', + 'collapsing' => 'Rozbalit nebo sbalit možnosti', + 'visible' => 'Vždy rozbalené', + 'collapsed' => 'Sbalit skupinu ve výchozím nastavení', + 'collapsed_incident' => 'Sbalit skupinu, ale rozšířit, pokud existují problémy', + 'visibility' => 'Viditelnost', + 'visibility_public' => 'Viditelné pro veřejnost', + 'visibility_authenticated' => 'Viditelné pouze pro přihlášené uživatele', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Jméno', + 'description' => 'Popis', + 'start_at' => 'Naplánovat čas spuštění', + 'timezone' => 'Časová zóna', + 'schedule_frequency' => 'Naplánovat frekvenci (ve vteřinách)', + 'completion_latency' => 'Prodleva dokončení (ve vteřinách)', + 'group' => 'Skupina', + 'active' => 'Aktivní?', + 'groups' => [ + 'name' => 'Název skupiny', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Jméno', + 'suffix' => 'Přípona', + 'description' => 'Popis', + 'description-help' => 'Můžete také použít Markdown.', + 'display-chart' => 'Zobrazovat graf na stavové stránce?', + 'default-value' => 'Výchozí hodnota', + 'calc_type' => 'Výpočet metrik', + 'type_sum' => 'Celkem', + 'type_avg' => 'Průměr', + 'places' => 'Počet desetinných míst', + 'default_view' => 'Výchozí zobrazení', + 'threshold' => 'Jak často se mají snímat metrické body?', + 'visibility' => 'Viditelnost', + 'visibility_authenticated' => 'Viditelné přihlášeným uživatelům', + 'visibility_public' => 'Viditelný všem', + 'visibility_hidden' => 'Vždy skrýt', + + 'points' => [ + 'value' => 'Hodnota', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Název webu', + 'site-url' => 'URL adresa webu', + 'display-graphs' => 'Zobrazit grafy na stavové stránce?', + 'about-this-page' => 'O této stránce', + 'days-of-incidents' => 'Kolik dní incidentů zobrazovat?', + 'time_before_refresh' => 'Obnovovací frekvence status stránky (v sekundách)', + 'major_outage_rate' => 'Hlavní doba výpadků (v %)', + 'banner' => 'Obrázek banneru', + 'banner-help' => 'Doručuje se nenahrávat soubory větší než 930 pixelů na šířku', + 'subscribers' => 'Umožnit lidem, aby se přihlašovali k odběru e-mailových upozornění?', + 'suppress_notifications_in_maintenance' => 'Potlačit oznámení dojde-li k události během během času údržby?', + 'skip_subscriber_verification' => 'Přestat ověřovat uživatele? (Pozor na spammery)', + 'automatic_localization' => 'Automaticky lokalizovat stránku do jazyka návštěvníka?', + 'enable_external_dependencies' => 'Povolit závislosti třetích stran (Google písma, Trackery, atd...)', + 'show_timezone' => 'Zobrazit časové pásmo, ve které je zobrazena stavová stránka', + 'only_disrupted_days' => 'Zobrazit na časové ose pouze dny, kdy došlo k incidentu?', + ], + 'analytics' => [ + 'analytics_google' => 'Kód pro Google Analytics', + 'analytics_gosquared' => 'Kód pro GoSquared Analytics', + 'analytics_piwik_url' => 'URL vaší instance Piwik', + 'analytics_piwik_siteid' => 'Id webu Piwik', + ], + 'localization' => [ + 'site-timezone' => 'Časové pásmo webu', + 'site-locale' => 'Jazyk webu', + 'date-format' => 'Formát datumu', + 'incident-date-format' => 'Formát času pro incident', + ], + 'security' => [ + 'allowed-domains' => 'Povolené domény', + 'allowed-domains-help' => 'Oddělené čárkami. Výše uvedené domény jsou ve výchozím nastavení automaticky povoleny.', + 'always-authenticate' => 'Vždy ověřovat', + 'always-authenticate-help' => 'Požadovat přihlášení k zobrazení jakékoli Cachet stránky', + ], + 'stylesheet' => [ + 'custom-css' => 'Vlastní šablona stylů', + ], + 'theme' => [ + 'background-color' => 'Barva pozadí', + 'background-fills' => 'Pozadí výplně (komponenty, incidenty, zápatí)', + 'banner-background-color' => 'Barva pozadí banneru', + 'banner-padding' => 'Odsazení banneru', + 'fullwidth-banner' => 'Povolit banner přes celou obrazovku?', + 'text-color' => 'Barva textu', + 'dashboard-login' => 'Zobrazit tlačítko Řídící panel v zápatí?', + 'reds' => 'Červená (používané pro chyby)', + 'blues' => 'Modrá (používané pro informace)', + 'greens' => 'Zelená (používá se pro vyřešení problémů)', + 'yellows' => 'Žlutá (používá se pro upozornění)', + 'oranges' => 'Oranžová (slouží k oznámení)', + 'metrics' => 'Vyplnění metrik', + 'links' => 'Odkazy', + ], + ], + + 'user' => [ + 'username' => 'Uživatelské jméno', + 'email' => 'E-mail', + 'password' => 'Heslo', + 'api-token' => 'API Token', + 'api-token-help' => 'Přegenerování vašeho API tokenu zabrání současným aplikacím přistupovat ke Cachet.', + 'gravatar' => 'Profilový obrázek si změn na Gravatar.', + 'user_level' => 'Úroveň uživatele', + 'levels' => [ + 'admin' => 'Správce', + 'user' => 'Uživatel', + ], + '2fa' => [ + 'help' => 'Zapnutí dvoufaktorového ověřování zvýší zabezpečení vašeho účtu. Budete muset stáhnout Google Authenticator nebo podobnou aplikaci pro mobilní zařízení. Po přihlášení budete vyzváni k zadání tokenu vygenerovaného aplikací.', + ], + 'team' => [ + 'description' => 'Pozvi uživatele do týmu zadáním emailové adresy.', + 'email' => 'Email #:id', + ], + ], + + 'general' => [ + 'timezone' => 'Vybrat časové pásmo', + ], + + 'seo' => [ + 'title' => 'SEO titulek', + 'description' => 'Popis SEO', + ], + + // Buttons + 'add' => 'Přidat', + 'save' => 'Uložit', + 'update' => 'Aktualizovat', + 'create' => 'Vytvořit', + 'edit' => 'Upravit', + 'delete' => 'Smazat', + 'submit' => 'Potvrdit', + 'cancel' => 'Zrušit', + 'remove' => 'Smazat', + 'invite' => 'Pozvat', + 'signup' => 'Registrovat se', + 'manage_updates' => 'Správa aktualizací', + + // Other + 'optional' => '* Volitelné', +]; diff --git a/resources/lang/cs-CZ/notifications.php b/resources/lang/cs-CZ/notifications.php new file mode 100644 index 00000000000..7da9d880641 --- /dev/null +++ b/resources/lang/cs-CZ/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Aktualizován stav komponenty', + 'greeting' => 'Stav kompomenty byl aktualizován!', + 'content' => ':name změnil stav z :old_status na :new_status.', + 'action' => 'Zobrazit', + ], + 'slack' => [ + 'title' => 'Aktualizován stav komponenty', + 'content' => ':name změnil stav z :old_status na :new_status.', + ], + 'sms' => [ + 'content' => ':name změnil stav z :old_status na :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Nahlášena nová událost', + 'greeting' => 'Nová událost byla nahlášena v :app_name.', + 'content' => 'Událost :name byla nahlášena', + 'action' => 'Zobrazit', + ], + 'slack' => [ + 'title' => 'Událost :name nahlášena', + 'content' => 'Nová událost byla nahlášena v :app_name', + ], + 'sms' => [ + 'content' => 'Nová událost byla nahlášena v :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Událost aktualizována', + 'content' => ':name byl aktualizován', + 'title' => ':name změnil stav na :new_status', + 'action' => 'Zobrazit', + ], + 'slack' => [ + 'title' => ':name byl aktualizován', + 'content' => ':name změnil stav na :new_status', + ], + 'sms' => [ + 'content' => 'Událost :name byla aktualizována', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Nový plán vytvořen', + 'content' => ':name bylo naplánováno na :date', + 'title' => 'Nová plánovaná údržba byla vytvořena.', + 'action' => 'Zobrazit', + ], + 'slack' => [ + 'title' => 'Nový plán vytvořen!', + 'content' => ':name bylo naplánováno na :date', + ], + 'sms' => [ + 'content' => ':name bylo naplánováno na :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Potvrďte váš odběr', + 'content' => 'Klikněte pro potvrzení odběru stavové stránky :app_name.', + 'title' => 'Potvrďte svůj odběr stavové stránky :app_name.', + 'action' => 'Ověřit', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Spravovat e-mailové odběry', + 'content' => 'Klikněte pro potvrzení odběru stavové stránky :app_name.', + 'title' => 'Klikněte pro potvrzení odběru stavové stránky :app_name.', + 'action' => 'Spravovat odběry', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping z Cachet!', + 'content' => 'Toto je testovací oznámení z Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Uvnitř najdete pozvánku...', + 'content' => 'Byl jste pozván, abyste se připojil ke stavové stránce :app_name.', + 'title' => 'Jste pozváni, abyste se připojili ke stavové stránce :app_name.', + 'action' => 'Potvrdit', + ], + ], + ], +]; diff --git a/resources/lang/cs-CZ/pagination.php b/resources/lang/cs-CZ/pagination.php new file mode 100644 index 00000000000..f4f458eae98 --- /dev/null +++ b/resources/lang/cs-CZ/pagination.php @@ -0,0 +1,28 @@ + 'Předchozí', + 'next' => 'Další', + +]; diff --git a/resources/lang/cs-CZ/setup.php b/resources/lang/cs-CZ/setup.php new file mode 100644 index 00000000000..311b185cf09 --- /dev/null +++ b/resources/lang/cs-CZ/setup.php @@ -0,0 +1,23 @@ + 'Instalace', + 'title' => 'Instalace Cachet', + 'service_details' => 'Podrobnosti o službě', + 'env_setup' => 'Nastavení prostředí', + 'status_page_setup' => 'Nastavení Stavové stránky', + 'show_support' => 'Zobrazit podporu pro Cachet?', + 'admin_account' => 'Účet správce', + 'complete_setup' => 'Dokončení instalace', + 'completed' => 'Cachet byl úspěšně nakonfigurován!', + 'finish_setup' => 'Přejít na dashboard', +]; diff --git a/resources/lang/cs-CZ/validation.php b/resources/lang/cs-CZ/validation.php new file mode 100644 index 00000000000..43d5e772579 --- /dev/null +++ b/resources/lang/cs-CZ/validation.php @@ -0,0 +1,122 @@ + 'Je potřeba potvrdit :attribute.', + 'active_url' => ':attribute není platná adresa URL.', + 'after' => ':attribute musí být datum po :date.', + 'alpha' => ':attribute může obsahovat pouze písmena.', + 'alpha_dash' => ':attribute může obsahovat pouze písmena, čísla a pomlčky.', + 'alpha_num' => ':attribute může obsahovat pouze písmena a čísla.', + 'array' => ':attribute musí být textové pole.', + 'before' => ':attribute musí být datum před :date.', + 'between' => [ + 'numeric' => ':attribute musí mít hodnou mezi :min a :max.', + 'file' => ':attribute musí mít velikost v rozmezí :min až :max kilobytů.', + 'string' => ':attribute musí mít délku v rozmezí :min a :max znaků.', + 'array' => ':attribute musí mít mezi :min a :max položkami.', + ], + 'boolean' => ':attribute musí mít hodnotu pravda nebo nepravda.', + 'confirmed' => 'Potvrzení :attribute se neshoduje.', + 'date' => ':attribute není platné datum.', + 'date_format' => ':attribute se neshoduje se správným formátem :format.', + 'different' => ':attribute a :other se musí lišit.', + 'digits' => ':attribute musí obsahovat :digits číslice.', + 'digits_between' => ':attribute musí být v rozmezí :min a :max číslic.', + 'email' => ':attribute musí být platná e-mailová adresa.', + 'exists' => 'Vybraný :attribute je neplatný.', + 'distinct' => ':attribute má duplicitní hodnotu.', + 'filled' => 'Pole :attribute je vyžadováno.', + 'image' => ':attribute musí být obrázek.', + 'in' => 'Vybraný :attribute je neplatný.', + 'in_array' => ':attribute není v :other.', + 'integer' => ':attribute musí být celé číslo.', + 'ip' => ':attribute musí být platná IP adresa.', + 'json' => ': attribute musí být ve formátu JSON.', + 'max' => [ + 'numeric' => ':attribute nesmí být větší než :max.', + 'file' => ':attribute nesmí být větší než :max kb.', + 'string' => ':attribute nesmí být delší než :max znaků.', + 'array' => 'Atribut nesmí mít více než :max položek.', + ], + 'mimes' => ':attribute musí být soubor typu: :values.', + 'min' => [ + 'numeric' => ':attribute musí být alespoň :min.', + 'file' => 'Atribut musí mít alespoň :min kB.', + 'string' => ':attribute musí být dlouhý alespoň :min znaků.', + 'array' => ':attribute musí mít alespoň :min položek.', + ], + 'not_in' => 'Vybraný :attribute je neplatný.', + 'numeric' => 'Pole :attribute musí být číslo.', + 'present' => 'Pole :attribute je vyžadováno.', + 'regex' => 'Formát :attribute je neplatný.', + 'required' => 'Pole :attribute je vyžadováno.', + 'required_if' => 'Pole :attribute je požadováno, když :other je :value.', + 'required_unless' => 'Pole :attribute je požadováno, pokud :other není v :value.', + 'required_with' => 'Pole :attribute je požadováno, když je zadané :values.', + 'required_with_all' => 'Pole :attribute je požadováno, když je zadané :values.', + 'required_without' => 'Pole :attribute je požadováno když :values není k dispozici.', + 'required_without_all' => 'Pole :attribute je požadováno když :values není k dispozici.', + 'same' => ':attribute a: :other se musí shodovat.', + 'size' => [ + 'numeric' => ':attribute musí mít velikost: :size.', + 'file' => 'Atribut musí mít :size kB.', + 'string' => 'Atribut musí mít :size znaků.', + 'array' => ':attribute musí obsahovat :size položek.', + ], + 'string' => ':attribute musí být text.', + 'timezone' => ':attribute musí být platná zóna.', + 'unique' => ':attribute byl už použit.', + 'url' => 'Formát :attribute je neplatný.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'vlastní zpráva', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/cs/cachet.php b/resources/lang/cs/cachet.php index b1654ab3aef..e9fe4560831 100644 --- a/resources/lang/cs/cachet.php +++ b/resources/lang/cs/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/cs/forms.php b/resources/lang/cs/forms.php index e3e5a1033bf..84af93c8df8 100644 --- a/resources/lang/cs/forms.php +++ b/resources/lang/cs/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Jméno', 'template' => 'Šablona', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/da-DK/cachet.php b/resources/lang/da-DK/cachet.php new file mode 100644 index 00000000000..4b93cc66f96 --- /dev/null +++ b/resources/lang/da-DK/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Sidst opdateret :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Normal', + 2 => 'Hastighedsproblemer', + 3 => 'Nogen udfald', + 4 => 'Store problemer', + ], + 'group' => [ + 'other' => 'Andre komponenter', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Ingen hændelser er rapporteret', + 'past' => 'Tidligere hændelser', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', planlagt til :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Undersøger', + 2 => 'Identificeret', + 3 => 'Overvåger', + 4 => 'Rettet', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Generer en ny API nøgle', + 'revoke' => 'Tilbagekald API nøgle', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Sidste time', + 'hourly' => 'Sidste 12 timer', + 'weekly' => 'Ugentlig', + 'monthly' => 'Månedlig', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Abonner', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifikationer', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'Du abonner i øjeblikket på alle opdateringer.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'Du abonnere i øjeblikket på følgende opdateringer.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Abonner på email opdateringer.', + 'subscribed' => 'Du er blevet tilmeldt email notifikationer. Vi har sendt dig en bekræftelse på den indtastede email-adresse.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Din tilmelding er nu blevet bekræftet, tak.', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Afmeld email notifikationer.', + 'unsubscribed' => 'Du er nu blevet frameldt vores emailnotifikationer.', + 'failure' => 'Noget gik galt med bekræftelsen.', + 'already-subscribed' => 'Kan ikke abonnere da :email allerede er tilmeldt.', + ], + ], + + 'signup' => [ + 'title' => 'Tilmeld', + 'username' => 'Brugernavn', + 'email' => 'Email', + 'password' => 'Adgangskode', + 'success' => 'Din konto er nu oprettet.', + 'failure' => 'Noget gik galt under tilmeldingen.', + ], + + 'system' => [ + 'update' => 'Der er en nyere version af Cachet tilgængelig. Du kan læse mere om hvordan du opdatere her!', + ], + + // Modal + 'modal' => [ + 'close' => 'Luk', + 'subscribe' => [ + 'title' => 'Abonner på komponent opdateringer', + 'body' => 'Indtast din email adresse for at abonnere på opdateringer angående dette komponent. Hvis du allerede er tilmeldt, vil du modtage emails angående dette komponent.', + 'button' => 'Abonner', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Hold dig opdateret med de seneste opdateringer fra :app.', + ], + ], + + // Other + 'home' => 'Hjem', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'Om denne side', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/da-DK/dashboard.php b/resources/lang/da-DK/dashboard.php new file mode 100644 index 00000000000..67bb6687b34 --- /dev/null +++ b/resources/lang/da-DK/dashboard.php @@ -0,0 +1,304 @@ + 'Oversigt', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Opret hændelse', + 'success' => 'Hændelse tilføjet.', + 'failure' => 'Der opstod en fejl i forsøget på at tilføje hændelsen. Prøv venligst igen.', + ], + 'edit' => [ + 'title' => 'Redigér hændelse', + 'success' => 'Hændelse opdateret.', + 'failure' => 'Der opstod en fejl under forsøget på at redigere hændelsen. Prøv venligst igen.', + ], + 'delete' => [ + 'success' => 'Hændelsen er blevet slettet og vil ikke blive vist på din statusside.', + 'failure' => 'Hændelsen kunne ikke slettes. Prøv venligst igen.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Opret hændelses skabelon', + 'message' => 'Create your first incident template.', + 'success' => 'Din nye hændelses skabelon er blevet oprettet.', + 'failure' => 'En fejl er opstået med hændelses skabelonen.', + ], + 'edit' => [ + 'title' => 'Redigér skabelon', + 'success' => 'Hændelses skabelonen er blevet opdateret.', + 'failure' => 'Der opstod en fejl under forsøget på at opdatere hændelses skabelonen', + ], + 'delete' => [ + 'success' => 'Hændelses skabelonen er blevet slettet.', + 'failure' => 'Hændelses skabelonen kunne ikke slettes. Prøv venligst igen.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Planlagt til :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Komponentstatus', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Tilføj komponent', + 'message' => 'Du bør tilføje en komponent.', + 'success' => 'Komponent oprettet.', + 'failure' => 'Noget gik galt med komponentet. Prøv venligst igen.', + ], + 'edit' => [ + 'title' => 'Redigér komponent', + 'success' => 'Komponent opdateret.', + 'failure' => 'Noget gik galt med komponentet. Prøv venligst igen.', + ], + 'delete' => [ + 'success' => 'Komponentet er blevet slettet!', + 'failure' => 'Komponentet kunne ikke slettes. Prøv venligst igen.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Komponentgruppe|Komponentgrupper', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Tilføj komponentgruppe', + 'success' => 'Komponent gruppe tilføjet.', + 'failure' => 'Noget gik galt med komponentet. Prøv venligst igen.', + ], + 'edit' => [ + 'title' => 'Redigér komponentgruppe', + 'success' => 'Komponent gruppe opdateret.', + 'failure' => 'Noget gik galt med komponentet. Prøv venligst igen.', + ], + 'delete' => [ + 'success' => 'Komponent gruppen er blevet slettet!', + 'failure' => 'Komponent gruppen kunne ikke slettes. Prøv venligst igen.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Grafer', + 'add' => [ + 'title' => 'Opret graf', + 'message' => 'Du bør tilføje en graf.', + 'success' => 'Graf oprettet.', + 'failure' => 'Noget gik galt med graffen. Prøv venligst igen.', + ], + 'edit' => [ + 'title' => 'Redigér graf', + 'success' => 'Graf opdateret.', + 'failure' => 'Noget gik galt med graffen. Prøv venligst igen.', + ], + 'delete' => [ + 'success' => 'Grafen er blevet slette og vil ikke længere blive vist på din status side.', + 'failure' => 'Grafen kunne ikke slettes. Prøv venligst igen.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Abonnenter vil modtage notifikationer når hændelser oprettes eller komponenter opdateres.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Bekræftet', + 'not_verified' => 'Ej bekræftet', + 'subscriber' => ':email, abonnerede :date', + 'no_subscriptions' => 'Abonnere på alle opdateringer', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Tilføj abonnent', + 'success' => 'Subscriber added.', + 'failure' => 'Noget gik galt under forsøget på at tilføje en abonnent. Prøv venligst igen.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Redigér abonnent', + 'success' => 'Subscriber updated.', + 'failure' => 'Noget gik galt under forsøget på at redigere abonnenten. Prøv venligst igen.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Brugere', + 'member' => 'Bruger', + 'profile' => 'Profile', + 'description' => 'Brugere kan oprette og rette komponenter og hændelser.', + 'add' => [ + 'title' => 'Tilføj bruger', + 'success' => 'Bruger tilføjet.', + 'failure' => 'Brugeren kunne ikke tilføjes. Prøv venligst igen.', + ], + 'edit' => [ + 'title' => 'Redigér profil', + 'success' => 'Profil opdateret.', + 'failure' => 'Noget gik galt under forsøget på at opdatere profilen. Prøv venligst igen.', + ], + 'delete' => [ + 'success' => 'Slet bruger.', + 'failure' => 'Brugeren kunne ikke tilføjes. Prøv venligst igen.', + ], + 'invite' => [ + 'title' => 'Invite a New Team Member', + 'success' => 'The users invited.', + 'failure' => 'Invitationen kunne ikke sendes. Prøv venligst igen.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Applikationssetup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'Filen du prøvede at uploade er for stort, billet skal være mindre end :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Tilpasning', + 'header' => 'Brugerdefineret header HTML', + 'footer' => 'Brugerdefineret footer html', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Sikkerhed', + 'two-factor' => 'Brugere uden totrinsbekræftelse', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Tema', + ], + 'edit' => [ + 'success' => 'Indstillingerne er gemt.', + 'failure' => 'Indstillingerne kunne ikke gemmes.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Log ind', + 'logged_in' => 'Du er logget ind.', + 'welcome' => 'Velkommen tilbage!', + 'two-factor' => 'Indtast venligst din totrins bekræftelses nøgle.', + ], + + // Sidebar footer + 'help' => 'Hjælp', + 'status_page' => 'Status side', + 'logout' => 'Log ud', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifikationer', + 'awesome' => 'Fantastisk.', + 'whoops' => 'Hov.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Velkommen til din statusside!', + 'message' => 'Din status side er næsten klar! Du ønsker måske at konfigurere disse ekstra indstillinger', + 'close' => 'Til oversigtssiden tak.', + 'steps' => [ + 'component' => 'Opret Komponent', + 'incident' => 'Opret hændelser', + 'customize' => 'Tilpas', + 'team' => 'Tilføj bruger', + 'api' => 'Generer API nøgle', + 'two-factor' => 'Totrinsbekræftelse', + ], + ], + +]; diff --git a/resources/lang/da-DK/forms.php b/resources/lang/da-DK/forms.php new file mode 100644 index 00000000000..3b3ae58e63a --- /dev/null +++ b/resources/lang/da-DK/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Brugernavn', + 'password' => 'Adgangskode', + 'site_name' => 'Sidenavn', + 'site_domain' => 'Sidens domæne', + 'site_timezone' => 'Vælg din tidszone', + 'site_locale' => 'Vælg dit sprog', + 'enable_google2fa' => 'Aktiver Googles to-trins bekræftelse', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Brugernavn eller email', + 'email' => 'Email', + 'password' => 'Adgangskode', + '2fauth' => 'Bekræftelseskode', + 'invalid' => 'Ugyldigt brugernavn eller adgangskode', + 'invalid-token' => 'Ugyldig token', + 'cookies' => 'Du skal tillade cookies for at logge ind.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Navn', + 'status' => 'Status', + 'component' => 'Komponent', + 'component_status' => 'Component Status', + 'message' => 'Besked', + 'message-help' => 'Du kan benytte Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Underret abonnenter', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Hændelses synlighed', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Kan ses af alle', + 'logged_in_only' => 'Kun synlig for brugere der er logget ind', + 'templates' => [ + 'name' => 'Navn', + 'template' => 'Skabelon', + 'twig' => 'Hændelse skabeloner kan gøre brug af Twigs skabelon sprog.', + ], + ], + + 'schedules' => [ + 'name' => 'Navn', + 'status' => 'Status', + 'message' => 'Besked', + 'message-help' => 'Du kan benytte Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Navn', + 'template' => 'Skabelon', + 'twig' => 'Hændelse skabeloner kan gøre brug af Twigs skabelon sprog.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Navn', + 'status' => 'Status', + 'group' => 'Gruppe', + 'description' => 'Beskrivelse', + 'link' => 'Link', + 'tags' => 'Mærkat', + 'tags-help' => 'Komma adskilt.', + 'enabled' => 'Komponent er aktivt', + + 'groups' => [ + 'name' => 'Navn', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Altid åben', + 'collapsed' => 'Minimer gruppen som standard', + 'collapsed_incident' => 'Minimer gruppen, men hold den åben hvis der er fejl', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Navn', + 'description' => 'Beskrivelse', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Gruppe', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Navn', + 'suffix' => 'Endelse', + 'description' => 'Beskrivelse', + 'description-help' => 'Du kan benytte Markdown.', + 'display-chart' => 'Vis graf på statussiden?', + 'default-value' => 'Standard værdi', + 'calc_type' => 'Beregning af grafer', + 'type_sum' => 'Sum', + 'type_avg' => 'Gennemsnit', + 'places' => 'Antal decimaler', + 'default_view' => 'Standardvisning', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Værdi', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Sidenavn', + 'site-url' => 'Sidens URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'Om', + 'days-of-incidents' => 'Hvor mange dage skal der vises hændelser for?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner billede', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Tillad folk at tilmelde sig email underretninger?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics kode', + 'analytics_gosquared' => 'GoSquared Analytics kode', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Tidszone', + 'site-locale' => 'Sprog på siden', + 'date-format' => 'Datoformat', + 'incident-date-format' => 'Datoformat for hændelser', + ], + 'security' => [ + 'allowed-domains' => 'Tilladte domæner', + 'allowed-domains-help' => 'Komma adskilt. Domænet ovenfor har automatisk adgang.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Tilpasset CSS', + ], + 'theme' => [ + 'background-color' => 'Baggrundsfarve', + 'background-fills' => 'Baggrundsfyld (Komponenter, hændelser og footer)', + 'banner-background-color' => 'Baggrundsfarve bag banneret', + 'banner-padding' => 'Banner Padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Tekstfarve', + 'dashboard-login' => 'Vis oversigtsside ikon i bunden af siden?', + 'reds' => 'Rød (Brugt til fejl)', + 'blues' => 'Blå (Brugt til information)', + 'greens' => 'Grøn (Brugt til success)', + 'yellows' => 'Gul (Brugt til advarsler)', + 'oranges' => 'Orange (Brugt til noter)', + 'metrics' => 'Graffyld', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Brugernavn', + 'email' => 'Email', + 'password' => 'Adgangskode', + 'api-token' => 'API nøgle', + 'api-token-help' => 'Hvis du regenerere din API nøgle vil eksisterende applikationer ikke kunne tilgå API\'et.', + 'gravatar' => 'Ændre dit profilbillede hos Gravatar.', + 'user_level' => 'Brugertype', + 'levels' => [ + 'admin' => 'Administrator', + 'user' => 'Bruger', + ], + '2fa' => [ + 'help' => 'Brug totrinsbekræftelse for større sikkerhed på din konto. Du skal installere Google Authenticator eller en lignende app på din mobile enhed, for at kunne logge ind med nøgler fra appen.', + ], + 'team' => [ + 'description' => 'Inviter brugere, ved at indtaste dere email adresser her.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Tilføj', + 'save' => 'Gem', + 'update' => 'Opdatér', + 'create' => 'Opret', + 'edit' => 'Rediger', + 'delete' => 'Slet', + 'submit' => 'Send', + 'cancel' => 'Afbryd', + 'remove' => 'Fjern', + 'invite' => 'Inviter', + 'signup' => 'Tilmeld', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* ikke påkrævet', +]; diff --git a/resources/lang/da-DK/notifications.php b/resources/lang/da-DK/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/da-DK/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/da-DK/pagination.php b/resources/lang/da-DK/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/da-DK/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/da-DK/setup.php b/resources/lang/da-DK/setup.php new file mode 100644 index 00000000000..7bf6b18a973 --- /dev/null +++ b/resources/lang/da-DK/setup.php @@ -0,0 +1,23 @@ + 'Opsætning', + 'title' => 'Indstil Cachet', + 'service_details' => 'Tjenestesdetaljer', + 'env_setup' => 'Opsætning af miljø', + 'status_page_setup' => 'Status side opsætning', + 'show_support' => 'Vis støtte til Cachet?', + 'admin_account' => 'Administratorkonto', + 'complete_setup' => 'Gennemfør opsætning', + 'completed' => 'Cachet er nu sat op og er klar til brug!', + 'finish_setup' => 'Gå til oversigtssiden', +]; diff --git a/resources/lang/da-DK/validation.php b/resources/lang/da-DK/validation.php new file mode 100644 index 00000000000..100398e0320 --- /dev/null +++ b/resources/lang/da-DK/validation.php @@ -0,0 +1,122 @@ + ':attribute skal accepteres.', + 'active_url' => ':attribute er ikke en valid URL.', + 'after' => ':attribute skal være efter den :date.', + 'alpha' => ':attribute må kun indeholde bogstaver.', + 'alpha_dash' => ':attribute må kun indeholde bogstaver, tal og bindestreger.', + 'alpha_num' => ':attribute må kun indeholde tal og bogstaver.', + 'array' => ':attribute skal være et array.', + 'before' => ':attribute skal være før den :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => ':attribute skal have mellem :min og :max emner.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => ':attribute skal være et billede.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => ':attribute skal være en gyldig JSON streng.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => ':attribute må ikke have mere end :max emner.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => ':attribute skal være mindst :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => ':attribute feltet er påkrævet, medmindre :other er i :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => ':attribute skal være :size kilobytes.', + 'string' => ':attribute skal være :size karakterer.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => ':attribute skal være en gyldig zone.', + 'unique' => ':attribute er allerede i brug.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'tilpasset-besked', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/da/cachet.php b/resources/lang/da/cachet.php index 4811ed858ac..cb3deda2411 100644 --- a/resources/lang/da/cachet.php +++ b/resources/lang/da/cachet.php @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "Du er blevet inviteret til :app_name status status side, Klik på linket for at oprette dig.\n:link\nTak, :app_name", - 'html' => '

Du er blevet inviteret til :app_name status side, Klik på linket for at oprette dig.

:link

Tak, :app_name

', + 'text' => "Du er blevet inviteret til :app_name status status side, Klik på linket for at oprette dig.\n:link\nTak, :app_name", + 'html' => '

Du er blevet inviteret til :app_name status side, Klik på linket for at oprette dig.

:link

Tak, :app_name

', ], ], ], diff --git a/resources/lang/da/forms.php b/resources/lang/da/forms.php index 4875cd0ef74..06e0e7c1e06 100644 --- a/resources/lang/da/forms.php +++ b/resources/lang/da/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Navn', 'template' => 'Skabelon', - 'twig' => 'Hændelse skabeloner kan gøre brug af Twigs skabelon sprog.', + 'twig' => 'Hændelse skabeloner kan gøre brug af Twigs skabelon sprog.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Tidszone', - 'site-locale' => 'Sprog på siden', - 'date-format' => 'Datoformat', - 'incident-date-format' => 'Datoformat for hændelser', + 'site-timezone' => 'Tidszone', + 'site-locale' => 'Sprog på siden', + 'date-format' => 'Datoformat', + 'incident-date-format' => 'Datoformat for hændelser', ], 'security' => [ 'allowed-domains' => 'Tilladte domæner', diff --git a/resources/lang/de-DE/cachet.php b/resources/lang/de-DE/cachet.php new file mode 100644 index 00000000000..77779632d56 --- /dev/null +++ b/resources/lang/de-DE/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Letztes Update :timestamp', + 'status' => [ + 0 => 'Unbekannt', + 1 => 'Funktionsfähig', + 2 => 'Leistungsprobleme', + 3 => 'Teilweiser Ausfall', + 4 => 'Schwerer Ausfall', + ], + 'group' => [ + 'other' => 'Andere Komponenten', + ], + 'select_all' => 'Alles auswählen', + 'deselect_all' => 'Alles abwählen', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Es liegen keine Ereignisse vor', + 'past' => 'Vergangene Ereignisse', + 'stickied' => 'Angepinnte Vorfälle', + 'scheduled' => 'Wartungsarbeiten', + 'scheduled_at' => ', geplant :timestamp', + 'posted' => 'Veröffentlicht :timestamp von :username', + 'posted_at' => 'Veröffentlicht am :timestamp', + 'status' => [ + 1 => 'Untersuchungen laufen', + 2 => 'Identifiziert', + 3 => 'Unter Beobachtung', + 4 => 'Behoben', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Bevorstehend', + 1 => 'In Bearbeitung', + 2 => 'Abgeschlossen', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System funktioniert|[2,*]Alle Systeme funktionieren', + 'bad' => '[0,1] Das System hat momentan Probleme|[2,*] Mehrere Systeme haben momentan Probleme', + 'major' => '[0,1] Das System hat ein schwerwiegendes Problem|[2,*] Mehrere Systeme haben ein schwerwiegendes Problem', + ], + + 'api' => [ + 'regenerate' => 'API-Schlüssel erneuern', + 'revoke' => 'API-Schlüssel widerrufen', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Letzte Stunde', + 'hourly' => 'Letzte 12 Stunden', + 'weekly' => 'Wöchentlich', + 'monthly' => 'Monatlich', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Abonniere Status- und Vorfalländerungen', + 'unsubscribe' => 'Abmelden', + 'button' => 'Abonnieren', + 'manage_subscription' => 'Abonnements verwalten', + 'manage' => [ + 'notifications' => 'Benachrichtigungen', + 'notifications_for' => 'Verwalten von Benachrichtigungen für', + 'no_subscriptions' => 'Du hast im Augenblick alle Updates abonniert.', + 'update_subscription' => 'Aktualisieren', + 'my_subscriptions' => 'Du hast im Augenblick folgende Updates abonniert.', + 'manage_at_link' => 'Verwalte deine Abonnements unter :link', + ], + 'email' => [ + 'manage_subscription' => 'Wir haben Ihnen eine E-Mail gesendet. Klicken Sie bitte auf den Link, um Ihr Abonnement zu verwalten.', + 'subscribe' => 'Aktualisierungen per E-Mail abonnieren.', + 'subscribed' => 'Sie haben die E-Mail-Benachrichtigungen bestätigt.', + 'updated-subscribe' => 'Abonnement erfolgreich aktualisiert', + 'verified' => 'Ihre E-Mail-Abonnement ist bestätigt worden. Danke!', + 'manage' => 'Verwalte deine Abonnements', + 'unsubscribe' => 'Abonnement widerrufen.', + 'unsubscribed' => 'Ihre E-Mail-Abonnement wurde beendet.', + 'failure' => 'Beim Aktivieren des Abonnements ist ein Fehler aufgetreten.', + 'already-subscribed' => 'Abonnement für :email konnte nicht registriert werden, da die E-Mail-Adresse bereits registriert ist.', + ], + ], + + 'signup' => [ + 'title' => 'Registrieren', + 'username' => 'Benutzername', + 'email' => 'E-Mail', + 'password' => 'Passwort', + 'success' => 'Ihr Konto wurde erfolgreich erstellt.', + 'failure' => 'Bei der Registrierung ist etwas schief gelaufen.', + ], + + 'system' => [ + 'update' => 'Es ist eine neuere Version von Cachet verfügbar. Erfahre hier!, wie du aktualisieren kannst!', + ], + + // Modal + 'modal' => [ + 'close' => 'Schließen', + 'subscribe' => [ + 'title' => 'Abonniere die Komponenten-Updates', + 'body' => 'Gib deine E-Mail-Adresse ein, um Updates für diese Komponente(n) zu erhalten. Wenn du bereits Abonnent bist, erhältst du automatisch Updates.', + 'button' => 'Abonnieren', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details und Aktualisierung über den :name Vorfall, die am :date aufgetreten sind', + 'schedule' => 'Details zu den geplanten Wartungszeitraum :name beginnend ab :startDate', + 'subscribe' => 'Abonniere :app um Updates von Vorfällen und geplanten Wartungszeiten zu erhalten', + 'overview' => 'Bleiben sie auf dem Laufenden mit den neuesten Service-Updates von :app.', + ], + ], + + // Other + 'home' => 'Startseite', + 'powered_by' => 'Unterstützt von Cachet.', + 'timezone' => 'Uhrzeiten werden in :timezone angezeigt.', + 'about_this_site' => 'Über diese Seite', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status-Feed', + +]; diff --git a/resources/lang/de-DE/dashboard.php b/resources/lang/de-DE/dashboard.php new file mode 100644 index 00000000000..32bbc5ff60c --- /dev/null +++ b/resources/lang/de-DE/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'Das Cachet-Konfigurationsverzeichnis ist nicht beschreibbar. Bitte stellen Sie sicher, dass ./ bootstrap/cachet vom Webserver beschreibbar ist.', + + // Incidents + 'incidents' => [ + 'title' => 'Vorfälle & Wartungsarbeiten', + 'incidents' => 'Ereignisse', + 'logged' => '{0}Es gibt keine Ereignisse, gute Arbeit.|[1]Du hast ein Ereignis gemeldet.|[2,*]Du hast :count Ereignisse gemeldet.', + 'incident-create-template' => 'Vorlage erstellen', + 'incident-templates' => 'Ereignis-Vorlagen', + 'updates' => [ + 'title' => 'Vorfall-Updates für :incident', + 'count' => '{0}Keine Updates|[1]Ein Update|[2]Zwei Updates|[3,*]Mehrere Updates', + 'add' => [ + 'title' => 'Vorfall-Update erstellen', + 'success' => 'Dein Vorfall-Update wurde erstellt.', + 'failure' => 'Beim Erstellen des Vorfalls ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'edit' => [ + 'title' => 'Vorfall-Update bearbeiten', + 'success' => 'Vorfall wurde aktualisiert.', + 'failure' => 'Beim Bearbeiten des Vorfalls ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + ], + 'reported_by' => 'Veröffentlicht :timestamp von :user', + 'add' => [ + 'title' => 'Ereignis hinzufügen', + 'success' => 'Ereignis hinzugefügt.', + 'failure' => 'Beim Erstellen des Ereignisses ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'edit' => [ + 'title' => 'Ereignis bearbeiten', + 'success' => 'Ereignis aktualisiert.', + 'failure' => 'Beim Bearbeiten des Ereignisses ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'delete' => [ + 'success' => 'Das Ereignis wurde gelöscht und wird nicht mehr angezeigt.', + 'failure' => 'Beim Löschen des Ereignisses ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Ereignis-Vorlagen', + 'add' => [ + 'title' => 'Ereignisvorlage erstellen', + 'message' => 'Noch keine Ereignis-Vorlage erstellt.', + 'success' => 'Deine neue Ereignis-Vorlage wurde angelegt.', + 'failure' => 'Beim Erstellen der Ereignis-Vorlage ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'edit' => [ + 'title' => 'Vorlage bearbeiten', + 'success' => 'Die Ereignis-Vorlage wurde aktualisiert.', + 'failure' => 'Beim Bearbeiten der Ereignis-Vorlage ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'delete' => [ + 'success' => 'Die Ereignis-Vorlage wurde gelöscht.', + 'failure' => 'Beim Löschen der Ereignis-Vorlage ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Wartungsarbeiten', + 'logged' => '{0}Es gibt keine geplanten Wartungen, gute Arbeit.|[1]Du hast einen Eintrag erstellt.|[2,*]Du hast :count Einträge erstellt.', + 'scheduled_at' => 'Geplant am :timestamp', + 'add' => [ + 'title' => 'Wartungsarbeiten hinzufügen', + 'success' => 'Wartungsarbeiten hinzugefügt.', + 'failure' => 'Beim Erstellen des Zeitplans ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'edit' => [ + 'title' => 'Planmäßige Wartung bearbeiten', + 'success' => 'Wartungsarbeiten wurden aktualisiert!', + 'failure' => 'Beim Bearbeiten des Zeitplans ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'delete' => [ + 'success' => 'Der Zeitplan wurde gelöscht und wird nicht auf Ihrer Statusseite angezeigt.', + 'failure' => 'Beim Löschen des Zeitplans ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Komponenten', + 'component_statuses' => 'Komponentenstatus', + 'listed_group' => 'Gruppenname :name', + 'add' => [ + 'title' => 'Komponente hinzufügen', + 'message' => 'Sie sollten eine Komponente erstellen.', + 'success' => 'Komponente erstellt.', + 'failure' => 'Beim Erstellen der Komponente ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'edit' => [ + 'title' => 'Komponente bearbeiten', + 'success' => 'Komponente aktualisiert.', + 'failure' => 'Beim Bearbeiten der Komponente ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'delete' => [ + 'success' => 'Die Komponente wurde gelöscht!', + 'failure' => 'Beim Löschen der Komponente ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Komponentengruppe|Komponentengruppen', + 'no_components' => 'Sie sollten eine Komponentengruppe hinzufügen.', + 'add' => [ + 'title' => 'Eine Komponentengruppe hinzufügen', + 'success' => 'Komponentengruppe hinzugefügt.', + 'failure' => 'Beim Erstellen der Komponentengruppe ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'edit' => [ + 'title' => 'Komponentengruppe bearbeiten', + 'success' => 'Komponentengruppe aktualisiert.', + 'failure' => 'Beim Bearbeiten der Komponentengruppe ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'delete' => [ + 'success' => 'Die Komponentengruppe wurde gelöscht!', + 'failure' => 'Beim Löschen der Komponentengruppe ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metriken', + 'add' => [ + 'title' => 'Metrik erstellen', + 'message' => 'Noch keine Metrik erstellt.', + 'success' => 'Metrik erstellt.', + 'failure' => 'Beim Erstellen der Metrik ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'edit' => [ + 'title' => 'Metrik bearbeiten', + 'success' => 'Metrik aktualisiert.', + 'failure' => 'Beim Bearbeiten der Metrik ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'delete' => [ + 'success' => 'Die Metrik wurde gelöscht und wird nicht mehr angezeigt.', + 'failure' => 'Beim Löschen der Metrik ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Abonnenten', + 'description' => 'Abonnenten erhalten E-Mail Updates, wenn Vorfälle erstellt oder Komponenten bearbeitet werden.', + 'description_disabled' => 'Um diese Funktion nutzen zu können, musst du zulassen, dass sich Personen für Benachrichtigungen anmelden dürfen.', + 'verified' => 'Bestätigt', + 'not_verified' => 'Nicht bestätigt', + 'subscriber' => ':email, abonniert am :date', + 'no_subscriptions' => 'Aktualisierungen per E-Mail abonnieren', + 'global' => 'Alles abonniert', + 'add' => [ + 'title' => 'Einen neuen Abonnenten hinzufügen', + 'success' => 'Abonnent hinzugefügt.', + 'failure' => 'Beim Hinzufügen des Abonnenten ist ein Fehler aufgetreten. Versuche es bitte erneut.', + 'help' => 'Gib jeden Abonnenten in eine neue Zeile ein.', + ], + 'edit' => [ + 'title' => 'Abonnent aktualisieren', + 'success' => 'Abonnent aktualisiert.', + 'failure' => 'Beim Bearbeiten des Abonnenten ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Mitglied', + 'profile' => 'Profil', + 'description' => 'Teammitglieder werden die Möglichkeit haben, Komponente sowie Vorfälle hinzuzufügen und zu verändern.', + 'add' => [ + 'title' => 'Neues Teammitglied hinzufügen', + 'success' => 'Teammitglied hinzugefügt.', + 'failure' => 'Beim Hinzufügen des Teammitglieds ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'edit' => [ + 'title' => 'Profil aktualisieren', + 'success' => 'Profil aktualisiert.', + 'failure' => 'Beim Bearbeiten des Teammitglieds ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'delete' => [ + 'success' => 'Benutzer aktualisiert.', + 'failure' => 'Beim Löschen des Teammitglieds ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + 'invite' => [ + 'title' => 'Ein neues Teammitglied einladen', + 'success' => 'Eine Einladung wurde verschickt', + 'failure' => 'Beim Einladen des Teammitglieds ist ein Fehler aufgetreten. Versuche es bitte erneut.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Einstellungen', + 'app-setup' => [ + 'app-setup' => 'Anwendungsinstallation', + 'images-only' => 'Es können nur Bilder hochgeladen werden.', + 'too-big' => 'Die hochgeladene Datei ist zu groß. Es sind nur Dateien mit einer Maximalgröße von :size erlaubt.', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Verlauf', + ], + 'localization' => [ + 'localization' => 'Standort', + ], + 'customization' => [ + 'customization' => 'Individualisierung', + 'header' => 'Benutzerdefinierter HTML Header', + 'footer' => 'Benutzerdefinierter HTML Footer', + ], + 'mail' => [ + 'mail' => 'E-Mail-Einstellungen', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test-Benachrichtigung von Cachet', + 'body' => 'Dies ist eine Test-Benachrichtigung von Cachet.', + ], + ], + 'security' => [ + 'security' => 'Sicherheit', + 'two-factor' => 'Nutzer ohne Zwei-Faktor-Authentifizierung', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Einstellungen gespeichert.', + 'failure' => 'Beim Speichern der Einstellungen ist ein Fehler aufgetreten.', + ], + 'credits' => [ + 'credits' => 'Danksagungen', + 'contributors' => 'Unterstützer', + 'license' => 'Cachet ist ein BSD-3-lizensiertes Open Source-Projekt, veröffentlicht von Alt Three Services Limited.', + 'backers-title' => 'Unterstützer & Sponsoren', + 'backers' => 'Wenn Du die Entwicklung der Software unterstützen möchtest, kannst Du unter Cachet Patreon einen Beitrag leisten.', + 'thank-you' => 'Vielen Dank an jeden der :count Unterstützer.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Einloggen', + 'logged_in' => 'Sie sind eingeloggt.', + 'welcome' => 'Willkommen zurück!', + 'two-factor' => 'Zwei-Faktor-Authentifizierung', + ], + + // Sidebar footer + 'help' => 'Hilfe', + 'status_page' => 'Statusseite', + 'logout' => 'Abmelden', + + // Notifications + 'notifications' => [ + 'notifications' => 'Benachrichtigungen', + 'awesome' => 'Großartig.', + 'whoops' => 'Hoppla.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Cachet unterstützen', + 'support_subtitle' => 'Unterstütze uns auf Patreon!', + 'news' => 'Aktuelle Neuigkeiten', + 'news_subtitle' => 'Erhalte die neusten Nachrichten', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Willkommen zu Deiner Status Seite!', + 'message' => 'Deine Statusseite ist fast fertig! Vielleicht möchtest Du diese zusätzlichen Einstellungen konfigurieren.', + 'close' => 'Gehe einfach direkt zu meinem Dashboard', + 'steps' => [ + 'component' => 'Komponenten erstellen', + 'incident' => 'Ereignis erstellen', + 'customize' => 'Seite anpassen', + 'team' => 'Benutzer hinzufügen', + 'api' => 'API Token generieren', + 'two-factor' => 'Zwei-Faktor-Authentifizierung', + ], + ], + +]; diff --git a/resources/lang/de-DE/forms.php b/resources/lang/de-DE/forms.php new file mode 100644 index 00000000000..445e3ae48a9 --- /dev/null +++ b/resources/lang/de-DE/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'E-Mail', + 'username' => 'Benutzername', + 'password' => 'Passwort', + 'site_name' => 'Seitenname', + 'site_domain' => 'Domain ihrer Seite', + 'site_timezone' => 'Wählen Sie Ihre Zeitzone', + 'site_locale' => 'Wählen Sie Ihre Sprache', + 'enable_google2fa' => 'Google Zwei-Faktor-Authentifizierung aktivieren', + 'cache_driver' => 'Cache-Treiber', + 'queue_driver' => 'Queue-Treiber', + 'session_driver' => 'Sitzungs-Treiber', + 'mail_driver' => 'Mail Protokoll', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Absenderadresse', + 'mail_username' => 'Mail Nutzername', + 'mail_password' => 'Mail Passwort', + ], + + // Login form fields + 'login' => [ + 'login' => 'Nutzername oder E-Mail', + 'email' => 'E-Mail', + 'password' => 'Passwort', + '2fauth' => 'Authentifizierungscode', + 'invalid' => 'Benutzername oder Passwort ungültig', + 'invalid-token' => 'Token ist ungültig', + 'cookies' => 'Sie müssen Cookies aktivieren um sich anzumelden.', + 'rate-limit' => 'Maximale Anzahl von Bewertungen erreicht.', + 'remember_me' => 'Eingeloggt bleiben', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Komponente', + 'component_status' => 'Komponentenstatus', + 'message' => 'Nachricht', + 'message-help' => 'Sie können auch Markdown verwenden.', + 'occurred_at' => 'Wann ist dieser Vorfall aufgetreten?', + 'notify_subscribers' => 'Abonnenten benachrichtigen', + 'notify_disabled' => 'Aufgrund von Wartungsarbeiten werden Benachrichtigungen über diesen Vorfall oder seiner Komponenten unterdrückt.', + 'visibility' => 'Ereignis Sichtbarkeit', + 'stick_status' => 'Vorfall anpinnen', + 'stickied' => 'Angepinnt', + 'not_stickied' => 'Nicht angepinnt', + 'public' => 'Öffentlich sichtbar', + 'logged_in_only' => 'Nur für angemeldete Benutzer sichtbar', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Vorlage', + 'twig' => 'Ereignis-Vorlagen können den Twig Syntax nutzen.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Nachricht', + 'message-help' => 'Sie können auch Markdown verwenden.', + 'scheduled_at' => 'Für wann ist die Wartungsarbeit geplant?', + 'completed_at' => 'Wann wurde diese Wartungsarbeit abgeschlossen?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Vorlage', + 'twig' => 'Ereignis-Vorlagen können den Twig Syntax nutzen.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Gruppe', + 'description' => 'Beschreibung', + 'link' => 'Link', + 'tags' => 'Schlagwörter', + 'tags-help' => 'Durch Kommata trennen.', + 'enabled' => 'Komponente aktiv?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Optionen Anzeigen/Ausblenden', + 'visible' => 'Immer erweitert', + 'collapsed' => 'Die Gruppe standardmäßig ausblenden', + 'collapsed_incident' => 'Die Gruppe standardmäßig ausblenden, aber erweitern wenn es Probleme gibt', + 'visibility' => 'Sichtbarkeit', + 'visibility_public' => 'Öffentlich sichtbar', + 'visibility_authenticated' => 'Nur für angemeldete Benutzer sichtbar', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Beschreibung', + 'start_at' => 'Startzeit festlegen', + 'timezone' => 'Zeitzone', + 'schedule_frequency' => 'Häufigkeit festlegen (in Sekunden)', + 'completion_latency' => 'Wartezeit bis zur Fertigstellung (in Sekunden)', + 'group' => 'Gruppe', + 'active' => 'Aktiv?', + 'groups' => [ + 'name' => 'Gruppen Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Beschreibung', + 'description-help' => 'Sie können auch Markdown verwenden.', + 'display-chart' => 'Diagramm auf der Statusseite anzeigen?', + 'default-value' => 'Standardwert', + 'calc_type' => 'Berechnung der Metrik', + 'type_sum' => 'Summe', + 'type_avg' => 'Durchschnitt', + 'places' => 'Nachkommastellen', + 'default_view' => 'Standardansicht', + 'threshold' => 'Wie viele Minuten soll der Abstand zwischen den Messpunkten sein?', + 'visibility' => 'Sichtbarkeit', + 'visibility_authenticated' => 'Sichtbar für angemeldete Nutzer', + 'visibility_public' => 'Sichtbar für alle', + 'visibility_hidden' => 'Immer ausgeblendet', + + 'points' => [ + 'value' => 'Wert', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Seitenname', + 'site-url' => 'URL ihrer Seite', + 'display-graphs' => 'Graphen auf der Statusseite anzeigen?', + 'about-this-page' => 'Über diese Seite', + 'days-of-incidents' => 'Wie viele Tage mit Vorfällen sollen gezeigt werden?', + 'time_before_refresh' => 'Aktualisierungsrate der Statusseite (in Sekunden)', + 'major_outage_rate' => 'Grenzwert für schwerwiegende Ausfälle (in %)', + 'banner' => 'Banner Bild', + 'banner-help' => 'Es wird empfohlen, dass Sie keine Dateien, die breiter als 930 Pixel sind, hochladen', + 'subscribers' => 'Personen die Anmeldung für E-Mail-Benachrichtigung erlauben?', + 'suppress_notifications_in_maintenance' => 'Möchten Sie Benachrichtigungen über einen Vorfall während des Zeitraumes der Wartungsarbeiten unterdrücken?', + 'skip_subscriber_verification' => 'Verifizierung der Nutzer überspringen? (Warnung, du könntest gespammt werden)', + 'automatic_localization' => 'Die Status-Seite automatisch auf die Sprache deiner Besucher anpassen?', + 'enable_external_dependencies' => 'Drittanbieter Abhängigkeiten erlauben (Google Schriftarten, Tracker, etc...)', + 'show_timezone' => 'Zeitzone in der sich die Status-Seite befindet anzeigen', + 'only_disrupted_days' => 'Im Verlauf nur Tage mit Vorfällen anzeigen?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics Code', + 'analytics_gosquared' => 'GoSquared Analytics Code', + 'analytics_piwik_url' => 'URL der Piwik-Instanz', + 'analytics_piwik_siteid' => 'Piwik\'s Seiten-ID', + ], + 'localization' => [ + 'site-timezone' => 'Zeitzone ihrer Seite', + 'site-locale' => 'Sprache ihrer Seite', + 'date-format' => 'Datumsformat', + 'incident-date-format' => 'Ereignis Uhrzeit Format', + ], + 'security' => [ + 'allowed-domains' => 'Erlaubte Domains', + 'allowed-domains-help' => 'Durch Kommata trennen. Die oben genannte Domain ist standardmäßig erlaubt.', + 'always-authenticate' => 'Immer anmelden', + 'always-authenticate-help' => 'Anmeldung für alle Cachet Seiten erzwingen', + ], + 'stylesheet' => [ + 'custom-css' => 'Benutzerdefiniertes Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Hintergrundfarbe', + 'background-fills' => 'Hintergrunddateien (Komponenten, Vorfälle, Footer)', + 'banner-background-color' => 'Banner Background Color', + 'banner-padding' => 'Banner Padding', + 'fullwidth-banner' => 'Banner über komplette Breite?', + 'text-color' => 'Schriftfarbe', + 'dashboard-login' => 'Dashboard-Button im Footer anzeigen?', + 'reds' => 'Rot (Genutzt für Fehler)', + 'blues' => 'Blau (Genutzt für Informationen)', + 'greens' => 'Grün (Genutzt für Erfolgreich)', + 'yellows' => 'Gelb (Genutzt für Warnungen)', + 'oranges' => 'Orange (Genutzt für Nachrichten)', + 'metrics' => 'Kennzahlen-Füllung', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Benutzername', + 'email' => 'E-Mail', + 'password' => 'Passwort', + 'api-token' => 'API Token', + 'api-token-help' => 'Wenn sie ihren API-Token neu generieren, können bestehende Anwendungen nicht mehr auf Cachet zugreifen.', + 'gravatar' => 'Ändern Sie Ihr Profilbild bei Gravatar.', + 'user_level' => 'Benutzerebene', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'Benutzer', + ], + '2fa' => [ + 'help' => 'Die Zwei-Faktor-Authentifizierung erhöht die Sicherheit Ihres Kontos. Sie benötigen Google Authenticator oder eine ähnliche App auf Ihrem Mobilgerät. Beim Anmelden werden sie aufgefordert, einen Token einzugeben, der von der App generiert wird.', + ], + 'team' => [ + 'description' => 'Laden Sie Ihre Teammitglieder ein, indem Sie deren E-Mail-Adressen hier eingeben.', + 'email' => 'E-Mail-Adresse des Teammitgliedes', + ], + ], + + 'general' => [ + 'timezone' => 'Zeitzone wählen', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Hinzufügen', + 'save' => 'Speichern', + 'update' => 'Aktualisieren', + 'create' => 'Erstellen', + 'edit' => 'Bearbeiten', + 'delete' => 'Löschen', + 'submit' => 'Abschicken', + 'cancel' => 'Abbrechen', + 'remove' => 'Entfernen', + 'invite' => 'Einladen', + 'signup' => 'Registrieren', + 'manage_updates' => 'Updates verwalten', + + // Other + 'optional' => '* optional', +]; diff --git a/resources/lang/de-DE/notifications.php b/resources/lang/de-DE/notifications.php new file mode 100644 index 00000000000..9ee1d429bd0 --- /dev/null +++ b/resources/lang/de-DE/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Status der Komponente aktualisiert', + 'greeting' => 'Ein Komponentenstatus wurde aktualisiert!', + 'content' => ':name Status wurde von :old_status zu :new_status geändert.', + 'action' => 'Anzeigen', + ], + 'slack' => [ + 'title' => 'Status der Komponente aktualisiert', + 'content' => ':name Status wurde von :old_status zu :new_status geändert.', + ], + 'sms' => [ + 'content' => ':name Status wurde von :old_status zu :new_status geändert.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Neuer Vorfall gemeldet', + 'greeting' => 'Ein neuer Vorfall wurde auf der :app_name Status Seite gemeldet.', + 'content' => 'Vorfall :name wurde gemeldet', + 'action' => 'Anzeigen', + ], + 'slack' => [ + 'title' => 'Vorfall :name gemeldet', + 'content' => 'Ein neuer Vorfall wurde auf der :app_name Status Seite gemeldet', + ], + 'sms' => [ + 'content' => 'Ein neuer Vorfall wurde auf der :app_name Status Seite gemeldet.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Vorfall aktualisiert', + 'content' => ':name wurde aktualisiert', + 'title' => ':name wurde auf :new_status aktualisiert', + 'action' => 'Anzeigen', + ], + 'slack' => [ + 'title' => ':name aktualisiert', + 'content' => ':name wurde auf :new_status aktualisiert', + ], + 'sms' => [ + 'content' => 'Vorfall :name wurde aktualisiert', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Neuer Zeitplan erstellt', + 'content' => ':name wurde für :date geplant', + 'title' => 'Eine neue geplante Wartung wurde erstellt.', + 'action' => 'Anzeigen', + ], + 'slack' => [ + 'title' => 'Neuer Zeitplan erstellt!', + 'content' => ':name wurde für :date geplant', + ], + 'sms' => [ + 'content' => ':name wurde für :date geplant', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Bitte bestätigen Sie Ihr Abonnement', + 'content' => 'Klicken Sie, um Ihr Abonnement von :app_name Statusseite zu bestätigen.', + 'title' => 'Bestätigen Sie Ihr Abonnement für die :app_name Statusseite.', + 'action' => 'Bestätigen', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Verwaltung Ihres Abonnements', + 'content' => 'Klicken, um Ihr Abonnement für die Statusseite :app_name zu verwalten.', + 'title' => 'Klicken, um Ihr Abonnement für die Statusseite :app_name zu verwalten.', + 'action' => 'Abonnements verwalten', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping von Cachet!', + 'content' => 'Dies ist eine Test-Benachrichtigung von Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Ihre Einladung wartet auf Sie...', + 'content' => 'Sie wurden eingeladen, um der :app_name Statusseite beizutreten.', + 'title' => 'Sie sind dazu eingeladen, der :app_name Statusseite beizutreten.', + 'action' => 'Akzeptieren', + ], + ], + ], +]; diff --git a/resources/lang/de-DE/pagination.php b/resources/lang/de-DE/pagination.php new file mode 100644 index 00000000000..b52dd5ce6f2 --- /dev/null +++ b/resources/lang/de-DE/pagination.php @@ -0,0 +1,28 @@ + 'Vorherige', + 'next' => 'Nächste', + +]; diff --git a/resources/lang/de-DE/setup.php b/resources/lang/de-DE/setup.php new file mode 100644 index 00000000000..ccda3bfa3fa --- /dev/null +++ b/resources/lang/de-DE/setup.php @@ -0,0 +1,23 @@ + 'Installation', + 'title' => 'Cachet installieren', + 'service_details' => 'Servicedetails', + 'env_setup' => 'Einrichtung der Systemumgebung', + 'status_page_setup' => 'Statusseite einrichten', + 'show_support' => 'Möchten Sie Cachet unterstützen?', + 'admin_account' => 'Administrator Konto', + 'complete_setup' => 'Installation abschließen', + 'completed' => 'Cachet wurde erfolgreich konfiguriert!', + 'finish_setup' => 'Zum Dashboard wechseln', +]; diff --git a/resources/lang/de-DE/validation.php b/resources/lang/de-DE/validation.php new file mode 100644 index 00000000000..9483f4187ef --- /dev/null +++ b/resources/lang/de-DE/validation.php @@ -0,0 +1,122 @@ + ':attribute muss akzeptiert werden.', + 'active_url' => ':attribute ist keine gültige Internet-Adresse.', + 'after' => ':attribute muss ein Datum nach dem :date sein.', + 'alpha' => ':attribute darf nur aus Buchstaben bestehen.', + 'alpha_dash' => ':attribute darf nur aus Buchstaben, Zahlen, Binde- und Unterstrichen bestehen. Umlaute (ä, ö, ü) und Eszett (ß) sind nicht erlaubt.', + 'alpha_num' => ':attribute darf nur aus Buchstaben, Zahlen, Binde- und Unterstrichen bestehen. Umlaute (ä, ö, ü) und Eszett (ß) sind nicht erlaubt.', + 'array' => ':attribute muss ein Array sein.', + 'before' => ':attribute muss ein Datum vor dem :date sein.', + 'between' => [ + 'numeric' => ':attribute muss zwischen :min und :max liegen.', + 'file' => ':attribute muss zwischen :min und :max Kilobytes groß sein.', + 'string' => ':attribute muss zwischen :min und :max Zeichen lang sein.', + 'array' => ':attribute muss zwischen :min & :max Elemente haben.', + ], + 'boolean' => ':attribute Feld muss true oder false sein.', + 'confirmed' => ':attribute Bestätigung stimmt nicht überein.', + 'date' => ':attribute ist kein gültiges Datum.', + 'date_format' => ':attribute entspricht nicht dem Format :format.', + 'different' => ':attribute und :other dürfen nicht identisch sein.', + 'digits' => ':attribute muss :digits Zeichen lang sein.', + 'digits_between' => ':attribute muss zwischen :min und :max Zeichen lang sein.', + 'email' => ':attribute muss eine gültige E-Mail-Ad­res­se sein.', + 'exists' => 'Das ausgewählte :attribute ist ungültig.', + 'distinct' => ':attribute hat doppelte Werte.', + 'filled' => 'Das Feld :attribute ist erforderlich.', + 'image' => ':attribute muss ein Bild sein.', + 'in' => 'Das ausgewählte :attribute ist ungültig.', + 'in_array' => ':attribute existiert nicht in :other.', + 'integer' => ':attribute muss eine ganze Zahl sein.', + 'ip' => ':attribute muss eine gültige IP-Adresse sein.', + 'json' => ':attribut muss ein gültiger JSON-String sein.', + 'max' => [ + 'numeric' => ':attribute darf nicht größer sein als :max.', + 'file' => ':attribute darf nicht größer sein als :max kilobytes.', + 'string' => ':attribute darf maximal :max Zeichen haben.', + 'array' => ':attribute darf nicht mehr als :max Elemente haben.', + ], + 'mimes' => ':attribute muss einem der Dateitypen: :values entsprechen.', + 'min' => [ + 'numeric' => ':attribute muss mindestens :min sein.', + 'file' => ':attribute muss mindestens :min Kilobytes groß sein.', + 'string' => ':attribute muss mindestens :min Zeichen enthalten.', + 'array' => ':attribute muss mindestens :min Elemente haben.', + ], + 'not_in' => 'Das ausgewählte :attribute ist ungültig.', + 'numeric' => ':attribute muss eine Zahl sein.', + 'present' => ':attribute muss ausgefüllt sein.', + 'regex' => 'Das Format von :attribute ist ungültig.', + 'required' => 'Das Feld :attribute ist erforderlich.', + 'required_if' => ':attribute wird benötigt wenn :other :value entspricht.', + 'required_unless' => 'Das :attribute Feld ist erforderlich außer :other hat den Wert :values.', + 'required_with' => ':attribute muss angegeben werden, wenn :values ausgefüllt wurde.', + 'required_with_all' => ':attribute muss angegeben werden, wenn :values ausgefüllt wurde.', + 'required_without' => ':attribute muss angegeben werden, wenn :values nicht angegeben wurde.', + 'required_without_all' => ':attribute ist erforderlich, wenn keiner von :values vorhanden sind.', + 'same' => ':attribute und :other müssen übereinstimmen.', + 'size' => [ + 'numeric' => ':attribute muss :size sein.', + 'file' => ':attribute muss :size Kilobytes groß sein.', + 'string' => ':attribute muss :size Zeichen lang sein.', + 'array' => ':attribute muss :size Elemente beinhalten.', + ], + 'string' => 'Das :attribute muss eine Zeichenfolge sein.', + 'timezone' => ':attribute muss eine gültige Zeitzone sein.', + 'unique' => ':attribute ist schon vergeben.', + 'url' => 'Das Format von :attribute ist ungültig.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'Individuelle Nachricht', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/de/cachet.php b/resources/lang/de/cachet.php index 6791a9306b4..152f8842b26 100644 --- a/resources/lang/de/cachet.php +++ b/resources/lang/de/cachet.php @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "Du wurdest in das Team :app_name Status Seite eingeladen. Um dich zu registrieren klicke den Link.\n:link\nDanke, :app_name", - 'html' => '

Du wurdest in das Team :app_name Status Seite eingeladen. Um dich zu registrieren klicke den Link.

:link

Danke, :app_name

', + 'text' => "Du wurdest in das Team :app_name Status Seite eingeladen. Um dich zu registrieren klicke den Link.\n:link\nDanke, :app_name", + 'html' => '

Du wurdest in das Team :app_name Status Seite eingeladen. Um dich zu registrieren klicke den Link.

:link

Danke, :app_name

', ], ], ], diff --git a/resources/lang/de/forms.php b/resources/lang/de/forms.php index 3eca40e15cb..72a32ee55a0 100644 --- a/resources/lang/de/forms.php +++ b/resources/lang/de/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Name', 'template' => 'Vorlage', - 'twig' => 'Vorfall Vorlagen können den Twig Syntax nutzen.', + 'twig' => 'Vorfall Vorlagen können den Twig Syntax nutzen.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s Seiten-ID', ], 'localization' => [ - 'site-timezone' => 'Zeitzone ihrer Seite', - 'site-locale' => 'Sprache ihrer Seite', - 'date-format' => 'Datumsformat', - 'incident-date-format' => 'Vorfall Zeitstempel-Format', + 'site-timezone' => 'Zeitzone ihrer Seite', + 'site-locale' => 'Sprache ihrer Seite', + 'date-format' => 'Datumsformat', + 'incident-date-format' => 'Vorfall Zeitstempel-Format', ], 'security' => [ 'allowed-domains' => 'Erlaubte Domains', diff --git a/resources/lang/el-GR/cachet.php b/resources/lang/el-GR/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/el-GR/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/el-GR/dashboard.php b/resources/lang/el-GR/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/el-GR/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/el-GR/forms.php b/resources/lang/el-GR/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/el-GR/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/el-GR/notifications.php b/resources/lang/el-GR/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/el-GR/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/el-GR/pagination.php b/resources/lang/el-GR/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/el-GR/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/el-GR/setup.php b/resources/lang/el-GR/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/el-GR/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/el-GR/validation.php b/resources/lang/el-GR/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/el-GR/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/el/cachet.php b/resources/lang/el/cachet.php index 3957dec7d35..a1fef4d062c 100644 --- a/resources/lang/el/cachet.php +++ b/resources/lang/el/cachet.php @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "Έχετε προσκληθεί στη σελίδα ενημερώσεων της ομάδας :app_name, εγγραφείτε στον παρακάτω σύνδεσμο.\n:link\nΕυχαριστούμε, :app_name", - 'html' => '

Έχετε προσκληθεί στη σελίδα ενημερώσεων της ομάδας :app_name, εγγραφείτε στον παρακάτω σύνδεσμο.

:link

Ευχαριστούμε, :app_name

', + 'text' => "Έχετε προσκληθεί στη σελίδα ενημερώσεων της ομάδας :app_name, εγγραφείτε στον παρακάτω σύνδεσμο.\n:link\nΕυχαριστούμε, :app_name", + 'html' => '

Έχετε προσκληθεί στη σελίδα ενημερώσεων της ομάδας :app_name, εγγραφείτε στον παρακάτω σύνδεσμο.

:link

Ευχαριστούμε, :app_name

', ], ], ], diff --git a/resources/lang/el/forms.php b/resources/lang/el/forms.php index 74b55721f6c..c31433ed0fe 100644 --- a/resources/lang/el/forms.php +++ b/resources/lang/el/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Name', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/en-UD/cachet.php b/resources/lang/en-UD/cachet.php index 64dfda79393..0072aa245cb 100644 --- a/resources/lang/en-UD/cachet.php +++ b/resources/lang/en-UD/cachet.php @@ -12,133 +12,129 @@ return [ // Components 'components' => [ - 'last_updated' => 'crwdns721:0crwdne721:0', + 'last_updated' => 'crwdns877:0crwdne877:0', 'status' => [ - 1 => 'crwdns265:0crwdne265:0', - 2 => 'crwdns293:0crwdne293:0', - 3 => 'crwdns294:0crwdne294:0', - 4 => 'crwdns295:0crwdne295:0', + 0 => 'crwdns878:0crwdne878:0', + 1 => 'crwdns879:0crwdne879:0', + 2 => 'crwdns880:0crwdne880:0', + 3 => 'crwdns881:0crwdne881:0', + 4 => 'crwdns882:0crwdne882:0', ], 'group' => [ - 'other' => 'crwdns659:0crwdne659:0', + 'other' => 'crwdns883:0crwdne883:0', ], ], // Incidents 'incidents' => [ - 'none' => 'crwdns657:0crwdne657:0', - 'past' => 'crwdns542:0crwdne542:0', - 'previous_week' => 'crwdns543:0crwdne543:0', - 'next_week' => 'crwdns544:0crwdne544:0', - 'scheduled' => 'crwdns438:0crwdne438:0', - 'scheduled_at' => 'crwdns439:0crwdne439:0', - 'status' => [ - 0 => 'crwdns440:0crwdne440:0', // TODO: Hopefully remove this. - 1 => 'crwdns299:0crwdne299:0', - 2 => 'crwdns300:0crwdne300:0', - 3 => 'crwdns301:0crwdne301:0', - 4 => 'crwdns302:0crwdne302:0', + 'none' => 'crwdns884:0crwdne884:0', + 'past' => 'crwdns885:0crwdne885:0', + 'stickied' => 'crwdns888:0crwdne888:0', + 'scheduled' => 'crwdns1395:0crwdne1395:0', + 'scheduled_at' => 'crwdns890:0crwdne890:0', + 'posted' => 'crwdns891:0crwdne891:0', + 'posted_at' => 'crwdns1396:0crwdne1396:0', + 'status' => [ + 1 => 'crwdns892:0crwdne892:0', + 2 => 'crwdns893:0crwdne893:0', + 3 => 'crwdns894:0crwdne894:0', + 4 => 'crwdns895:0crwdne895:0', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'crwdns896:0crwdne896:0', + 1 => 'crwdns897:0crwdne897:0', + 2 => 'crwdns898:0crwdne898:0', ], ], // Service Status 'service' => [ - 'good' => 'crwdns622:0crwdne622:0', - 'bad' => 'crwdns623:0crwdne623:0', - 'major' => 'crwdns624:0crwdne624:0', + 'good' => 'crwdns1437:0crwdne1437:0', + 'bad' => 'crwdns1398:0crwdne1398:0', + 'major' => 'crwdns1399:0crwdne1399:0', ], 'api' => [ - 'regenerate' => 'crwdns271:0crwdne271:0', - 'revoke' => 'crwdns304:0crwdne304:0', + 'regenerate' => 'crwdns902:0crwdne902:0', + 'revoke' => 'crwdns903:0crwdne903:0', ], // Metrics 'metrics' => [ 'filter' => [ - 'last_hour' => 'crwdns625:0crwdne625:0', - 'hourly' => 'crwdns548:0crwdne548:0', - 'weekly' => 'crwdns549:0crwdne549:0', - 'monthly' => 'crwdns550:0crwdne550:0', + 'last_hour' => 'crwdns904:0crwdne904:0', + 'hourly' => 'crwdns905:0crwdne905:0', + 'weekly' => 'crwdns906:0crwdne906:0', + 'monthly' => 'crwdns907:0crwdne907:0', ], ], // Subscriber 'subscriber' => [ - 'subscribe' => 'crwdns551:0crwdne551:0', - 'button' => 'crwdns490:0crwdne490:0', - 'manage' => [ - 'no_subscriptions' => 'crwdns660:0crwdne660:0', - 'my_subscriptions' => 'crwdns661:0crwdne661:0', + 'subscribe' => 'crwdns908:0crwdne908:0', + 'unsubscribe' => 'crwdns1352:0crwdne1352:0', + 'button' => 'crwdns909:0crwdne909:0', + 'manage' => [ + 'no_subscriptions' => 'crwdns910:0crwdne910:0', + 'my_subscriptions' => 'crwdns911:0crwdne911:0', + 'manage_at_link' => 'crwdns1432:0crwdne1432:0', ], 'email' => [ - 'subscribe' => 'crwdns491:0crwdne491:0', - 'subscribed' => 'crwdns492:0crwdne492:0', - 'verified' => 'crwdns493:0crwdne493:0', - 'manage' => 'crwdns775:0crwdne775:0', - 'unsubscribe' => 'crwdns552:0crwdne552:0', - 'unsubscribed' => 'crwdns495:0crwdne495:0', - 'failure' => 'crwdns496:0crwdne496:0', - 'already-subscribed' => 'crwdns626:0crwdne626:0', - 'verify' => [ - 'text' => 'crwdns776:0crwdne776:0', - 'html' => 'crwdns777:0crwdne777:0', - 'button' => 'crwdns778:0crwdne778:0', - ], - 'maintenance' => [ - 'subject' => 'crwdns779:0crwdne779:0', - ], - 'incident' => [ - 'subject' => 'crwdns780:0:status:crwdne780:0', - ], - 'component' => [ - 'subject' => 'crwdns627:0crwdne627:0', - 'text' => 'crwdns628:0crwdne628:0', - 'html' => 'crwdns630:0crwdne630:0', - 'tooltip-title' => 'crwdns631:0crwdne631:0', - ], - ], - ], - - 'users' => [ - 'email' => [ - 'invite' => [ - 'text' => 'crwdns553:0crwdne553:0', - 'html' => 'crwdns555:0crwdne555:0', - ], + 'subscribe' => 'crwdns912:0crwdne912:0', + 'subscribed' => 'crwdns913:0crwdne913:0', + 'verified' => 'crwdns914:0crwdne914:0', + 'manage' => 'crwdns915:0crwdne915:0', + 'unsubscribe' => 'crwdns916:0crwdne916:0', + 'unsubscribed' => 'crwdns917:0crwdne917:0', + 'failure' => 'crwdns918:0crwdne918:0', + 'already-subscribed' => 'crwdns919:0crwdne919:0', ], ], 'signup' => [ - 'title' => 'crwdns556:0crwdne556:0', - 'username' => 'crwdns557:0crwdne557:0', - 'email' => 'crwdns558:0crwdne558:0', - 'password' => 'crwdns559:0crwdne559:0', - 'success' => 'crwdns560:0crwdne560:0', - 'failure' => 'crwdns561:0crwdne561:0', + 'title' => 'crwdns931:0crwdne931:0', + 'username' => 'crwdns932:0crwdne932:0', + 'email' => 'crwdns933:0crwdne933:0', + 'password' => 'crwdns934:0crwdne934:0', + 'success' => 'crwdns935:0crwdne935:0', + 'failure' => 'crwdns936:0crwdne936:0', ], 'system' => [ - 'update' => 'crwdns632:0crwdne632:0', + 'update' => 'crwdns937:0crwdne937:0', ], // Modal 'modal' => [ - 'close' => 'crwdns633:0crwdne633:0', + 'close' => 'crwdns938:0crwdne938:0', 'subscribe' => [ - 'title' => 'crwdns634:0crwdne634:0', - 'body' => 'crwdns658:0crwdne658:0', - 'button' => 'crwdns636:0crwdne636:0', + 'title' => 'crwdns939:0crwdne939:0', + 'body' => 'crwdns940:0crwdne940:0', + 'button' => 'crwdns941:0crwdne941:0', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'crwdns1428:0crwdne1428:0', + 'schedule' => 'crwdns1429:0crwdne1429:0', + 'subscribe' => 'crwdns1430:0crwdne1430:0', + 'overview' => 'crwdns1431:0crwdne1431:0', ], ], // Other - 'home' => 'crwdns722:0crwdne722:0', - 'description' => 'crwdns663:0crwdne663:0', - 'powered_by' => 'crwdns723:0crwdne723:0', - 'about_this_site' => 'crwdns563:0crwdne563:0', - 'rss-feed' => 'crwdns506:0crwdne506:0', - 'atom-feed' => 'crwdns507:0crwdne507:0', - 'feed' => 'crwdns275:0crwdne275:0', + 'home' => 'crwdns942:0crwdne942:0', + 'powered_by' => 'crwdns944:0crwdne944:0', + 'timezone' => 'crwdns945:0crwdne945:0', + 'about_this_site' => 'crwdns946:0crwdne946:0', + 'rss-feed' => 'crwdns947:0crwdne947:0', + 'atom-feed' => 'crwdns948:0crwdne948:0', + 'feed' => 'crwdns949:0crwdne949:0', ]; diff --git a/resources/lang/en-UD/dashboard.php b/resources/lang/en-UD/dashboard.php index f35edc96aba..46ec0e9a4f6 100644 --- a/resources/lang/en-UD/dashboard.php +++ b/resources/lang/en-UD/dashboard.php @@ -11,264 +11,293 @@ return [ - 'dashboard' => 'crwdns152:0crwdne152:0', + 'dashboard' => 'crwdns950:0crwdne950:0', + 'writeable_settings' => 'crwdns951:0crwdne951:0', // Incidents 'incidents' => [ - 'title' => 'crwdns444:0crwdne444:0', - 'incidents' => 'crwdns153:0crwdne153:0', - 'logged' => 'crwdns305:0{0}crwdne305:0', - 'incident-create-template' => 'crwdns306:0crwdne306:0', - 'incident-templates' => 'crwdns307:0crwdne307:0', + 'title' => 'crwdns1400:0crwdne1400:0', + 'incidents' => 'crwdns953:0crwdne953:0', + 'logged' => 'crwdns1441:0{0}crwdnd1441:0[1]crwdne1441:0', + 'incident-create-template' => 'crwdns955:0crwdne955:0', + 'incident-templates' => 'crwdns956:0crwdne956:0', + 'updates' => [ + 'title' => 'crwdns1402:0crwdne1402:0', + 'count' => 'crwdns1439:0{0}crwdnd1439:0[1]crwdnd1439:0[2]crwdne1439:0', + 'add' => [ + 'title' => 'crwdns1404:0crwdne1404:0', + 'success' => 'crwdns1405:0crwdne1405:0', + 'failure' => 'crwdns1406:0crwdne1406:0', + ], + 'edit' => [ + 'title' => 'crwdns1407:0crwdne1407:0', + 'success' => 'crwdns1408:0crwdne1408:0', + 'failure' => 'crwdns1409:0crwdne1409:0', + ], + ], + 'reported_by' => 'crwdns1433:0crwdne1433:0', 'add' => [ - 'title' => 'crwdns564:0crwdne564:0', - 'success' => 'crwdns664:0crwdne664:0', - 'failure' => 'crwdns665:0crwdne665:0', + 'title' => 'crwdns958:0crwdne958:0', + 'success' => 'crwdns959:0crwdne959:0', + 'failure' => 'crwdns960:0crwdne960:0', ], 'edit' => [ - 'title' => 'crwdns565:0crwdne565:0', - 'success' => 'crwdns312:0crwdne312:0', - 'failure' => 'crwdns666:0crwdne666:0', + 'title' => 'crwdns961:0crwdne961:0', + 'success' => 'crwdns962:0crwdne962:0', + 'failure' => 'crwdns963:0crwdne963:0', ], 'delete' => [ - 'success' => 'crwdns637:0crwdne637:0', - 'failure' => 'crwdns667:0crwdne667:0', + 'success' => 'crwdns964:0crwdne964:0', + 'failure' => 'crwdns965:0crwdne965:0', ], // Incident templates 'templates' => [ - 'title' => 'crwdns314:0crwdne314:0', + 'title' => 'crwdns968:0crwdne968:0', 'add' => [ - 'title' => 'crwdns566:0crwdne566:0', - 'message' => 'crwdns639:0crwdne639:0', - 'success' => 'crwdns668:0crwdne668:0', - 'failure' => 'crwdns669:0crwdne669:0', + 'title' => 'crwdns969:0crwdne969:0', + 'message' => 'crwdns1443:0crwdne1443:0', + 'success' => 'crwdns971:0crwdne971:0', + 'failure' => 'crwdns972:0crwdne972:0', ], 'edit' => [ - 'title' => 'crwdns567:0crwdne567:0', - 'success' => 'crwdns670:0crwdne670:0', - 'failure' => 'crwdns671:0crwdne671:0', + 'title' => 'crwdns973:0crwdne973:0', + 'success' => 'crwdns974:0crwdne974:0', + 'failure' => 'crwdns975:0crwdne975:0', ], 'delete' => [ - 'success' => 'crwdns640:0crwdne640:0', - 'failure' => 'crwdns672:0crwdne672:0', + 'success' => 'crwdns976:0crwdne976:0', + 'failure' => 'crwdns977:0crwdne977:0', ], ], ], // Incident Maintenance 'schedule' => [ - 'schedule' => 'crwdns445:0crwdne445:0', - 'logged' => 'crwdns642:0{0}crwdne642:0', - 'scheduled_at' => 'crwdns446:0crwdne446:0', + 'schedule' => 'crwdns1410:0crwdne1410:0', + 'logged' => 'crwdns1440:0{0}crwdnd1440:0[1]crwdne1440:0', + 'scheduled_at' => 'crwdns980:0crwdne980:0', 'add' => [ - 'title' => 'crwdns673:0crwdne673:0', - 'success' => 'crwdns674:0crwdne674:0', - 'failure' => 'crwdns675:0crwdne675:0', + 'title' => 'crwdns1412:0crwdne1412:0', + 'success' => 'crwdns1413:0crwdne1413:0', + 'failure' => 'crwdns1414:0crwdne1414:0', ], 'edit' => [ - 'title' => 'crwdns676:0crwdne676:0', - 'success' => 'crwdns677:0crwdne677:0', - 'failure' => 'crwdns678:0crwdne678:0', + 'title' => 'crwdns1415:0crwdne1415:0', + 'success' => 'crwdns1416:0crwdne1416:0', + 'failure' => 'crwdns1417:0crwdne1417:0', ], 'delete' => [ - 'success' => 'crwdns679:0crwdne679:0', - 'failure' => 'crwdns680:0crwdne680:0', + 'success' => 'crwdns1418:0crwdne1418:0', + 'failure' => 'crwdns1419:0crwdne1419:0', ], ], // Components 'components' => [ - 'components' => 'crwdns431:0crwdne431:0', - 'component_statuses' => 'crwdns321:0crwdne321:0', - 'listed_group' => 'crwdns473:0crwdne473:0', + 'components' => 'crwdns989:0crwdne989:0', + 'component_statuses' => 'crwdns990:0crwdne990:0', + 'listed_group' => 'crwdns991:0crwdne991:0', 'add' => [ - 'title' => 'crwdns568:0crwdne568:0', - 'message' => 'crwdns323:0crwdne323:0', - 'success' => 'crwdns681:0crwdne681:0', - 'failure' => 'crwdns682:0crwdne682:0', + 'title' => 'crwdns992:0crwdne992:0', + 'message' => 'crwdns993:0crwdne993:0', + 'success' => 'crwdns994:0crwdne994:0', + 'failure' => 'crwdns995:0crwdne995:0', ], 'edit' => [ - 'title' => 'crwdns569:0crwdne569:0', - 'success' => 'crwdns683:0crwdne683:0', - 'failure' => 'crwdns684:0crwdne684:0', + 'title' => 'crwdns996:0crwdne996:0', + 'success' => 'crwdns997:0crwdne997:0', + 'failure' => 'crwdns998:0crwdne998:0', ], 'delete' => [ - 'success' => 'crwdns643:0crwdne643:0', - 'failure' => 'crwdns685:0crwdne685:0', + 'success' => 'crwdns999:0crwdne999:0', + 'failure' => 'crwdns1000:0crwdne1000:0', ], // Component groups 'groups' => [ - 'groups' => 'crwdns329:0crwdne329:0', - 'no_components' => 'crwdns478:0crwdne478:0', + 'groups' => 'crwdns1001:0crwdne1001:0', + 'no_components' => 'crwdns1002:0crwdne1002:0', 'add' => [ - 'title' => 'crwdns570:0crwdne570:0', - 'success' => 'crwdns686:0crwdne686:0', - 'failure' => 'crwdns687:0crwdne687:0', + 'title' => 'crwdns1003:0crwdne1003:0', + 'success' => 'crwdns1004:0crwdne1004:0', + 'failure' => 'crwdns1005:0crwdne1005:0', ], 'edit' => [ - 'title' => 'crwdns571:0crwdne571:0', - 'success' => 'crwdns688:0crwdne688:0', - 'failure' => 'crwdns689:0crwdne689:0', + 'title' => 'crwdns1006:0crwdne1006:0', + 'success' => 'crwdns1007:0crwdne1007:0', + 'failure' => 'crwdns1008:0crwdne1008:0', ], 'delete' => [ - 'success' => 'crwdns645:0crwdne645:0', - 'failure' => 'crwdns690:0crwdne690:0', + 'success' => 'crwdns1009:0crwdne1009:0', + 'failure' => 'crwdns1010:0crwdne1010:0', ], ], ], // Metrics 'metrics' => [ - 'metrics' => 'crwdns178:0crwdne178:0', + 'metrics' => 'crwdns1011:0crwdne1011:0', 'add' => [ - 'title' => 'crwdns572:0crwdne572:0', - 'message' => 'crwdns647:0crwdne647:0', - 'success' => 'crwdns691:0crwdne691:0', - 'failure' => 'crwdns692:0crwdne692:0', + 'title' => 'crwdns1012:0crwdne1012:0', + 'message' => 'crwdns1013:0crwdne1013:0', + 'success' => 'crwdns1014:0crwdne1014:0', + 'failure' => 'crwdns1015:0crwdne1015:0', ], 'edit' => [ - 'title' => 'crwdns573:0crwdne573:0', - 'success' => 'crwdns693:0crwdne693:0', - 'failure' => 'crwdns694:0crwdne694:0', + 'title' => 'crwdns1016:0crwdne1016:0', + 'success' => 'crwdns1017:0crwdne1017:0', + 'failure' => 'crwdns1018:0crwdne1018:0', ], 'delete' => [ - 'success' => 'crwdns648:0crwdne648:0', - 'failure' => 'crwdns695:0crwdne695:0', + 'success' => 'crwdns1019:0crwdne1019:0', + 'failure' => 'crwdns1020:0crwdne1020:0', ], ], // Subscribers 'subscribers' => [ - 'subscribers' => 'crwdns522:0crwdne522:0', - 'description' => 'crwdns696:0crwdne696:0', - 'verified' => 'crwdns524:0crwdne524:0', - 'not_verified' => 'crwdns525:0crwdne525:0', - 'subscriber' => 'crwdns697:0crwdne697:0', - 'no_subscriptions' => 'crwdns698:0crwdne698:0', - 'add' => [ - 'title' => 'crwdns574:0crwdne574:0', - 'success' => 'crwdns527:0crwdne527:0', - 'failure' => 'crwdns699:0crwdne699:0', - 'help' => 'crwdns724:0crwdne724:0', + 'subscribers' => 'crwdns1021:0crwdne1021:0', + 'description' => 'crwdns1022:0crwdne1022:0', + 'description_disabled' => 'crwdns1420:0crwdne1420:0', + 'verified' => 'crwdns1023:0crwdne1023:0', + 'not_verified' => 'crwdns1024:0crwdne1024:0', + 'subscriber' => 'crwdns1025:0crwdne1025:0', + 'no_subscriptions' => 'crwdns1026:0crwdne1026:0', + 'global' => 'crwdns1421:0crwdne1421:0', + 'add' => [ + 'title' => 'crwdns1027:0crwdne1027:0', + 'success' => 'crwdns1028:0crwdne1028:0', + 'failure' => 'crwdns1029:0crwdne1029:0', + 'help' => 'crwdns1030:0crwdne1030:0', ], 'edit' => [ - 'title' => 'crwdns575:0crwdne575:0', - 'success' => 'crwdns530:0crwdne530:0', - 'failure' => 'crwdns700:0crwdne700:0', + 'title' => 'crwdns1031:0crwdne1031:0', + 'success' => 'crwdns1032:0crwdne1032:0', + 'failure' => 'crwdns1033:0crwdne1033:0', ], ], // Team 'team' => [ - 'team' => 'crwdns182:0crwdne182:0', - 'member' => 'crwdns336:0crwdne336:0', - 'profile' => 'crwdns337:0crwdne337:0', - 'description' => 'crwdns338:0crwdne338:0', + 'team' => 'crwdns1034:0crwdne1034:0', + 'member' => 'crwdns1035:0crwdne1035:0', + 'profile' => 'crwdns1036:0crwdne1036:0', + 'description' => 'crwdns1325:0crwdne1325:0', 'add' => [ - 'title' => 'crwdns576:0crwdne576:0', - 'success' => 'crwdns701:0crwdne701:0', - 'failure' => 'crwdns702:0crwdne702:0', + 'title' => 'crwdns1038:0crwdne1038:0', + 'success' => 'crwdns1039:0crwdne1039:0', + 'failure' => 'crwdns1040:0crwdne1040:0', ], 'edit' => [ - 'title' => 'crwdns578:0crwdne578:0', - 'success' => 'crwdns703:0crwdne703:0', - 'failure' => 'crwdns704:0crwdne704:0', + 'title' => 'crwdns1041:0crwdne1041:0', + 'success' => 'crwdns1042:0crwdne1042:0', + 'failure' => 'crwdns1043:0crwdne1043:0', ], 'delete' => [ - 'success' => 'crwdns579:0crwdne579:0', - 'failure' => 'crwdns705:0crwdne705:0', + 'success' => 'crwdns1044:0crwdne1044:0', + 'failure' => 'crwdns1045:0crwdne1045:0', ], 'invite' => [ - 'title' => 'crwdns580:0crwdne580:0', - 'success' => 'crwdns581:0crwdne581:0', - 'failure' => 'crwdns706:0crwdne706:0', + 'title' => 'crwdns1046:0crwdne1046:0', + 'success' => 'crwdns1047:0crwdne1047:0', + 'failure' => 'crwdns1048:0crwdne1048:0', ], ], // Settings 'settings' => [ - 'settings' => 'crwdns192:0crwdne192:0', + 'settings' => 'crwdns1049:0crwdne1049:0', 'app-setup' => [ - 'app-setup' => 'crwdns345:0crwdne345:0', - 'images-only' => 'crwdns346:0crwdne346:0', - 'too-big' => 'crwdns347:0crwdne347:0', + 'app-setup' => 'crwdns1050:0crwdne1050:0', + 'images-only' => 'crwdns1051:0crwdne1051:0', + 'too-big' => 'crwdns1052:0crwdne1052:0', ], 'analytics' => [ - 'analytics' => 'crwdns583:0crwdne583:0', + 'analytics' => 'crwdns1053:0crwdne1053:0', + ], + 'log' => [ + 'log' => 'crwdns1054:0crwdne1054:0', ], 'localization' => [ - 'localization' => 'crwdns584:0crwdne584:0', + 'localization' => 'crwdns1055:0crwdne1055:0', ], 'customization' => [ - 'customization' => 'crwdns707:0crwdne707:0', - 'header' => 'crwdns708:0crwdne708:0', - 'footer' => 'crwdns709:0crwdne709:0', + 'customization' => 'crwdns1056:0crwdne1056:0', + 'header' => 'crwdns1057:0crwdne1057:0', + 'footer' => 'crwdns1058:0crwdne1058:0', + ], + 'mail' => [ + 'mail' => 'crwdns1059:0crwdne1059:0', + 'test' => 'crwdns1060:0crwdne1060:0', + 'email' => [ + 'subject' => 'crwdns1061:0crwdne1061:0', + 'body' => 'crwdns1062:0crwdne1062:0', + ], ], 'security' => [ - 'security' => 'crwdns348:0crwdne348:0', - 'two-factor' => 'crwdns474:0crwdne474:0', + 'security' => 'crwdns1063:0crwdne1063:0', + 'two-factor' => 'crwdns1064:0crwdne1064:0', ], 'stylesheet' => [ - 'stylesheet' => 'crwdns349:0crwdne349:0', + 'stylesheet' => 'crwdns1065:0crwdne1065:0', ], 'theme' => [ - 'theme' => 'crwdns350:0crwdne350:0', + 'theme' => 'crwdns1066:0crwdne1066:0', ], 'edit' => [ - 'success' => 'crwdns351:0crwdne351:0', - 'failure' => 'crwdns352:0crwdne352:0', + 'success' => 'crwdns1067:0crwdne1067:0', + 'failure' => 'crwdns1068:0crwdne1068:0', ], 'credits' => [ - 'credits' => 'crwdns765:0crwdne765:0', - 'contributors' => 'crwdns766:0crwdne766:0', - 'license' => 'crwdns767:0%20Ccrwdnd767:0%20Dcrwdne767:0', - 'backers-title' => 'crwdns768:0crwdne768:0', - 'backers' => 'crwdns769:0crwdne769:0', - 'thank-you' => 'crwdns770:0crwdne770:0', + 'credits' => 'crwdns1069:0crwdne1069:0', + 'contributors' => 'crwdns1070:0crwdne1070:0', + 'license' => 'crwdns1071:0%20Ccrwdnd1071:0%20crwdne1071:0', + 'backers-title' => 'crwdns1072:0crwdne1072:0', + 'backers' => 'crwdns1073:0crwdne1073:0', + 'thank-you' => 'crwdns1074:0crwdne1074:0', ], ], // Login 'login' => [ - 'login' => 'crwdns199:0crwdne199:0', - 'logged_in' => 'crwdns353:0crwdne353:0', - 'welcome' => 'crwdns354:0crwdne354:0', - 'two-factor' => 'crwdns355:0crwdne355:0', + 'login' => 'crwdns1075:0crwdne1075:0', + 'logged_in' => 'crwdns1076:0crwdne1076:0', + 'welcome' => 'crwdns1077:0crwdne1077:0', + 'two-factor' => 'crwdns1078:0crwdne1078:0', ], // Sidebar footer - 'help' => 'crwdns202:0crwdne202:0', - 'status_page' => 'crwdns203:0crwdne203:0', - 'logout' => 'crwdns204:0crwdne204:0', + 'help' => 'crwdns1079:0crwdne1079:0', + 'status_page' => 'crwdns1080:0crwdne1080:0', + 'logout' => 'crwdns1081:0crwdne1081:0', // Notifications 'notifications' => [ - 'notifications' => 'crwdns205:0crwdne205:0', - 'awesome' => 'crwdns356:0crwdne356:0', - 'whoops' => 'crwdns357:0crwdne357:0', + 'notifications' => 'crwdns1082:0crwdne1082:0', + 'awesome' => 'crwdns1083:0crwdne1083:0', + 'whoops' => 'crwdns1084:0crwdne1084:0', ], // Widgets 'widgets' => [ - 'support' => 'crwdns771:0crwdne771:0', - 'support_subtitle' => 'crwdns772:0crwdne772:0', - 'news' => 'crwdns773:0crwdne773:0', - 'news_subtitle' => 'crwdns774:0crwdne774:0', + 'support' => 'crwdns1085:0crwdne1085:0', + 'support_subtitle' => 'crwdns1086:0crwdne1086:0', + 'news' => 'crwdns1087:0crwdne1087:0', + 'news_subtitle' => 'crwdns1088:0crwdne1088:0', ], // Welcome modal 'welcome' => [ - 'welcome' => 'crwdns650:0crwdne650:0', - 'message' => 'crwdns359:0crwdne359:0', - 'close' => 'crwdns710:0crwdne710:0', + 'welcome' => 'crwdns1089:0crwdne1089:0', + 'message' => 'crwdns1090:0crwdne1090:0', + 'close' => 'crwdns1091:0crwdne1091:0', 'steps' => [ - 'component' => 'crwdns361:0crwdne361:0', - 'incident' => 'crwdns362:0crwdne362:0', - 'customize' => 'crwdns432:0crwdne432:0', - 'team' => 'crwdns433:0crwdne433:0', - 'api' => 'crwdns434:0crwdne434:0', - 'two-factor' => 'crwdns479:0crwdne479:0', + 'component' => 'crwdns1092:0crwdne1092:0', + 'incident' => 'crwdns1093:0crwdne1093:0', + 'customize' => 'crwdns1094:0crwdne1094:0', + 'team' => 'crwdns1095:0crwdne1095:0', + 'api' => 'crwdns1096:0crwdne1096:0', + 'two-factor' => 'crwdns1097:0crwdne1097:0', ], ], diff --git a/resources/lang/en-UD/forms.php b/resources/lang/en-UD/forms.php index d5cc70fe907..36c814b099f 100644 --- a/resources/lang/en-UD/forms.php +++ b/resources/lang/en-UD/forms.php @@ -13,175 +13,236 @@ // Setup form fields 'setup' => [ - 'email' => 'crwdns212:0crwdne212:0', - 'username' => 'crwdns374:0crwdne374:0', - 'password' => 'crwdns375:0crwdne375:0', - 'site_name' => 'crwdns376:0crwdne376:0', - 'site_domain' => 'crwdns377:0crwdne377:0', - 'site_timezone' => 'crwdns378:0crwdne378:0', - 'site_locale' => 'crwdns379:0crwdne379:0', - 'enable_google2fa' => 'crwdns380:0crwdne380:0', - 'cache_driver' => 'crwdns508:0crwdne508:0', - 'session_driver' => 'crwdns509:0crwdne509:0', + 'email' => 'crwdns1098:0crwdne1098:0', + 'username' => 'crwdns1099:0crwdne1099:0', + 'password' => 'crwdns1100:0crwdne1100:0', + 'site_name' => 'crwdns1101:0crwdne1101:0', + 'site_domain' => 'crwdns1102:0crwdne1102:0', + 'site_timezone' => 'crwdns1103:0crwdne1103:0', + 'site_locale' => 'crwdns1104:0crwdne1104:0', + 'enable_google2fa' => 'crwdns1105:0crwdne1105:0', + 'cache_driver' => 'crwdns1106:0crwdne1106:0', + 'queue_driver' => 'crwdns1107:0crwdne1107:0', + 'session_driver' => 'crwdns1108:0crwdne1108:0', + 'mail_driver' => 'crwdns1109:0crwdne1109:0', + 'mail_host' => 'crwdns1110:0crwdne1110:0', + 'mail_address' => 'crwdns1111:0crwdne1111:0', + 'mail_username' => 'crwdns1112:0crwdne1112:0', + 'mail_password' => 'crwdns1113:0crwdne1113:0', ], // Login form fields 'login' => [ - 'login' => 'crwdns651:0crwdne651:0', - 'email' => 'crwdns217:0crwdne217:0', - 'password' => 'crwdns381:0crwdne381:0', - '2fauth' => 'crwdns382:0crwdne382:0', - 'invalid' => 'crwdns652:0crwdne652:0', - 'invalid-token' => 'crwdns384:0crwdne384:0', - 'cookies' => 'crwdns480:0crwdne480:0', - 'rate-limit' => 'crwdns781:0crwdne781:0', + 'login' => 'crwdns1114:0crwdne1114:0', + 'email' => 'crwdns1115:0crwdne1115:0', + 'password' => 'crwdns1116:0crwdne1116:0', + '2fauth' => 'crwdns1117:0crwdne1117:0', + 'invalid' => 'crwdns1118:0crwdne1118:0', + 'invalid-token' => 'crwdns1119:0crwdne1119:0', + 'cookies' => 'crwdns1120:0crwdne1120:0', + 'rate-limit' => 'crwdns1121:0crwdne1121:0', + 'remember_me' => 'crwdns1122:0crwdne1122:0', ], // Incidents form fields 'incidents' => [ - 'name' => 'crwdns219:0crwdne219:0', - 'status' => 'crwdns385:0crwdne385:0', - 'component' => 'crwdns386:0crwdne386:0', - 'message' => 'crwdns387:0crwdne387:0', - 'message-help' => 'crwdns388:0crwdne388:0', - 'scheduled_at' => 'crwdns464:0crwdne464:0', - 'incident_time' => 'crwdns481:0crwdne481:0', - 'notify_subscribers' => 'crwdns585:0crwdne585:0', - 'visibility' => 'crwdns711:0crwdne711:0', - 'public' => 'crwdns483:0crwdne483:0', - 'logged_in_only' => 'crwdns586:0crwdne586:0', + 'name' => 'crwdns1123:0crwdne1123:0', + 'status' => 'crwdns1124:0crwdne1124:0', + 'component' => 'crwdns1125:0crwdne1125:0', + 'component_status' => 'crwdns1425:0crwdne1425:0', + 'message' => 'crwdns1126:0crwdne1126:0', + 'message-help' => 'crwdns1127:0crwdne1127:0', + 'occurred_at' => 'crwdns1128:0crwdne1128:0', + 'notify_subscribers' => 'crwdns1129:0crwdne1129:0', + 'notify_disabled' => 'crwdns1426:0crwdne1426:0', + 'visibility' => 'crwdns1130:0crwdne1130:0', + 'stick_status' => 'crwdns1131:0crwdne1131:0', + 'stickied' => 'crwdns1132:0crwdne1132:0', + 'not_stickied' => 'crwdns1133:0crwdne1133:0', + 'public' => 'crwdns1134:0crwdne1134:0', + 'logged_in_only' => 'crwdns1135:0crwdne1135:0', 'templates' => [ - 'name' => 'crwdns389:0crwdne389:0', - 'template' => 'crwdns390:0crwdne390:0', - 'twig' => 'crwdns653:0crwdne653:0', + 'name' => 'crwdns1136:0crwdne1136:0', + 'template' => 'crwdns1137:0crwdne1137:0', + 'twig' => 'crwdns1138:0crwdne1138:0', + ], + ], + + 'schedules' => [ + 'name' => 'crwdns1139:0crwdne1139:0', + 'status' => 'crwdns1140:0crwdne1140:0', + 'message' => 'crwdns1141:0crwdne1141:0', + 'message-help' => 'crwdns1142:0crwdne1142:0', + 'scheduled_at' => 'crwdns1143:0crwdne1143:0', + 'completed_at' => 'crwdns1144:0crwdne1144:0', + 'templates' => [ + 'name' => 'crwdns1145:0crwdne1145:0', + 'template' => 'crwdns1146:0crwdne1146:0', + 'twig' => 'crwdns1147:0crwdne1147:0', ], ], // Components form fields 'components' => [ - 'name' => 'crwdns225:0crwdne225:0', - 'status' => 'crwdns391:0crwdne391:0', - 'group' => 'crwdns392:0crwdne392:0', - 'description' => 'crwdns393:0crwdne393:0', - 'link' => 'crwdns394:0crwdne394:0', - 'tags' => 'crwdns395:0crwdne395:0', - 'tags-help' => 'crwdns396:0crwdne396:0', - 'enabled' => 'crwdns587:0crwdne587:0', + 'name' => 'crwdns1148:0crwdne1148:0', + 'status' => 'crwdns1149:0crwdne1149:0', + 'group' => 'crwdns1150:0crwdne1150:0', + 'description' => 'crwdns1151:0crwdne1151:0', + 'link' => 'crwdns1152:0crwdne1152:0', + 'tags' => 'crwdns1153:0crwdne1153:0', + 'tags-help' => 'crwdns1154:0crwdne1154:0', + 'enabled' => 'crwdns1155:0crwdne1155:0', 'groups' => [ - 'name' => 'crwdns397:0crwdne397:0', - 'collapsing' => 'crwdns712:0crwdne712:0', - 'visible' => 'crwdns713:0crwdne713:0', - 'collapsed' => 'crwdns714:0crwdne714:0', - 'collapsed_incident' => 'crwdns715:0crwdne715:0', + 'name' => 'crwdns1156:0crwdne1156:0', + 'collapsing' => 'crwdns1157:0crwdne1157:0', + 'visible' => 'crwdns1158:0crwdne1158:0', + 'collapsed' => 'crwdns1159:0crwdne1159:0', + 'collapsed_incident' => 'crwdns1160:0crwdne1160:0', + 'visibility' => 'crwdns1161:0crwdne1161:0', + 'visibility_public' => 'crwdns1162:0crwdne1162:0', + 'visibility_authenticated' => 'crwdns1163:0crwdne1163:0', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'crwdns1164:0crwdne1164:0', + 'description' => 'crwdns1165:0crwdne1165:0', + 'start_at' => 'crwdns1166:0crwdne1166:0', + 'timezone' => 'crwdns1167:0crwdne1167:0', + 'schedule_frequency' => 'crwdns1168:0crwdne1168:0', + 'completion_latency' => 'crwdns1169:0crwdne1169:0', + 'group' => 'crwdns1170:0crwdne1170:0', + 'active' => 'crwdns1171:0crwdne1171:0', + 'groups' => [ + 'name' => 'crwdns1172:0crwdne1172:0', ], ], // Metric form fields 'metrics' => [ - 'name' => 'crwdns465:0crwdne465:0', - 'suffix' => 'crwdns466:0crwdne466:0', - 'description' => 'crwdns467:0crwdne467:0', - 'description-help' => 'crwdns468:0crwdne468:0', - 'display-chart' => 'crwdns469:0crwdne469:0', - 'default-value' => 'crwdns588:0crwdne588:0', - 'calc_type' => 'crwdns589:0crwdne589:0', - 'type_sum' => 'crwdns476:0crwdne476:0', - 'type_avg' => 'crwdns477:0crwdne477:0', - 'places' => 'crwdns590:0crwdne590:0', - 'default_view' => 'crwdns655:0crwdne655:0', - 'threshold' => 'crwdns725:0crwdne725:0', + 'name' => 'crwdns1173:0crwdne1173:0', + 'suffix' => 'crwdns1174:0crwdne1174:0', + 'description' => 'crwdns1175:0crwdne1175:0', + 'description-help' => 'crwdns1176:0crwdne1176:0', + 'display-chart' => 'crwdns1177:0crwdne1177:0', + 'default-value' => 'crwdns1178:0crwdne1178:0', + 'calc_type' => 'crwdns1179:0crwdne1179:0', + 'type_sum' => 'crwdns1180:0crwdne1180:0', + 'type_avg' => 'crwdns1181:0crwdne1181:0', + 'places' => 'crwdns1182:0crwdne1182:0', + 'default_view' => 'crwdns1183:0crwdne1183:0', + 'threshold' => 'crwdns1184:0crwdne1184:0', + 'visibility' => 'crwdns1185:0crwdne1185:0', + 'visibility_authenticated' => 'crwdns1186:0crwdne1186:0', + 'visibility_public' => 'crwdns1187:0crwdne1187:0', + 'visibility_hidden' => 'crwdns1188:0crwdne1188:0', 'points' => [ - 'value' => 'crwdns471:0crwdne471:0', + 'value' => 'crwdns1189:0crwdne1189:0', ], ], // Settings 'settings' => [ - /// Application setup + // Application setup 'app-setup' => [ - 'site-name' => 'crwdns716:0crwdne716:0', - 'site-url' => 'crwdns398:0crwdne398:0', - 'display-graphs' => 'crwdns472:0crwdne472:0', - 'about-this-page' => 'crwdns402:0crwdne402:0', - 'days-of-incidents' => 'crwdns403:0crwdne403:0', - 'banner' => 'crwdns717:0crwdne717:0', - 'banner-help' => 'crwdns405:0crwdne405:0', - 'subscribers' => 'crwdns513:0crwdne513:0', - 'automatic_localization' => 'crwdns726:0crwdne726:0', + 'site-name' => 'crwdns1190:0crwdne1190:0', + 'site-url' => 'crwdns1191:0crwdne1191:0', + 'display-graphs' => 'crwdns1192:0crwdne1192:0', + 'about-this-page' => 'crwdns1193:0crwdne1193:0', + 'days-of-incidents' => 'crwdns1194:0crwdne1194:0', + 'time_before_refresh' => 'crwdns1434:0crwdne1434:0', + 'major_outage_rate' => 'crwdns1444:0crwdne1444:0', + 'banner' => 'crwdns1195:0crwdne1195:0', + 'banner-help' => 'crwdns1435:0crwdne1435:0', + 'subscribers' => 'crwdns1197:0crwdne1197:0', + 'suppress_notifications_in_maintenance' => 'crwdns1427:0crwdne1427:0', + 'skip_subscriber_verification' => 'crwdns1198:0crwdne1198:0', + 'automatic_localization' => 'crwdns1199:0crwdne1199:0', + 'enable_external_dependencies' => 'crwdns1200:0crwdne1200:0', + 'show_timezone' => 'crwdns1436:0crwdne1436:0', + 'only_disrupted_days' => 'crwdns1202:0crwdne1202:0', ], 'analytics' => [ - 'analytics_google' => 'crwdns591:0crwdne591:0', - 'analytics_gosquared' => 'crwdns592:0crwdne592:0', - 'analytics_piwik_url' => 'crwdns593:0crwdne593:0', - 'analytics_piwik_siteid' => 'crwdns594:0crwdne594:0', + 'analytics_google' => 'crwdns1203:0crwdne1203:0', + 'analytics_gosquared' => 'crwdns1204:0crwdne1204:0', + 'analytics_piwik_url' => 'crwdns1205:0crwdne1205:0', + 'analytics_piwik_siteid' => 'crwdns1206:0crwdne1206:0', ], 'localization' => [ - 'site-timezone' => 'crwdns595:0crwdne595:0', - 'site-locale' => 'crwdns596:0crwdne596:0', - 'date-format' => 'crwdns597:0crwdne597:0', - 'incident-date-format' => 'crwdns598:0crwdne598:0', + 'site-timezone' => 'crwdns1207:0crwdne1207:0', + 'site-locale' => 'crwdns1208:0crwdne1208:0', + 'date-format' => 'crwdns1209:0crwdne1209:0', + 'incident-date-format' => 'crwdns1210:0crwdne1210:0', ], 'security' => [ - 'allowed-domains' => 'crwdns599:0crwdne599:0', - 'allowed-domains-help' => 'crwdns408:0crwdne408:0', + 'allowed-domains' => 'crwdns1211:0crwdne1211:0', + 'allowed-domains-help' => 'crwdns1212:0crwdne1212:0', + 'always-authenticate' => 'crwdns1445:0crwdne1445:0', + 'always-authenticate-help' => 'crwdns1446:0crwdne1446:0', ], 'stylesheet' => [ - 'custom-css' => 'crwdns718:0crwdne718:0', + 'custom-css' => 'crwdns1213:0crwdne1213:0', ], 'theme' => [ - 'background-color' => 'crwdns719:0crwdne719:0', - 'background-fills' => 'crwdns600:0crwdne600:0', - 'banner-background-color' => 'crwdns601:0crwdne601:0', - 'banner-padding' => 'crwdns602:0crwdne602:0', - 'fullwidth-banner' => 'crwdns603:0crwdne603:0', - 'text-color' => 'crwdns720:0crwdne720:0', - 'dashboard-login' => 'crwdns604:0crwdne604:0', - 'reds' => 'crwdns605:0crwdne605:0', - 'blues' => 'crwdns606:0crwdne606:0', - 'greens' => 'crwdns607:0crwdne607:0', - 'yellows' => 'crwdns608:0crwdne608:0', - 'oranges' => 'crwdns609:0crwdne609:0', - 'metrics' => 'crwdns610:0crwdne610:0', - 'links' => 'crwdns611:0crwdne611:0', + 'background-color' => 'crwdns1214:0crwdne1214:0', + 'background-fills' => 'crwdns1215:0crwdne1215:0', + 'banner-background-color' => 'crwdns1216:0crwdne1216:0', + 'banner-padding' => 'crwdns1217:0crwdne1217:0', + 'fullwidth-banner' => 'crwdns1442:0crwdne1442:0', + 'text-color' => 'crwdns1219:0crwdne1219:0', + 'dashboard-login' => 'crwdns1220:0crwdne1220:0', + 'reds' => 'crwdns1221:0crwdne1221:0', + 'blues' => 'crwdns1222:0crwdne1222:0', + 'greens' => 'crwdns1223:0crwdne1223:0', + 'yellows' => 'crwdns1224:0crwdne1224:0', + 'oranges' => 'crwdns1225:0crwdne1225:0', + 'metrics' => 'crwdns1226:0crwdne1226:0', + 'links' => 'crwdns1227:0crwdne1227:0', ], ], 'user' => [ - 'username' => 'crwdns244:0crwdne244:0', - 'email' => 'crwdns412:0crwdne412:0', - 'password' => 'crwdns413:0crwdne413:0', - 'api-token' => 'crwdns414:0crwdne414:0', - 'api-token-help' => 'crwdns436:0crwdne436:0', - 'gravatar' => 'crwdns612:0crwdne612:0', - 'user_level' => 'crwdns613:0crwdne613:0', + 'username' => 'crwdns1228:0crwdne1228:0', + 'email' => 'crwdns1229:0crwdne1229:0', + 'password' => 'crwdns1230:0crwdne1230:0', + 'api-token' => 'crwdns1231:0crwdne1231:0', + 'api-token-help' => 'crwdns1232:0crwdne1232:0', + 'gravatar' => 'crwdns1233:0crwdne1233:0', + 'user_level' => 'crwdns1234:0crwdne1234:0', 'levels' => [ - 'admin' => 'crwdns614:0crwdne614:0', - 'user' => 'crwdns615:0crwdne615:0', + 'admin' => 'crwdns1235:0crwdne1235:0', + 'user' => 'crwdns1236:0crwdne1236:0', ], '2fa' => [ - 'help' => 'crwdns416:0crwdne416:0', + 'help' => 'crwdns1237:0crwdne1237:0', ], 'team' => [ - 'description' => 'crwdns616:0crwdne616:0', - 'email' => 'crwdns617:0crwdne617:0', + 'description' => 'crwdns1238:0crwdne1238:0', + 'email' => 'crwdns1423:0crwdne1423:0', ], ], + 'general' => [ + 'timezone' => 'crwdns1240:0crwdne1240:0', + ], + // Buttons - 'add' => 'crwdns249:0crwdne249:0', - 'save' => 'crwdns250:0crwdne250:0', - 'update' => 'crwdns251:0crwdne251:0', - 'create' => 'crwdns252:0crwdne252:0', - 'edit' => 'crwdns253:0crwdne253:0', - 'delete' => 'crwdns254:0crwdne254:0', - 'submit' => 'crwdns255:0crwdne255:0', - 'cancel' => 'crwdns256:0crwdne256:0', - 'remove' => 'crwdns257:0crwdne257:0', - 'invite' => 'crwdns618:0crwdne618:0', - 'signup' => 'crwdns619:0crwdne619:0', + 'add' => 'crwdns1241:0crwdne1241:0', + 'save' => 'crwdns1242:0crwdne1242:0', + 'update' => 'crwdns1243:0crwdne1243:0', + 'create' => 'crwdns1244:0crwdne1244:0', + 'edit' => 'crwdns1245:0crwdne1245:0', + 'delete' => 'crwdns1246:0crwdne1246:0', + 'submit' => 'crwdns1247:0crwdne1247:0', + 'cancel' => 'crwdns1248:0crwdne1248:0', + 'remove' => 'crwdns1249:0crwdne1249:0', + 'invite' => 'crwdns1250:0crwdne1250:0', + 'signup' => 'crwdns1251:0crwdne1251:0', + 'manage_updates' => 'crwdns1424:0crwdne1424:0', // Other - 'optional' => 'crwdns417:0crwdne417:0', + 'optional' => 'crwdns1252:0crwdne1252:0', ]; diff --git a/resources/lang/en-UD/notifications.php b/resources/lang/en-UD/notifications.php new file mode 100644 index 00000000000..5bbb05e7445 --- /dev/null +++ b/resources/lang/en-UD/notifications.php @@ -0,0 +1,108 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'crwdns1354:0crwdne1354:0', + 'greeting' => 'crwdns1355:0crwdne1355:0', + 'content' => 'crwdns1356:0crwdne1356:0', + 'action' => 'crwdns1357:0crwdne1357:0', + ], + 'slack' => [ + 'title' => 'crwdns1358:0crwdne1358:0', + 'content' => 'crwdns1359:0crwdne1359:0', + ], + 'sms' => [ + 'content' => 'crwdns1360:0crwdne1360:0', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'crwdns1361:0crwdne1361:0', + 'greeting' => 'crwdns1362:0crwdne1362:0', + 'content' => 'crwdns1363:0crwdne1363:0', + 'action' => 'crwdns1364:0crwdne1364:0', + ], + 'slack' => [ + 'title' => 'crwdns1365:0crwdne1365:0', + 'content' => 'crwdns1366:0crwdne1366:0', + ], + 'sms' => [ + 'content' => 'crwdns1367:0crwdne1367:0', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'crwdns1368:0crwdne1368:0', + 'content' => 'crwdns1369:0crwdne1369:0', + 'title' => 'crwdns1370:0crwdne1370:0', + 'action' => 'crwdns1371:0crwdne1371:0', + ], + 'slack' => [ + 'title' => 'crwdns1372:0crwdne1372:0', + 'content' => 'crwdns1373:0crwdne1373:0', + ], + 'sms' => [ + 'content' => 'crwdns1374:0crwdne1374:0', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'crwdns1375:0crwdne1375:0', + 'content' => 'crwdns1376:0crwdne1376:0', + 'title' => 'crwdns1377:0crwdne1377:0', + 'action' => 'crwdns1378:0crwdne1378:0', + ], + 'slack' => [ + 'title' => 'crwdns1379:0crwdne1379:0', + 'content' => 'crwdns1380:0crwdne1380:0', + ], + 'sms' => [ + 'content' => 'crwdns1381:0crwdne1381:0', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'crwdns1382:0crwdne1382:0', + 'content' => 'crwdns1383:0crwdne1383:0', + 'title' => 'crwdns1384:0crwdne1384:0', + 'action' => 'crwdns1385:0crwdne1385:0', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'crwdns1386:0crwdne1386:0', + 'content' => 'crwdns1387:0crwdne1387:0', + 'title' => 'crwdns1388:0crwdne1388:0', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'crwdns1389:0crwdne1389:0', + 'content' => 'crwdns1390:0crwdne1390:0', + 'title' => 'crwdns1391:0crwdne1391:0', + 'action' => 'crwdns1392:0crwdne1392:0', + ], + ], + ], +]; diff --git a/resources/lang/en-UD/pagination.php b/resources/lang/en-UD/pagination.php index 08fa787b25c..325882060d0 100644 --- a/resources/lang/en-UD/pagination.php +++ b/resources/lang/en-UD/pagination.php @@ -22,7 +22,7 @@ | */ - 'previous' => 'crwdns89:0crwdne89:0', - 'next' => 'crwdns90:0crwdne90:0', + 'previous' => 'crwdns1393:0crwdne1393:0', + 'next' => 'crwdns1394:0crwdne1394:0', ]; diff --git a/resources/lang/en-UD/setup.php b/resources/lang/en-UD/setup.php index 754a9d1cabb..4f7bbbeed14 100644 --- a/resources/lang/en-UD/setup.php +++ b/resources/lang/en-UD/setup.php @@ -10,14 +10,14 @@ */ return [ - 'setup' => 'crwdns258:0crwdne258:0', - 'title' => 'crwdns259:0crwdne259:0', - 'service_details' => 'crwdns260:0crwdne260:0', - 'env_setup' => 'crwdns514:0crwdne514:0', - 'status_page_setup' => 'crwdns261:0crwdne261:0', - 'show_support' => 'crwdns488:0crwdne488:0', - 'admin_account' => 'crwdns263:0crwdne263:0', - 'complete_setup' => 'crwdns264:0crwdne264:0', - 'completed' => 'crwdns291:0crwdne291:0', - 'finish_setup' => 'crwdns292:0crwdne292:0', + 'setup' => 'crwdns1255:0crwdne1255:0', + 'title' => 'crwdns1256:0crwdne1256:0', + 'service_details' => 'crwdns1257:0crwdne1257:0', + 'env_setup' => 'crwdns1258:0crwdne1258:0', + 'status_page_setup' => 'crwdns1259:0crwdne1259:0', + 'show_support' => 'crwdns1260:0crwdne1260:0', + 'admin_account' => 'crwdns1261:0crwdne1261:0', + 'complete_setup' => 'crwdns1262:0crwdne1262:0', + 'completed' => 'crwdns1263:0crwdne1263:0', + 'finish_setup' => 'crwdns1264:0crwdne1264:0', ]; diff --git a/resources/lang/en-UD/validation.php b/resources/lang/en-UD/validation.php index 0dc3076b34a..8a727c3857d 100644 --- a/resources/lang/en-UD/validation.php +++ b/resources/lang/en-UD/validation.php @@ -22,72 +22,72 @@ | */ - 'accepted' => 'crwdns96:0crwdne96:0', - 'active_url' => 'crwdns97:0crwdne97:0', - 'after' => 'crwdns98:0crwdne98:0', - 'alpha' => 'crwdns99:0crwdne99:0', - 'alpha_dash' => 'crwdns100:0crwdne100:0', - 'alpha_num' => 'crwdns101:0crwdne101:0', - 'array' => 'crwdns102:0crwdne102:0', - 'before' => 'crwdns103:0crwdne103:0', + 'accepted' => 'crwdns1265:0crwdne1265:0', + 'active_url' => 'crwdns1266:0crwdne1266:0', + 'after' => 'crwdns1267:0crwdne1267:0', + 'alpha' => 'crwdns1268:0crwdne1268:0', + 'alpha_dash' => 'crwdns1269:0crwdne1269:0', + 'alpha_num' => 'crwdns1270:0crwdne1270:0', + 'array' => 'crwdns1271:0crwdne1271:0', + 'before' => 'crwdns1272:0crwdne1272:0', 'between' => [ - 'numeric' => 'crwdns727:0crwdne727:0', - 'file' => 'crwdns728:0crwdne728:0', - 'string' => 'crwdns729:0crwdne729:0', - 'array' => 'crwdns420:0crwdne420:0', + 'numeric' => 'crwdns1273:0crwdne1273:0', + 'file' => 'crwdns1274:0crwdne1274:0', + 'string' => 'crwdns1275:0crwdne1275:0', + 'array' => 'crwdns1276:0crwdne1276:0', ], - 'boolean' => 'crwdns730:0crwdne730:0', - 'confirmed' => 'crwdns731:0crwdne731:0', - 'date' => 'crwdns732:0crwdne732:0', - 'date_format' => 'crwdns733:0crwdne733:0', - 'different' => 'crwdns734:0crwdne734:0', - 'digits' => 'crwdns735:0crwdne735:0', - 'digits_between' => 'crwdns736:0crwdne736:0', - 'email' => 'crwdns737:0crwdne737:0', - 'exists' => 'crwdns738:0crwdne738:0', - 'distinct' => 'crwdns739:0crwdne739:0', - 'filled' => 'crwdns740:0crwdne740:0', - 'image' => 'crwdns117:0crwdne117:0', - 'in' => 'crwdns741:0crwdne741:0', - 'in_array' => 'crwdns742:0crwdne742:0', - 'integer' => 'crwdns743:0crwdne743:0', - 'ip' => 'crwdns744:0crwdne744:0', - 'json' => 'crwdns621:0crwdne621:0', + 'boolean' => 'crwdns1277:0crwdne1277:0', + 'confirmed' => 'crwdns1278:0crwdne1278:0', + 'date' => 'crwdns1279:0crwdne1279:0', + 'date_format' => 'crwdns1280:0crwdne1280:0', + 'different' => 'crwdns1281:0crwdne1281:0', + 'digits' => 'crwdns1282:0crwdne1282:0', + 'digits_between' => 'crwdns1283:0crwdne1283:0', + 'email' => 'crwdns1284:0crwdne1284:0', + 'exists' => 'crwdns1285:0crwdne1285:0', + 'distinct' => 'crwdns1286:0crwdne1286:0', + 'filled' => 'crwdns1287:0crwdne1287:0', + 'image' => 'crwdns1288:0crwdne1288:0', + 'in' => 'crwdns1289:0crwdne1289:0', + 'in_array' => 'crwdns1290:0crwdne1290:0', + 'integer' => 'crwdns1291:0crwdne1291:0', + 'ip' => 'crwdns1292:0crwdne1292:0', + 'json' => 'crwdns1293:0crwdne1293:0', 'max' => [ - 'numeric' => 'crwdns745:0crwdne745:0', - 'file' => 'crwdns746:0crwdne746:0', - 'string' => 'crwdns747:0crwdne747:0', - 'array' => 'crwdns423:0crwdne423:0', + 'numeric' => 'crwdns1294:0crwdne1294:0', + 'file' => 'crwdns1295:0crwdne1295:0', + 'string' => 'crwdns1296:0crwdne1296:0', + 'array' => 'crwdns1297:0crwdne1297:0', ], - 'mimes' => 'crwdns748:0crwdne748:0', + 'mimes' => 'crwdns1298:0crwdne1298:0', 'min' => [ - 'numeric' => 'crwdns749:0crwdne749:0', - 'file' => 'crwdns424:0crwdne424:0', - 'string' => 'crwdns750:0crwdne750:0', - 'array' => 'crwdns751:0crwdne751:0', + 'numeric' => 'crwdns1299:0crwdne1299:0', + 'file' => 'crwdns1300:0crwdne1300:0', + 'string' => 'crwdns1301:0crwdne1301:0', + 'array' => 'crwdns1302:0crwdne1302:0', ], - 'not_in' => 'crwdns752:0crwdne752:0', - 'numeric' => 'crwdns753:0crwdne753:0', - 'present' => 'crwdns754:0crwdne754:0', - 'regex' => 'crwdns755:0crwdne755:0', - 'required' => 'crwdns756:0crwdne756:0', - 'required_if' => 'crwdns757:0crwdne757:0', - 'required_unless' => 'crwdns656:0crwdne656:0', - 'required_with' => 'crwdns758:0crwdne758:0', - 'required_with_all' => 'crwdns136:0crwdne136:0', - 'required_without' => 'crwdns759:0crwdne759:0', - 'required_without_all' => 'crwdns760:0crwdne760:0', - 'same' => 'crwdns761:0crwdne761:0', + 'not_in' => 'crwdns1303:0crwdne1303:0', + 'numeric' => 'crwdns1304:0crwdne1304:0', + 'present' => 'crwdns1305:0crwdne1305:0', + 'regex' => 'crwdns1306:0crwdne1306:0', + 'required' => 'crwdns1307:0crwdne1307:0', + 'required_if' => 'crwdns1308:0crwdne1308:0', + 'required_unless' => 'crwdns1309:0crwdne1309:0', + 'required_with' => 'crwdns1310:0crwdne1310:0', + 'required_with_all' => 'crwdns1311:0crwdne1311:0', + 'required_without' => 'crwdns1312:0crwdne1312:0', + 'required_without_all' => 'crwdns1313:0crwdne1313:0', + 'same' => 'crwdns1314:0crwdne1314:0', 'size' => [ - 'numeric' => 'crwdns762:0crwdne762:0', - 'file' => 'crwdns427:0crwdne427:0', - 'string' => 'crwdns428:0crwdne428:0', - 'array' => 'crwdns763:0crwdne763:0', + 'numeric' => 'crwdns1315:0crwdne1315:0', + 'file' => 'crwdns1316:0crwdne1316:0', + 'string' => 'crwdns1317:0crwdne1317:0', + 'array' => 'crwdns1318:0crwdne1318:0', ], - 'string' => 'crwdns764:0crwdne764:0', - 'timezone' => 'crwdns146:0crwdne146:0', - 'unique' => 'crwdns144:0crwdne144:0', - 'url' => 'crwdns145:0crwdne145:0', + 'string' => 'crwdns1319:0crwdne1319:0', + 'timezone' => 'crwdns1320:0crwdne1320:0', + 'unique' => 'crwdns1321:0crwdne1321:0', + 'url' => 'crwdns1322:0crwdne1322:0', /* |-------------------------------------------------------------------------- @@ -102,7 +102,7 @@ 'custom' => [ 'attribute-name' => [ - 'rule-name' => 'crwdns147:0crwdne147:0', + 'rule-name' => 'crwdns1323:0crwdne1323:0', ], ], diff --git a/resources/lang/en-US/cachet.php b/resources/lang/en-US/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/en-US/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/en-US/dashboard.php b/resources/lang/en-US/dashboard.php new file mode 100644 index 00000000000..a07a2e4a276 --- /dev/null +++ b/resources/lang/en-US/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome Back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new Status page!', + 'message' => 'Your status page is almost ready! You might want to configure these extra settings', + 'close' => 'Take me straight to my dashboard', + 'steps' => [ + 'component' => 'Create components', + 'incident' => 'Create incidents', + 'customize' => 'Customize', + 'team' => 'Add users', + 'api' => 'Generate API token', + 'two-factor' => 'Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/en-US/forms.php b/resources/lang/en-US/forms.php new file mode 100644 index 00000000000..c3630ab2c01 --- /dev/null +++ b/resources/lang/en-US/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background Color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text Color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/en-US/notifications.php b/resources/lang/en-US/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/en-US/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/en-US/pagination.php b/resources/lang/en-US/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/en-US/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/en-US/setup.php b/resources/lang/en-US/setup.php new file mode 100644 index 00000000000..044cf2e2aa4 --- /dev/null +++ b/resources/lang/en-US/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Setup Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/en-US/validation.php b/resources/lang/en-US/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/en-US/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/en/cachet.php b/resources/lang/en/cachet.php index 3cb3070fc9a..cb24fc10e7c 100644 --- a/resources/lang/en/cachet.php +++ b/resources/lang/en/cachet.php @@ -14,6 +14,7 @@ 'components' => [ 'last_updated' => 'Last updated :timestamp', 'status' => [ + 0 => 'Unknown', 1 => 'Operational', 2 => 'Performance Issues', 3 => 'Partial Outage', @@ -22,18 +23,20 @@ 'group' => [ 'other' => 'Other Components', ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', ], // Incidents 'incidents' => [ - 'none' => 'No incidents reported', - 'past' => 'Past Incidents', - 'previous_week' => 'Previous Week', - 'next_week' => 'Next Week', - 'scheduled' => 'Scheduled Maintenance', - 'scheduled_at' => ', scheduled :timestamp', - 'status' => [ - 0 => 'Scheduled', // TODO: Hopefully remove this. + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ 1 => 'Investigating', 2 => 'Identified', 3 => 'Watching', @@ -41,11 +44,20 @@ ], ], + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + // Service Status 'service' => [ - 'good' => '[0,1] System operational|[2,Inf] All systems are operational', - 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', ], 'api' => [ @@ -65,47 +77,29 @@ // Subscriber 'subscriber' => [ - 'subscribe' => 'Subscribe to get the most recent updates', - 'button' => 'Subscribe', - 'manage' => [ - 'no_subscriptions' => 'You\'re currently subscribed to all updates.', - 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', ], 'email' => [ - 'subscribe' => 'Subscribe to email updates.', - 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', - 'verified' => 'Your email subscription has been confirmed. Thank you!', - 'manage' => 'Manage your subscription', - 'unsubscribe' => 'Unsubscribe from email updates.', - 'unsubscribed' => 'Your email subscription has been cancelled.', - 'failure' => 'Something went wrong with the subscription.', - 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', - 'verify' => [ - 'text' => "Please confirm your email subscription to :app_name status updates.\n:link", - 'html' => '

Please confirm your email subscription to :app_name status updates.

', - 'button' => 'Confirm Subscription', - ], - 'maintenance' => [ - 'subject' => '[Maintenance Scheduled] :name', - ], - 'incident' => [ - 'subject' => '[New Incident] :status: :name', - ], - 'component' => [ - 'subject' => 'Component Status Update', - 'text' => 'The component :component_name has seen a status change. The component is now at :component_human_status.\nThank you, :app_name', - 'html' => '

The component :component_name has seen a status change. The component is now at :component_human_status.

Thank you, :app_name

', - 'tooltip-title' => 'Subscribe to notifications for :component_name.', - ], - ], - ], - - 'users' => [ - 'email' => [ - 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', - ], + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', ], ], @@ -132,10 +126,20 @@ ], ], + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + // Other 'home' => 'Home', - 'description' => 'Stay up to date with the latest service updates from :app.', 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', 'about_this_site' => 'About This Site', 'rss-feed' => 'RSS', 'atom-feed' => 'Atom', diff --git a/resources/lang/en/dashboard.php b/resources/lang/en/dashboard.php index 6b78f749eca..7dc9af669de 100644 --- a/resources/lang/en/dashboard.php +++ b/resources/lang/en/dashboard.php @@ -11,15 +11,31 @@ return [ - 'dashboard' => 'Dashboard', + 'dashboard' => 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', // Incidents 'incidents' => [ - 'title' => 'Incidents & Schedule', + 'title' => 'Incidents & Maintenance', 'incidents' => 'Incidents', - 'logged' => '{0} There are no incidents, good work.|You have logged one incident.|You have reported :count incidents.', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', 'incident-create-template' => 'Create Template', 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', 'add' => [ 'title' => 'Report an incident', 'success' => 'Incident added.', @@ -40,7 +56,7 @@ 'title' => 'Incident Templates', 'add' => [ 'title' => 'Create an incident template', - 'message' => 'You should add an incident template.', + 'message' => 'Create your first incident template.', 'success' => 'Your new incident template has been created.', 'failure' => 'Something went wrong with the incident template.', ], @@ -58,22 +74,22 @@ // Incident Maintenance 'schedule' => [ - 'schedule' => 'Scheduled Maintenance', - 'logged' => '{0} There are no schedules, good work.|You have logged one schedule.|You have reported :count schedules.', + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', 'scheduled_at' => 'Scheduled at :timestamp', 'add' => [ - 'title' => 'Add Scheduled Maintenance', - 'success' => 'Schedule added.', - 'failure' => 'Something went wrong adding the schedule, please try again.', + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', ], 'edit' => [ - 'title' => 'Edit Scheduled Maintenance', - 'success' => 'Schedule has been updated!', - 'failure' => 'Something went wrong editing the schedule, please try again.', + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', ], 'delete' => [ - 'success' => 'The scheduled maintenance has been deleted and will not show on your status page.', - 'failure' => 'The scheduled maintenance could not be deleted, please try again.', + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', ], ], @@ -140,13 +156,15 @@ ], // Subscribers 'subscribers' => [ - 'subscribers' => 'Subscribers', - 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', - 'verified' => 'Verified', - 'not_verified' => 'Not verified', - 'subscriber' => ':email, subscribed :date', - 'no_subscriptions' => 'Subscribed to all updates', - 'add' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ 'title' => 'Add a new subscriber', 'success' => 'Subscriber has been added!', 'failure' => 'Something went wrong adding the subscriber, please try again.', @@ -164,7 +182,7 @@ 'team' => 'Team', 'member' => 'Member', 'profile' => 'Profile', - 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', 'add' => [ 'title' => 'Add a new team member', 'success' => 'Team member added.', @@ -197,6 +215,9 @@ 'analytics' => [ 'analytics' => 'Analytics', ], + 'log' => [ + 'log' => 'Log', + ], 'localization' => [ 'localization' => 'Localization', ], @@ -205,6 +226,14 @@ 'header' => 'Custom Header HTML', 'footer' => 'Custom Footer HTML', ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], 'security' => [ 'security' => 'Security', 'two-factor' => 'Users without two-factor authentication', @@ -233,7 +262,7 @@ 'login' => [ 'login' => 'Login', 'logged_in' => 'You\'re logged in.', - 'welcome' => 'Welcome Back!', + 'welcome' => 'Welcome back!', 'two-factor' => 'Please enter your token.', ], @@ -259,16 +288,16 @@ // Welcome modal 'welcome' => [ - 'welcome' => 'Welcome to your new Status page!', - 'message' => 'Your status page is almost ready! You might want to configure these extra settings', - 'close' => 'Take me straight to my dashboard', + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', 'steps' => [ - 'component' => 'Create components', - 'incident' => 'Create incidents', - 'customize' => 'Customize', - 'team' => 'Add users', - 'api' => 'Generate API token', - 'two-factor' => 'Two Factor Authentication', + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', ], ], diff --git a/resources/lang/en/forms.php b/resources/lang/en/forms.php index e706de8a2a2..075b7588a9c 100644 --- a/resources/lang/en/forms.php +++ b/resources/lang/en/forms.php @@ -22,7 +22,13 @@ 'site_locale' => 'Select your language', 'enable_google2fa' => 'Enable Google Two Factor Authentication', 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', ], // Login form fields @@ -35,6 +41,7 @@ 'invalid-token' => 'Invalid token', 'cookies' => 'You must enable cookies to login.', 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', ], // Incidents form fields @@ -42,18 +49,36 @@ 'name' => 'Name', 'status' => 'Status', 'component' => 'Component', + 'component_status' => 'Component Status', 'message' => 'Message', 'message-help' => 'You may also use Markdown.', - 'scheduled_at' => 'When to schedule the maintenance for?', - 'incident_time' => 'When did this incident occur?', + 'occurred_at' => 'When did this incident occur?', 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', 'public' => 'Viewable by public', 'logged_in_only' => 'Only visible to logged in users', 'templates' => [ 'name' => 'Name', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -69,28 +94,50 @@ 'enabled' => 'Component enabled?', 'groups' => [ - 'name' => 'Name', - 'collapsing' => 'Choose visibility of the group', - 'visible' => 'Always expanded', - 'collapsed' => 'Collapse the group by default', - 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', ], ], // Metric form fields 'metrics' => [ - 'name' => 'Name', - 'suffix' => 'Suffix', - 'description' => 'Description', - 'description-help' => 'You may also use Markdown.', - 'display-chart' => 'Display chart on status page?', - 'default-value' => 'Default value', - 'calc_type' => 'Calculation of metrics', - 'type_sum' => 'Sum', - 'type_avg' => 'Average', - 'places' => 'Decimal places', - 'default_view' => 'Default view', - 'threshold' => 'How many minutes of threshold between metric points?', + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', 'points' => [ 'value' => 'Value', @@ -99,44 +146,53 @@ // Settings 'settings' => [ - /// Application setup + // Application setup 'app-setup' => [ - 'site-name' => 'Site Name', - 'site-url' => 'Site URL', - 'display-graphs' => 'Display graphs on status page?', - 'about-this-page' => 'About this page', - 'days-of-incidents' => 'How many days of incidents to show?', - 'banner' => 'Banner Image', - 'banner-help' => "It's recommended that you upload files no bigger than 930px wide .", - 'subscribers' => 'Allow people to signup to email notifications?', - 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', ], 'analytics' => [ 'analytics_google' => 'Google Analytics code', 'analytics_gosquared' => 'GoSquared Analytics code', - 'analytics_piwik_url' => 'URL of your Piwik instance (without http(s)://)', + 'analytics_piwik_url' => 'URL of your Piwik instance', 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ - 'allowed-domains' => 'Allowed domains', - 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', ], 'stylesheet' => [ 'custom-css' => 'Custom Stylesheet', ], 'theme' => [ - 'background-color' => 'Background Color', + 'background-color' => 'Background color', 'background-fills' => 'Background fills (components, incidents, footer)', 'banner-background-color' => 'Banner background color', 'banner-padding' => 'Banner padding', - 'fullwidth-banner' => 'Enable fullwidth banner?', - 'text-color' => 'Text Color', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', 'dashboard-login' => 'Show dashboard button in the footer?', 'reds' => 'Red (used for errors)', 'blues' => 'Blue (used for information)', @@ -165,22 +221,32 @@ ], 'team' => [ 'description' => 'Invite your team members by entering their email addresses here.', - 'email' => 'Email #:id', + 'email' => 'Your Team Members Email Address', ], ], + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + // Buttons - 'add' => 'Add', - 'save' => 'Save', - 'update' => 'Update', - 'create' => 'Create', - 'edit' => 'Edit', - 'delete' => 'Delete', - 'submit' => 'Submit', - 'cancel' => 'Cancel', - 'remove' => 'Remove', - 'invite' => 'Invite', - 'signup' => 'Sign Up', + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', // Other 'optional' => '* Optional', diff --git a/resources/lang/en/notifications.php b/resources/lang/en/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/en/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/en/pagination.php b/resources/lang/en/pagination.php index add1092a878..0ee724cf086 100644 --- a/resources/lang/en/pagination.php +++ b/resources/lang/en/pagination.php @@ -22,7 +22,7 @@ | */ - 'previous' => '« Previous', - 'next' => 'Next »', + 'previous' => 'Previous', + 'next' => 'Next', ]; diff --git a/resources/lang/en/setup.php b/resources/lang/en/setup.php index 044cf2e2aa4..bdc2a457873 100644 --- a/resources/lang/en/setup.php +++ b/resources/lang/en/setup.php @@ -11,7 +11,7 @@ return [ 'setup' => 'Setup', - 'title' => 'Setup Cachet', + 'title' => 'Install Cachet', 'service_details' => 'Service Details', 'env_setup' => 'Environment Setup', 'status_page_setup' => 'Status Page Setup', diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index fb52c2f333a..7d196d984dd 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -31,60 +31,60 @@ 'array' => 'The :attribute must be an array.', 'before' => 'The :attribute must be a date before :date.', 'between' => [ - 'numeric' => 'The :attribute must be a date before :date.', - 'file' => 'The :attribute must be between :min and :max.', - 'string' => 'The :attribute must be between :min and :max kilobytes.', + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', 'array' => 'The :attribute must have between :min and :max items.', ], - 'boolean' => 'The :attribute must have between :min and :max items.', - 'confirmed' => 'The :attribute field must be true or false.', - 'date' => 'The :attribute confirmation does not match.', - 'date_format' => 'The :attribute is not a valid date.', - 'different' => 'The :attribute does not match the format :format.', - 'digits' => 'The :attribute and :other must be different.', - 'digits_between' => 'The :attribute must be :digits digits.', - 'email' => 'The :attribute must be between :min and :max digits.', - 'exists' => 'The :attribute must be a valid email address.', + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', 'distinct' => 'The :attribute field has a duplicate value.', - 'filled' => 'The :attribute format is invalid.', + 'filled' => 'The :attribute field is required.', 'image' => 'The :attribute must be an image.', - 'in' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', 'in_array' => 'The :attribute field does not exist in :other.', - 'integer' => 'The selected :attribute is invalid.', - 'ip' => 'The :attribute must be an integer.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', 'json' => 'The :attribute must be a valid JSON string.', 'max' => [ - 'numeric' => 'The :attribute must be a valid IP address.', - 'file' => 'The :attribute may not be greater than :max.', - 'string' => 'The :attribute may not be greater than :max kilobytes.', + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', 'array' => 'The :attribute may not have more than :max items.', ], - 'mimes' => 'The :attribute may not have more than :max items.', + 'mimes' => 'The :attribute must be a file of type: :values.', 'min' => [ - 'numeric' => 'The :attribute must be a file of type: :values.', + 'numeric' => 'The :attribute must be at least :min.', 'file' => 'The :attribute must be at least :min kilobytes.', - 'string' => 'The :attribute must be at least :min kilobytes.', - 'array' => 'The :attribute must be at least :min characters.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', ], - 'not_in' => 'The :attribute must have at least :min items.', - 'numeric' => 'The selected :attribute is invalid.', + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', 'present' => 'The :attribute field must be present.', - 'regex' => 'The :attribute must be a number.', - 'required' => 'The :attribute format is invalid.', - 'required_if' => 'The :attribute field is required.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', 'required_unless' => 'The :attribute field is required unless :other is in :values.', - 'required_with' => 'The :attribute field is required when :other is :value.', + 'required_with' => 'The :attribute field is required when :values is present.', 'required_with_all' => 'The :attribute field is required when :values is present.', - 'required_without' => 'The :attribute field is required when :values is present.', - 'required_without_all' => 'The :attribute field is required when :values is not present.', - 'same' => 'The :attribute field is required when none of :values are present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', 'size' => [ - 'numeric' => 'The :attribute and :other must match.', + 'numeric' => 'The :attribute must be :size.', 'file' => 'The :attribute must be :size kilobytes.', 'string' => 'The :attribute must be :size characters.', - 'array' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', ], - 'string' => 'The :attribute must contain :size items.', + 'string' => 'The :attribute must be a string.', 'timezone' => 'The :attribute must be a valid zone.', 'unique' => 'The :attribute has already been taken.', 'url' => 'The :attribute format is invalid.', diff --git a/resources/lang/es-ES/cachet.php b/resources/lang/es-ES/cachet.php new file mode 100644 index 00000000000..4af5ce20484 --- /dev/null +++ b/resources/lang/es-ES/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Última actualización :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operacional', + 2 => 'Problemas de rendimiento', + 3 => 'Interrupción parcial', + 4 => 'Interrupción mayor', + ], + 'group' => [ + 'other' => 'Otros componentes', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Ningún incidente reportado', + 'past' => 'Incidencias anteriores', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', programado para :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigando', + 2 => 'Identificado', + 3 => 'Observando', + 4 => 'Corregido', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1] El sistema está actualmente experimentando problemas|[2,Inf] Algunos sistemas están experimentando problemas', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerar API Key', + 'revoke' => 'Revocar API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Última hora', + 'hourly' => 'Últimas 12 horas', + 'weekly' => 'Semana', + 'monthly' => 'Mes', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Suscríbete', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notificaciones', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'Actualmente estás suscrito a todas las actualizaciones.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'Actualmente estás suscrito a las siguientes actualizaciones.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Suscríbete para recibir actualizaciones por correo electrónico.', + 'subscribed' => 'Te has subscrito a las notificaciones por correo electrónico, por favor verifica tu correo electrónico para confirmar tu subscripción.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Tu subscripción por correo electrónico ha sido confirmada. Gracias!', + 'manage' => 'Administre su suscripción', + 'unsubscribe' => 'Darse de baja de alertas.', + 'unsubscribed' => 'Tu subscripción de correo electrónico ha sido cancelada.', + 'failure' => 'Algo salió mal con la subscripción.', + 'already-subscribed' => 'No se puede suscribir :email porque ya esta suscrito.', + ], + ], + + 'signup' => [ + 'title' => 'Registrarse', + 'username' => 'Nombre de usuario', + 'email' => 'Correo electrónico', + 'password' => 'Contraseña', + 'success' => 'Tu cuenta ha sido creada.', + 'failure' => 'Hubo algún error al registrarse.', + ], + + 'system' => [ + 'update' => 'Hay disponible una versión de Cachet más nueva. Puedes aprender sobre cómo actualizarla aquí!', + ], + + // Modal + 'modal' => [ + 'close' => 'Cerrar', + 'subscribe' => [ + 'title' => 'Subscribirse a actualizaciones de componentes', + 'body' => 'Introduce tu dirección de correo electrónico para subscribirte a las actualizaciones de este componente. Si ya estás subscrito, ya recibirás los correos electrónicos para este componente.', + 'button' => 'Suscríbete', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Mantente informado con las últimas actualizaciones de servicio de :app.', + ], + ], + + // Other + 'home' => 'Inicio', + 'powered_by' => 'La página de estado de :app está proporcionada por Cachet.', + 'timezone' => 'Los horarios son mostrados en :timezone.', + 'about_this_site' => 'Acerca de este sitio', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Estado del Feed', + +]; diff --git a/resources/lang/es-ES/dashboard.php b/resources/lang/es-ES/dashboard.php new file mode 100644 index 00000000000..b41b10f3167 --- /dev/null +++ b/resources/lang/es-ES/dashboard.php @@ -0,0 +1,304 @@ + 'Panel de Control', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidentes', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Crear plantilla', + 'incident-templates' => 'Plantillas de incidente', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Reportar incidente', + 'success' => 'Incidente agregado.', + 'failure' => 'Hubo un error agregando el incidente, por favor intente de nuevo.', + ], + 'edit' => [ + 'title' => 'Editar un incidente', + 'success' => 'Incidente actualizado.', + 'failure' => 'Hubo un error editando el incidente, por favor intente de nuevo.', + ], + 'delete' => [ + 'success' => 'El incidente se ha eliminado y no se mostrará en tu página de estado.', + 'failure' => 'El incidente no se pudo eliminar, por favor intente de nuevo.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Plantillas de incidente', + 'add' => [ + 'title' => 'Crear una plantilla de incidente', + 'message' => 'Create your first incident template.', + 'success' => 'Su nueva plantilla de incidentes ha sido creada.', + 'failure' => 'Algo salió mal con la plantilla de incidente.', + ], + 'edit' => [ + 'title' => 'Editar plantilla', + 'success' => 'La plantilla de incidente ha sido actualizada.', + 'failure' => 'Algo salió mal actualizando la plantilla de incidente', + ], + 'delete' => [ + 'success' => 'La plantilla de incidente se ha eliminado.', + 'failure' => 'La plantilla de incidente no se pudo eliminar. Por favor, inténtalo de nuevo.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Programado para :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Componentes', + 'component_statuses' => 'Estatus de los componentes', + 'listed_group' => 'Agrupado bajo :nombre', + 'add' => [ + 'title' => 'Agregar componente', + 'message' => 'Deberías agregar un componente.', + 'success' => 'Componente creado.', + 'failure' => 'Algo salió mal con el componente, por favor intente de nuevo.', + ], + 'edit' => [ + 'title' => 'Editar componente', + 'success' => 'Componente actualizado.', + 'failure' => 'Algo salió mal con el componente, por favor intente de nuevo.', + ], + 'delete' => [ + 'success' => 'El componente se ha eliminado!', + 'failure' => 'El componente no pudo ser eliminado, por favor, inténtelo de nuevo.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Grupo de componente|Grupos de componente', + 'no_components' => 'Usted debería agregar un grupo de componentes.', + 'add' => [ + 'title' => 'Agregar un grupo de componentes', + 'success' => 'Grupo de componentes agregado.', + 'failure' => 'Algo salió mal con el componente, por favor intente de nuevo.', + ], + 'edit' => [ + 'title' => 'Editar un grupo de componentes', + 'success' => 'Grupo de componentes actualizado.', + 'failure' => 'Algo salió mal con el componente, por favor intente de nuevo.', + ], + 'delete' => [ + 'success' => 'El grupo de componentes se ha eliminado!', + 'failure' => 'El grupo de componentes no pudo ser eliminado, por favor, inténtelo de nuevo.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Métricas', + 'add' => [ + 'title' => 'Crear una métrica o indicador', + 'message' => 'Deberías añadir una métrica.', + 'success' => 'Métrica creada.', + 'failure' => 'Algo salió mal con la métrica, por favor, inténtelo de nuevo.', + ], + 'edit' => [ + 'title' => 'Editar una métrica', + 'success' => 'Métrica actualizada.', + 'failure' => 'Algo salió mal con la métrica, por favor, inténtelo de nuevo.', + ], + 'delete' => [ + 'success' => 'La métrica se ha eliminado y no se mostrará más en tu página de estado.', + 'failure' => 'La métrica no pudo ser eliminada, por favor, inténtelo de nuevo.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Suscriptores', + 'description' => 'Los suscriptores recibirán actualizaciones por correo electrónico cuando se creen incidentes o se actualicen componentes.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verificado', + 'not_verified' => 'No confirmado', + 'subscriber' => ':email, suscrito :date', + 'no_subscriptions' => 'Suscrito a todas las actualizaciones', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Agregar un nuevo subscriptor', + 'success' => 'Subscriptor agregado.', + 'failure' => 'Algo salió mal al agregar el suscriptor, por favor, inténtelo de nuevo.', + 'help' => 'Agregue cada subscriptor en una línea nueva.', + ], + 'edit' => [ + 'title' => 'Actualizar subscriptor', + 'success' => 'Subscriptor actualizado.', + 'failure' => 'Algo salió mal al editar el suscriptor, por favor, inténtelo de nuevo.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Equipo', + 'member' => 'Miembro', + 'profile' => 'Perfil', + 'description' => 'Los miembros del equipo será capaces de añadir, modificar y editar componentes e incidentes.', + 'add' => [ + 'title' => 'Añadir a un nuevo miembro de equipo', + 'success' => 'Miembro del equipo agregado.', + 'failure' => 'No se pudo agregar el miembro del equipo, por favor vuelva a intentarlo.', + ], + 'edit' => [ + 'title' => 'Actualizar perfil', + 'success' => 'Perfil actualizado.', + 'failure' => 'Algo salió mal actualizando el perfil, por favor intente de nuevo.', + ], + 'delete' => [ + 'success' => 'El miembro del equipo ha sido eliminado y ya no tendrán acceso al Pane de Control!', + 'failure' => 'No se pudo agregar el miembro del equipo, por favor vuelva a intentarlo.', + ], + 'invite' => [ + 'title' => 'Invitar a un nuevo miembro al equipo', + 'success' => 'Se ha enviado una invitación', + 'failure' => 'La invitación no pudo ser enviada, por favor intente de nuevo.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Ajustes', + 'app-setup' => [ + 'app-setup' => 'Configuración de aplicación', + 'images-only' => 'Sólo puedes subir imágenes.', + 'too-big' => 'El archivo subido es demasiado grande. Sube una imagen con tamaño menor a: tamaño', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localización', + ], + 'customization' => [ + 'customization' => 'Personalización', + 'header' => 'Cabecera HTML personalizada', + 'footer' => 'Pie HTML personalizado', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Seguridad', + 'two-factor' => 'Usuarios sin autenticación de dos factores', + ], + 'stylesheet' => [ + 'stylesheet' => 'Hoja de estilo', + ], + 'theme' => [ + 'theme' => 'Tema', + ], + 'edit' => [ + 'success' => 'Configuración guardada.', + 'failure' => 'La configuración no se podido guardar.', + ], + 'credits' => [ + 'credits' => 'Créditos', + 'contributors' => 'Colaboradores', + 'license' => 'Cachet es un proyecto de código libre bajo la licencia BSD-3, liberado por Alt Three Services Limited.', + 'backers-title' => 'Patrocinadores', + 'backers' => 'Si desea apoyar futuros desarrollos, ingrese a la campaña de Cachet Patreon.', + 'thank-you' => 'Gracias a todos y cada uno de los :count colaboradores.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Iniciar Sesión', + 'logged_in' => 'Estás conectado.', + 'welcome' => '¡Bienvenido!', + 'two-factor' => 'Por favor ingresa tu token.', + ], + + // Sidebar footer + 'help' => 'Ayuda', + 'status_page' => 'Página de estado', + 'logout' => 'Salir', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notificaciones', + 'awesome' => 'Excelente.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Apoye Cachet', + 'support_subtitle' => '¡Visite nuestro proyecto en la página de Patreon!', + 'news' => 'Últimas noticias', + 'news_subtitle' => 'Obtener las actualizaciones más recientes', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Bienvenido a tu página de estado!', + 'message' => 'La página de estado está casi lista! Tal vez quieras configurar estos ajustes adicionales', + 'close' => 'Llévame directamente a mi dashboard', + 'steps' => [ + 'component' => 'Crear componentes', + 'incident' => 'Crear incidentes', + 'customize' => 'Personalizar', + 'team' => 'Agregar Usuarios', + 'api' => 'Generar token API', + 'two-factor' => 'Autenticación de dos factores', + ], + ], + +]; diff --git a/resources/lang/es-ES/forms.php b/resources/lang/es-ES/forms.php new file mode 100644 index 00000000000..21780e6da43 --- /dev/null +++ b/resources/lang/es-ES/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Correo electrónico', + 'username' => 'Nombre de usuario', + 'password' => 'Contraseña', + 'site_name' => 'Nombre del sitio', + 'site_domain' => 'Dominio de sitio', + 'site_timezone' => 'Selecciona tu zona horaria', + 'site_locale' => 'Selecciona tu idioma', + 'enable_google2fa' => 'Habilitar la verificación en dos pasos de Google', + 'cache_driver' => 'Controlador de Memoria Cache', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Controlador de Sesion', + 'mail_driver' => 'Valora al conductor', + 'mail_host' => 'Host de correo', + 'mail_address' => 'Dirección de Correo Físico', + 'mail_username' => 'Nombre de usuario de correo', + 'mail_password' => 'Contraseña de correo', + ], + + // Login form fields + 'login' => [ + 'login' => 'Nombre de usuario o dirección de correo electrónico', + 'email' => 'Correo electrónico', + 'password' => 'Contraseña', + '2fauth' => 'Código de Autenticación', + 'invalid' => 'Nombre de usuario o contraseña incorrecto', + 'invalid-token' => 'Token inválido', + 'cookies' => 'Usted debe habilitar cookies para logearse o iniciar sesion.', + 'rate-limit' => 'Límite de transferencia excedido.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Nombre', + 'status' => 'Estado', + 'component' => 'Componente', + 'component_status' => 'Component Status', + 'message' => 'Mensaje', + 'message-help' => 'También puedes usar Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => '¿Notificar a los suscriptores?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Visibilidad del incidente', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Visible por el público', + 'logged_in_only' => 'Solo visible para usuarios logeados', + 'templates' => [ + 'name' => 'Nombre', + 'template' => 'Plantilla', + 'twig' => 'Las plantillas de incidentes pueden hacer uso del lenguaje de plantillas Twig.', + ], + ], + + 'schedules' => [ + 'name' => 'Nombre', + 'status' => 'Estado', + 'message' => 'Mensaje', + 'message-help' => 'También puedes usar Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Nombre', + 'template' => 'Plantilla', + 'twig' => 'Las plantillas de incidentes pueden hacer uso del lenguaje de plantillas Twig.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Nombre', + 'status' => 'Estado', + 'group' => 'Grupo', + 'description' => 'Descripción', + 'link' => 'Enlace', + 'tags' => 'Etiquetas', + 'tags-help' => 'Separado por comas.', + 'enabled' => '¿Componente habilitado?', + + 'groups' => [ + 'name' => 'Nombre', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Siempre expandido', + 'collapsed' => 'Contraer el grupo por defecto', + 'collapsed_incident' => 'Contraer el grupo, pero ampliar si hay problemas', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Nombre', + 'description' => 'Descripción', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Grupo', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Nombre', + 'suffix' => 'Sufijo', + 'description' => 'Descripción', + 'description-help' => 'También puedes usar Markdown.', + 'display-chart' => '¿Mostrar gráficas en la pagina de estado?', + 'default-value' => 'Valor predeterminado', + 'calc_type' => 'Cálculo de métricas', + 'type_sum' => 'Suma', + 'type_avg' => 'Promedio', + 'places' => 'Cantidad de decimales', + 'default_view' => 'Vista predeterminada', + 'threshold' => '¿Cuántos minutos de umbral entre púntos de métrica?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Valor', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Nombre del sitio', + 'site-url' => 'URL del sitio', + 'display-graphs' => '¿Mostrar gráficas en la pagina de estado?', + 'about-this-page' => 'Sobre esta página', + 'days-of-incidents' => '¿Cuántos días de incidentes mostrar?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Imagen del banner', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => '¿Permitir a la gente inscribirse mediante noficiacion por correo electronico?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => '¿Traducir automáticamente la página de estado según el lenguaje del visitante?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Código de Google Analytics', + 'analytics_gosquared' => 'Código de GoSquared Analytics', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Id de tu sitio Piwik', + ], + 'localization' => [ + 'site-timezone' => 'Zona horaria del sitio', + 'site-locale' => 'Idioma del sitio', + 'date-format' => 'Formato de la fecha', + 'incident-date-format' => 'Formato de fecha de incidente', + ], + 'security' => [ + 'allowed-domains' => 'Dominios permitidos', + 'allowed-domains-help' => 'Separados por coma. El dominio establecido en la configuración del sitio formará automáticamente parte de los dominios permitidos.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Hoja de estilo personalizada', + ], + 'theme' => [ + 'background-color' => 'Color de fondo', + 'background-fills' => 'Relleno del fondo (componentes, incidentes, pie)', + 'banner-background-color' => 'Color de fondo del banner', + 'banner-padding' => 'Padding del banner', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Color del texto', + 'dashboard-login' => '¿Mostrar el botón de Panel de Control en el pie?', + 'reds' => 'Rojo (usado para errores)', + 'blues' => 'Azul (usado para información)', + 'greens' => 'Verde (usado para operaciones correctas)', + 'yellows' => 'Amarillo (usado para alertas)', + 'oranges' => 'Naranja (usado para avisos)', + 'metrics' => 'Relleno de las métricas', + 'links' => 'Enlaces', + ], + ], + + 'user' => [ + 'username' => 'Nombre de usuario', + 'email' => 'Correo electrónico', + 'password' => 'Contraseña', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerando tu token de API evitaras que las aplicaciones existentes puedan acceder a Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'Nivel de usuario', + 'levels' => [ + 'admin' => 'Administrador', + 'user' => 'Usuario', + ], + '2fa' => [ + 'help' => 'Habilitar autenticación de dos pasos aumenta la seguridad de tu cuenta. Necesitarás descargar Google Authenticator o una aplicación similar a su dispositivo móvil. Al iniciar sesión, te pedirá proporcionar un token generado por la aplicación.', + ], + 'team' => [ + 'description' => 'Invita a los miembros de equipo introduciendo sus direcciones de correo electrónico aquí.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Agregar', + 'save' => 'Guardar', + 'update' => 'Actualizar', + 'create' => 'Crear', + 'edit' => 'Editar', + 'delete' => 'Eliminar', + 'submit' => 'Enviar', + 'cancel' => 'Cancelar', + 'remove' => 'Remover', + 'invite' => 'Invitar', + 'signup' => 'Registrarse', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Opcional', +]; diff --git a/resources/lang/es-ES/notifications.php b/resources/lang/es-ES/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/es-ES/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/es-ES/pagination.php b/resources/lang/es-ES/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/es-ES/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/es-ES/setup.php b/resources/lang/es-ES/setup.php new file mode 100644 index 00000000000..1438ce13797 --- /dev/null +++ b/resources/lang/es-ES/setup.php @@ -0,0 +1,23 @@ + 'Configurar', + 'title' => 'Configurar Cachet', + 'service_details' => 'Detalles del servicio', + 'env_setup' => 'Configuracion de entorno', + 'status_page_setup' => 'Configuración de la página de estado', + 'show_support' => '¿Deseas mostrar tu apoyo a Cachet?', + 'admin_account' => 'Cuenta de administrador', + 'complete_setup' => 'Completar configuración', + 'completed' => '¡Cachet se ha configurado correctamente!', + 'finish_setup' => 'Ir a Panel de control', +]; diff --git a/resources/lang/es-ES/validation.php b/resources/lang/es-ES/validation.php new file mode 100644 index 00000000000..da4aaf080cc --- /dev/null +++ b/resources/lang/es-ES/validation.php @@ -0,0 +1,122 @@ + 'El :attribute debe ser aceptado.', + 'active_url' => 'El :attribute no es un enlace válido.', + 'after' => 'El :attribute debe ser una fecha después de :date.', + 'alpha' => 'El :attribute sólo puede contener letras.', + 'alpha_dash' => 'El :attribute sólo puede contener letras, números y guiones.', + 'alpha_num' => 'El :attribute sólo puede contener letras y números.', + 'array' => 'El :attribute debe ser una matriz.', + 'before' => 'El :attribute debe ser una fecha antes de :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'El :attribute debe tener entre :min y :max objetos.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'El campo :attribute tiene un valor duplicado.', + 'filled' => 'The :attribute field is required.', + 'image' => 'El :attribute debe ser una imagen.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'El campo :attribute no existe en :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'El :attribute debe ser una cadena JSON válida.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'El :attribute no puede tener más de :max objetos.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'El :attribute debe tener al menos :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'El campo :attribute debe estar presente.', + 'regex' => 'El formato :attribute es inválido.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'El campo :attribute es obligatorio a no ser que :other se encuentre en :values.', + 'required_with' => 'El campo del :attribute se requiere cuando :values es presente.', + 'required_with_all' => 'El campo del :attribute se requiere cuando :values es presente.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'El :attribute debe ser :size kilobytes.', + 'string' => 'El :attribute debe tener :size caracteres.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'El :attribute debe ser una zona válida.', + 'unique' => 'El :attribute ya ha sido usado.', + 'url' => 'El formato :attribute es inválido.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'mensaje-personalizado', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/es/cachet.php b/resources/lang/es/cachet.php index 8ff5b59cbc0..83b4853b169 100644 --- a/resources/lang/es/cachet.php +++ b/resources/lang/es/cachet.php @@ -43,9 +43,9 @@ // Service Status 'service' => [ - 'good' => '[0,1] Sistema operativo | [2,Inf] Todos los sistemas están operativos', - 'bad' => '[0,1] El sistema está actualmente experimentando problemas | [2,Inf] Algunos sistemas están experimentando problemas', - 'major' => '[0,1] El servicio está experimentando una interrupción mayor | [2, Inf] Algunos sistemas están experimentando una interrupción mayor', + 'good' => '[0,1] Sistema operativo|[2,Inf] Todos los sistemas están operativos', + 'bad' => '[0,1] El sistema está actualmente experimentando problemas|[2,Inf] Algunos sistemas están experimentando problemas', + 'major' => '[0,1] El servicio está experimentando una interrupción mayor|[2, Inf] Algunos sistemas están experimentando una interrupción mayor', ], 'api' => [ @@ -103,15 +103,15 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "Te han invitado a la página de estado del equipo de :app_name, para registrarte sigue este enlace.\n:link\nGracias, :app_name", - 'html' => '

Has sido invitado a la página de estado del equipo :app_name, para inscribirte sigue el siguiente enlace.

:link

Gracias, :app_name

', + 'text' => "Te han invitado a la página de estado del equipo de :app_name, para registrarte sigue este enlace.\n:link\nGracias, :app_name", + 'html' => '

Has sido invitado a la página de estado del equipo :app_name, para inscribirte sigue el siguiente enlace.

:link

Gracias, :app_name

', ], ], ], 'signup' => [ 'title' => 'Registrarse', - 'username' => 'Nombre de usario', + 'username' => 'Nombre de usuario', 'email' => 'Correo electrónico', 'password' => 'Contraseña', 'success' => 'Tu cuenta ha sido creada.', diff --git a/resources/lang/es/forms.php b/resources/lang/es/forms.php index 450f21d8505..e304406a62b 100644 --- a/resources/lang/es/forms.php +++ b/resources/lang/es/forms.php @@ -14,7 +14,7 @@ // Setup form fields 'setup' => [ 'email' => 'Correo electrónico', - 'username' => 'Nombre de usario', + 'username' => 'Nombre de usuario', 'password' => 'Contraseña', 'site_name' => 'Nombre del sitio', 'site_domain' => 'Dominio de sitio', @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Nombre', 'template' => 'Plantilla', - 'twig' => 'Las plantillas de incidentes pueden hacer uso del lenguaje de plantillas Twig.', + 'twig' => 'Las plantillas de incidentes pueden hacer uso del lenguaje de plantillas Twig.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Id de tu sitio Piwik', ], 'localization' => [ - 'site-timezone' => 'Zona horaria del sitio', - 'site-locale' => 'Idioma del sitio', - 'date-format' => 'Formato de la fecha', - 'incident-date-format' => 'Formato de fecha de incidente', + 'site-timezone' => 'Zona horaria del sitio', + 'site-locale' => 'Idioma del sitio', + 'date-format' => 'Formato de la fecha', + 'incident-date-format' => 'Formato de fecha de incidente', ], 'security' => [ 'allowed-domains' => 'Dominios permitidos', @@ -149,7 +149,7 @@ ], 'user' => [ - 'username' => 'Nombre de usario', + 'username' => 'Nombre de usuario', 'email' => 'Correo electrónico', 'password' => 'Contraseña', 'api-token' => 'API Token', diff --git a/resources/lang/et-EE/cachet.php b/resources/lang/et-EE/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/et-EE/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/et-EE/dashboard.php b/resources/lang/et-EE/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/et-EE/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/et-EE/forms.php b/resources/lang/et-EE/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/et-EE/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/et-EE/notifications.php b/resources/lang/et-EE/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/et-EE/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/et-EE/pagination.php b/resources/lang/et-EE/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/et-EE/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/et-EE/setup.php b/resources/lang/et-EE/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/et-EE/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/et-EE/validation.php b/resources/lang/et-EE/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/et-EE/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/fa-IR/cachet.php b/resources/lang/fa-IR/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/fa-IR/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/fa-IR/dashboard.php b/resources/lang/fa-IR/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/fa-IR/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/fa-IR/forms.php b/resources/lang/fa-IR/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/fa-IR/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/fa-IR/notifications.php b/resources/lang/fa-IR/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/fa-IR/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/fa-IR/pagination.php b/resources/lang/fa-IR/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/fa-IR/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/fa-IR/setup.php b/resources/lang/fa-IR/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/fa-IR/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/fa-IR/validation.php b/resources/lang/fa-IR/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/fa-IR/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/fa/cachet.php b/resources/lang/fa/cachet.php index 80ccbedf0a1..f520dc42dcd 100644 --- a/resources/lang/fa/cachet.php +++ b/resources/lang/fa/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -92,8 +92,8 @@ 'subject' => '[New Incident] :status: :name', ], 'component' => [ - 'subject' => 'به‌روزرسانی وضعیت کامپوننت', - 'text' => 'کامپوننت :component یک تغییر وضعیت دارد. این کامپوننت هم‌اکنون در حالت :component_human_status قرار دارد.\n + 'subject' => 'به‌روزرسانی وضعیت کامپوننت', + 'text' => 'کامپوننت :component یک تغییر وضعیت دارد. این کامپوننت هم‌اکنون در حالت :component_human_status قرار دارد.\n با تشکر، :app_name', 'html' => '

کامپوننت با نام :component_name یک تغییر وضعیت دارد. کامپوننت هم‌اکنون در حالت :component_human_status قرار دارد.

با تشکر :app_name

', 'tooltip-title' => 'Subscribe to notifications for :component_name.', @@ -104,8 +104,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/fa/forms.php b/resources/lang/fa/forms.php index e56f170b7ac..d232db3f9e8 100644 --- a/resources/lang/fa/forms.php +++ b/resources/lang/fa/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Name', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/fi-FI/cachet.php b/resources/lang/fi-FI/cachet.php new file mode 100644 index 00000000000..7c1d6ccd091 --- /dev/null +++ b/resources/lang/fi-FI/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/fi-FI/dashboard.php b/resources/lang/fi-FI/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/fi-FI/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/fi-FI/forms.php b/resources/lang/fi-FI/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/fi-FI/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/fi-FI/notifications.php b/resources/lang/fi-FI/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/fi-FI/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/fi-FI/pagination.php b/resources/lang/fi-FI/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/fi-FI/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/fi-FI/setup.php b/resources/lang/fi-FI/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/fi-FI/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/fi-FI/validation.php b/resources/lang/fi-FI/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/fi-FI/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/fi/cachet.php b/resources/lang/fi/cachet.php index 17c8edd7359..4a6f8207b43 100644 --- a/resources/lang/fi/cachet.php +++ b/resources/lang/fi/cachet.php @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "Sinut on kutsuttu ryhmään :app_name tila sivulle, rekisteröi tästä: \n:link\n. Kiitos, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "Sinut on kutsuttu ryhmään :app_name tila sivulle, rekisteröi tästä: \n:link\n. Kiitos, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/fi/forms.php b/resources/lang/fi/forms.php index 5809c4e1a5e..173b87ac790 100644 --- a/resources/lang/fi/forms.php +++ b/resources/lang/fi/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Nimi', 'template' => 'Malli', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik sivun tunnus', ], 'localization' => [ - 'site-timezone' => 'Sivuston aikavyöhyke', - 'site-locale' => 'Sivuston kieli', - 'date-format' => 'Päivämäärän muoto', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Sivuston aikavyöhyke', + 'site-locale' => 'Sivuston kieli', + 'date-format' => 'Päivämäärän muoto', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Sallittu toimialueet', diff --git a/resources/lang/fr-FR/cachet.php b/resources/lang/fr-FR/cachet.php new file mode 100644 index 00000000000..a87d328f50c --- /dev/null +++ b/resources/lang/fr-FR/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Dernière mise-à-jour le :timestamp', + 'status' => [ + 0 => 'Inconnu', + 1 => 'Opérationnel', + 2 => 'Problèmes de performances', + 3 => 'Panne partielle', + 4 => 'Panne majeure', + ], + 'group' => [ + 'other' => 'Autres services', + ], + 'select_all' => 'Tout sélectionner', + 'deselect_all' => 'Tout désélectionner', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Aucun incident signalé', + 'past' => 'Incidents antérieurs', + 'stickied' => 'Incidents épinglés', + 'scheduled' => 'Maintenance planifiée', + 'scheduled_at' => ', planifé le :timestamp', + 'posted' => 'Signalé :timestamp par :username', + 'posted_at' => 'Signalé :timestamp', + 'status' => [ + 1 => 'En cours d’investigation', + 2 => 'Identifié', + 3 => 'Sous surveillance', + 4 => 'Corrigé', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Imminent', + 1 => 'En cours', + 2 => 'Terminé', + ], + ], + + // Service Status + 'service' => [ + 'good' => 'Aucun incident signalé', + 'bad' => 'Incident en cours', + 'major' => 'Incident majeur en cours', + ], + + 'api' => [ + 'regenerate' => 'Régénérer la clé API', + 'revoke' => 'Révoquer la clé API', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Dernière heure', + 'hourly' => 'Les 12 dernières heures', + 'weekly' => 'Semaine', + 'monthly' => 'Mois', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Être informé des nouveaux signalements d’incidents et changements de statut', + 'unsubscribe' => 'Se désabonner', + 'button' => 'S’abonner', + 'manage_subscription' => 'Gérer l’abonnement', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Gérer les notifications pour', + 'no_subscriptions' => 'Vous êtes actuellement abonné à toutes les mises-à-jour.', + 'update_subscription' => 'Mettre-à-jour l’abonnement', + 'my_subscriptions' => 'Vous êtes actuellement abonné aux mises-à-jour suivantes.', + 'manage_at_link' => 'Gérer vos abonnements à :link', + ], + 'email' => [ + 'manage_subscription' => 'Un courriel vous a été envoyé ; merci de cliquer sur le lien pour gérer votre abonnement', + 'subscribe' => 'S’abonner aux notifications par courriel.', + 'subscribed' => 'Vous êtes abonné aux notifications par courriel, veuillez vérifier votre messagerie pour confirmer votre adresse.', + 'updated-subscribe' => 'Vous avez mis-à-jour vos abonnements avec succès.', + 'verified' => 'Votre abonnement aux notifications par courriel a été confirmé. Merci !', + 'manage' => 'Gérer votre abonnement', + 'unsubscribe' => 'Se désabonner des mises à jour par courriel.', + 'unsubscribed' => 'Votre abonnement aux notifications par courriel a été annulé.', + 'failure' => 'Une erreur est survenue lors de l’abonnement.', + 'already-subscribed' => 'Impossible de s’abonner avec l’adresse mail :email car celle-ci est déjà abonnée.', + ], + ], + + 'signup' => [ + 'title' => 'Inscription', + 'username' => 'Nom d’utilisateur', + 'email' => 'Adresse mail', + 'password' => 'Mot de passe', + 'success' => 'Votre compte a été créé.', + 'failure' => 'Un problème est survenu lors de votre inscription.', + ], + + 'system' => [ + 'update' => 'Il y a une nouvelle version de Cachet disponible. Vous pouvez trouver des renseignements concernant la procédure de mise à jour ici!', + ], + + // Modal + 'modal' => [ + 'close' => 'Fermer', + 'subscribe' => [ + 'title' => 'S’abonner aux mises-à-jour du statut du service', + 'body' => 'Entrez votre adresse mail pour vous abonner aux mises-à-jour de ce service. Si vous êtes déjà abonné, vous recevez déjà des notifications pour ce service.', + 'button' => 'S’abonner', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Détails et mises-à-jour sur l’incident :name qui a eu lieu le :date', + 'schedule' => 'Détails sur la période de maintenance planifiée :name débutant le :startDate', + 'subscribe' => 'S’abonner à :app afin de recevoir les mises-à-jour des incidents et des périodes de maintenance planifiée', + 'overview' => 'Restez à jour avec les dernières mises-à-jour de :app.', + ], + ], + + // Other + 'home' => 'Accueil', + 'powered_by' => 'Propulsé par Cachet.', + 'timezone' => 'Les heures sont affichées avec le fuseau horaire :timezone.', + 'about_this_site' => 'À propos du site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Flux des statuts', + +]; diff --git a/resources/lang/fr-FR/dashboard.php b/resources/lang/fr-FR/dashboard.php new file mode 100644 index 00000000000..13e2e763cd0 --- /dev/null +++ b/resources/lang/fr-FR/dashboard.php @@ -0,0 +1,305 @@ + 'Tableau de bord', + 'writeable_settings' => 'Le dossier des paramètres de Cachet n’est pas accessible en écriture. Veuillez vous assurer que le serveur web peut écrire dans ./bootstrap/cachet.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenances', + 'incidents' => 'Incidents', + 'logged' => '{0}Il n’y a aucun incident, bon travail.|[1]Vous avez reporté un incident.|[2,*]Vous avez reporté :count incidents.', + 'incident-create-template' => 'Créer un modèle', + 'incident-templates' => 'Modèles d’incident', + 'updates' => [ + 'title' => 'Mises-à-jour d’incident pour :incident', + 'count' => '{0}aucune|[1]une mise-à-jour|[2]deux mises-à-jour|[3,*]plusieurs mises-à-jour', + 'add' => [ + 'title' => 'Créer une mise à jour d’incident', + 'success' => 'Votre nouvelle mise-à-jour d’incident a été créée.', + 'failure' => 'Un problème est survenu avec la mise-à-jour d’incident.', + ], + 'edit' => [ + 'title' => 'Modifier la mise-à-jour d’incident', + 'success' => 'La mise-à-jour d’incident a été modifiée.', + 'failure' => 'Un problème est survenu avec la modification de la mise-à-jour d’incident.', + ], + ], + 'reported_by' => 'Signalé :timestamp par :user', + 'add' => [ + 'title' => 'Ajouter un incident', + 'success' => 'Incident ajouté.', + 'failure' => 'Une erreur s’est produite en ajoutant l’incident, veuillez réessayer.', + ], + 'edit' => [ + 'title' => 'Modifier un incident', + 'success' => 'Incident modifié.', + 'failure' => 'Une erreur s’est produite en modifiant l’incident, veuillez réessayer.', + ], + 'delete' => [ + 'success' => 'L’incident a été supprimé et ne sera pas affiché sur votre page de statut.', + 'failure' => 'L’incident n’a pas pu être supprimé. Veuillez réessayer.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Modèles d’incident', + 'add' => [ + 'title' => 'Créer un modèle d’incident', + 'message' => 'Créer votre premier modèle d’incident.', + 'success' => 'Votre nouveau modèle d’incident a été créé.', + 'failure' => 'Une erreur est survenue avec le modèle d’incident.', + ], + 'edit' => [ + 'title' => 'Éditer le modèle', + 'success' => 'Le modèle d’incident a été mis-à-jour.', + 'failure' => 'Une erreur est survenue lors de la mise-à-jour du modèle d’incident', + ], + 'delete' => [ + 'success' => 'Le modèle d’incident a été supprimé.', + 'failure' => 'Le modèle d’incident n’a pas pu être supprimé. Veuillez réessayer.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenances planifiées', + 'logged' => '{0}Il n’y a aucune maintenance, bon travail.|[1]Vous avez reporté une maintenance.|[2,*]Vous avez reporté :count maintenances.', + 'scheduled_at' => 'Planifiée le :timestamp', + 'add' => [ + 'title' => 'Ajouter une maintenance', + 'success' => 'Maintenance ajoutée.', + 'failure' => 'Un problème est survenu avec l’ajout de la maintenance. Veuillez réessayer.', + ], + 'edit' => [ + 'title' => 'Modifier la maintenance', + 'success' => 'La maintrnance a été modifiée !', + 'failure' => 'Un problème est survenu avec la modification de la maintenance. Veuillez réessayer.', + ], + 'delete' => [ + 'success' => 'TLa maitenance a été supprimée et de s’affichera plus sur la page de statut.', + 'failure' => 'Un problème est survenu avec la suppression de la maintenance. Veuillez réessayer.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Services', + 'component_statuses' => 'Statut des services', + 'listed_group' => 'Groupé par :name', + 'add' => [ + 'title' => 'Ajouter un service', + 'message' => 'Vous devez ajouter un service.', + 'success' => 'Service créé.', + 'failure' => 'Un problème est survenu avec la création du service. Veuillez réessayer.', + ], + 'edit' => [ + 'title' => 'Modifier un service', + 'success' => 'Service modifié.', + 'failure' => 'Un problème est survenu avec la modification du service. Veuillez réessayer.', + ], + 'delete' => [ + 'success' => 'Le service a été supprimé !', + 'failure' => 'Un problème est survenu avec la suppression du service. Veuillez réessayer.', + ], + + // Component groups + 'groups' => [ + 'groups' => '[0,1]Groupe de services|[2,*]Groupes de services', + 'no_components' => 'Vous devez ajouter un groupe de services.', + 'add' => [ + 'title' => 'Ajouter un groupe de services', + 'success' => 'Groupe de services ajouté.', + 'failure' => 'Un problème est survenu avec l’ajout du groupe de services. Veuillez réessayer.', + ], + 'edit' => [ + 'title' => 'Modifier un groupe de services', + 'success' => 'Groupe de services modifié.', + 'failure' => 'Un problème est survenu avec la modification du groupe de services. Veuillez réessayer.', + ], + 'delete' => [ + 'title' => 'Supprimer le groupe de services', + 'success' => 'Le groupe de services a été supprimé !', + 'failure' => 'Un problème est survenu avec la suppression du groupe de services. Veuillez réessayer.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Indicateurs', + 'add' => [ + 'title' => 'Créer une métrique', + 'message' => 'Vous devez ajouter un indicateur.', + 'success' => 'Indicateur créé.', + 'failure' => 'Une erreur est survenue avec l’ajout de l’indicateur. Veuillez réessayer.', + ], + 'edit' => [ + 'title' => 'Modifier une métrique', + 'success' => 'Indicateur modifié.', + 'failure' => 'Une erreur est survenue avec la modification de l’indicateur. Veuillez réessayer.', + ], + 'delete' => [ + 'success' => 'La métrique a été supprimé et ne sera plus visible sur votre page de statut.', + 'failure' => 'Une erreur est survenue avec la suppression de l’indicateur. Veuillez réessayer.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Abonnés', + 'description' => 'Les abonnés recevront des notifications par courriel lorsque des incidents sont créés ou des services sont mis-à-jour.', + 'description_disabled' => 'Pour utiliser cette fonction, vous devez autoriser l’abonnement aux notifications.', + 'verified' => 'Vérifié', + 'not_verified' => 'Non vérifié', + 'subscriber' => ':email, abonné le :date', + 'no_subscriptions' => 'Aucun abonnement', + 'global' => 'Abonné à tout', + 'add' => [ + 'title' => 'Ajouter un abonné', + 'success' => 'L’abonné a été ajouté !', + 'failure' => 'Une erreur s’est produite lors de l’ajout de l’abonné. Veuillez réessayer.', + 'help' => 'Saisissez un abonné par ligne.', + ], + 'edit' => [ + 'title' => 'Modifier l’abonné', + 'success' => 'L’abonné a été modifié !', + 'failure' => 'Une erreur s’est produite lors de la modification de l’abonné. Veuillez réessayer.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Équipe', + 'member' => 'Membre', + 'profile' => 'Profil utilisateur', + 'description' => 'Les membres de l’équipe pourront ajouter & modifier les services et les incidents.', + 'add' => [ + 'title' => 'Ajouter un nouveau membre à l’équipe', + 'success' => 'Membre d’équipe a ajouté.', + 'failure' => 'Le membre n’a pas pu être ajouté à l’équipe. Veuillez réessayer.', + ], + 'edit' => [ + 'title' => 'Modifier le profil', + 'success' => 'Profil modifié.', + 'failure' => 'Une erreur s’est produite lors de la modification du profil. Veuillez réessayer.', + ], + 'delete' => [ + 'success' => 'Le membre été supprimé de l’équipe et n’aura plus l’accès au tableau de bord !', + 'failure' => 'Le membre n’a pas pu être supprimé de l’équipe. Veuillez réessayer.', + ], + 'invite' => [ + 'title' => 'Inviter un nouveau membre dans l’équipe', + 'success' => 'Nouveau membre invité.', + 'failure' => 'L’invitation n’a pas pu être envoyé. Veuillez réessayer.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Paramètres', + 'app-setup' => [ + 'app-setup' => 'Configuration de l’application', + 'images-only' => 'Seules les images peuvent être envoyées.', + 'too-big' => 'Le fichier envoyé est trop grand. Envoyer une image d’une taille inférieur à :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Journal', + ], + 'localization' => [ + 'localization' => 'Localisation', + ], + 'customization' => [ + 'customization' => 'Personnalisation', + 'header' => 'Entête HTML personnalisé', + 'footer' => 'Pied-de-page HTML personnalisé', + ], + 'mail' => [ + 'mail' => 'Courriel', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Tester la notification depuis Cachet', + 'body' => 'Ceci est une notification de test depuis Cachet.', + ], + ], + 'security' => [ + 'security' => 'Sécurité', + 'two-factor' => 'Utilisateurs sans authentification à deux facteurs', + ], + 'stylesheet' => [ + 'stylesheet' => 'Feuille de style', + ], + 'theme' => [ + 'theme' => 'Thème', + ], + 'edit' => [ + 'success' => 'Paramètres sauvegardés.', + 'failure' => 'Les paramètres n’ont pas pu être sauvegardés.', + ], + 'credits' => [ + 'credits' => 'Crédits', + 'contributors' => 'Contributeurs', + 'license' => 'Cachet est un logiciel libre sous licence BSD-3 édité par Alt Three Services Limited.', + 'backers-title' => 'Partenaires financiers et sponsors', + 'backers' => 'Si vous souhaitez aider des développements futurs jetez un œil à la campagne Cachet Patreon.', + 'thank-you' => 'Merci à chacun des :count contributeurs.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Connexion', + 'logged_in' => 'Vous êtes connecté.', + 'welcome' => 'Re-bonjour !', + 'two-factor' => 'Veuillez entrer votre jeton.', + ], + + // Sidebar footer + 'help' => 'Aide', + 'status_page' => 'Page de statut', + 'logout' => 'Déconnexion', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Fantastique.', + 'whoops' => 'Oups.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Soutenez Cachet', + 'support_subtitle' => 'Jetez un œil à la page Patreon!', + 'news' => 'Dernières actualités', + 'news_subtitle' => 'Obtenez les dernières mises à jour', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Bienvenue sur votre page de statut !', + 'message' => 'Votre page de statut est presque prête ! Vous voudrez peut-être configurer ces paramètres supplémentaires', + 'close' => 'Aller directement à mon tableau de bord', + 'steps' => [ + 'component' => 'Créer des services', + 'incident' => 'Créer des incidents', + 'customize' => 'Personnaliser', + 'team' => 'Ajouter des utilisateurs', + 'api' => 'Générer un jeton API', + 'two-factor' => 'Authentification à deux facteurs', + ], + ], + +]; diff --git a/resources/lang/fr-FR/forms.php b/resources/lang/fr-FR/forms.php new file mode 100644 index 00000000000..b43d3691720 --- /dev/null +++ b/resources/lang/fr-FR/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Adresse électronique', + 'username' => 'Nom d’utilisateur', + 'password' => 'Mot de passe', + 'site_name' => 'Nom du site', + 'site_domain' => 'Nom de domaine du site', + 'site_timezone' => 'Choisissez votre fuseau horaire', + 'site_locale' => 'Sélectionner votre langue', + 'enable_google2fa' => 'Activer l’authentification à deux facteurs de Google', + 'cache_driver' => 'Gestionnaire de cache', + 'queue_driver' => 'Pilote de fil', + 'session_driver' => 'Gestionnaire de session', + 'mail_driver' => 'Gestionnaire de mail', + 'mail_host' => 'Serveur de mail', + 'mail_address' => 'Adresse de l’expéditeur du mail', + 'mail_username' => 'Nom d’utilisateur de mail', + 'mail_password' => 'Mot de passe du serveur de mail', + ], + + // Login form fields + 'login' => [ + 'login' => 'Nom d’utilisateur ou courriel', + 'email' => 'Adresse électronique', + 'password' => 'Mot de passe', + '2fauth' => 'Code d’authentification', + 'invalid' => 'Nom d’utilisateur ou mot de passe incorrect', + 'invalid-token' => 'Jeton invalide', + 'cookies' => 'Vous devez activer les cookies pour vous connecter.', + 'rate-limit' => 'Limite de tentatives de connexion atteinte.', + 'remember_me' => 'Se souvenir de moi', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Nom', + 'status' => 'Statut', + 'component' => 'Service', + 'component_status' => 'Statut de service', + 'message' => 'Message', + 'message-help' => 'Vous pouvez également utiliser le format Markdown.', + 'occurred_at' => 'Quand s’est produit cet incident ?', + 'notify_subscribers' => 'Notifier les abonnés ?', + 'notify_disabled' => 'Suite à une maintenance plannifiée, les notifications sur cet incident ou ses services seront supprimées.', + 'visibility' => 'Visibilité de l’incident', + 'stick_status' => 'Incident épinglé', + 'stickied' => 'Épinglé', + 'not_stickied' => 'Non épinglé', + 'public' => 'Visible par le public', + 'logged_in_only' => 'Uniquement visible par les utilisateurs enregistrés', + 'templates' => [ + 'name' => 'Nom', + 'template' => 'Modèle', + 'twig' => 'Vous pouvez utiliser Twig pour créer des modèles par langues pour les modèles d’incidents.', + ], + ], + + 'schedules' => [ + 'name' => 'Nom', + 'status' => 'Statut', + 'message' => 'Message', + 'message-help' => 'Vous pouvez également utiliser le format Markdown.', + 'scheduled_at' => 'Pour quand la maintenance est-elle planifiée ?', + 'completed_at' => 'Quand est-ce que cette maintenance sera terminée ?', + 'templates' => [ + 'name' => 'Nom', + 'template' => 'Modèle', + 'twig' => 'Vous pouvez utiliser Twig pour créer des modèles par langues pour les modèles d’incidents.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Nom', + 'status' => 'Statut', + 'group' => 'Groupe', + 'description' => 'Description', + 'link' => 'Lien', + 'tags' => 'Mots-clés', + 'tags-help' => 'Séparés par des virgules.', + 'enabled' => 'Activer le service ?', + + 'groups' => [ + 'name' => 'Nom', + 'collapsing' => 'Afficher/Cacher les options', + 'visible' => 'Toujours déplier', + 'collapsed' => 'Réduire le groupe par défaut', + 'collapsed_incident' => 'Réduire le groupe par défaut, mais déplier s’il y a des incidents', + 'visibility' => 'Visibilité', + 'visibility_public' => 'Visible par le public', + 'visibility_authenticated' => 'Visible uniquement par les utilisateurs connectés', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Nom', + 'description' => 'Description', + 'start_at' => 'Heure de début planifiée', + 'timezone' => 'Fuseau horaire', + 'schedule_frequency' => 'Fréquence de planification (en secondes)', + 'completion_latency' => 'Délai d’achèvement (en secondes)', + 'group' => 'Groupe', + 'active' => 'Actif ?', + 'groups' => [ + 'name' => 'Nom du groupe', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Nom', + 'suffix' => 'Suffixe', + 'description' => 'Description', + 'description-help' => 'Vous pouvez également utiliser le format Markdown.', + 'display-chart' => 'Afficher le graphique sur la page de statut ?', + 'default-value' => 'Valeur par défaut', + 'calc_type' => 'Calcul des données', + 'type_sum' => 'Somme', + 'type_avg' => 'Moyenne', + 'places' => 'Nombre de chiffres après la virgule', + 'default_view' => 'Vue par défaut', + 'threshold' => 'Quel intervalle en minutes entre chaque point de métrique ?', + 'visibility' => 'Visibilité', + 'visibility_authenticated' => 'Visible aux utilisateurs authentifiés', + 'visibility_public' => 'Visible à tous', + 'visibility_hidden' => 'Toujours caché', + + 'points' => [ + 'value' => 'Valeur', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Nom du site', + 'site-url' => 'URL du site', + 'display-graphs' => 'Afficher les graphiques sur la page de statut ?', + 'about-this-page' => 'À propos de cette page', + 'days-of-incidents' => 'Combien de jours d’incidents à montrer ?', + 'time_before_refresh' => 'Taux de rafraîchissement de la page de statut (en secondes)', + 'major_outage_rate' => 'Seuil pour les pannes majeures (en %)', + 'banner' => 'Image d’entête', + 'banner-help' => 'Il est recommandé de téléverser des images d’une largeur d’au plus 930 pixels.', + 'subscribers' => 'Permettre aux personnes de s’inscrire aux notifications par courriel ?', + 'suppress_notifications_in_maintenance' => 'Désactiver les notifications lorsqu’un incident se produit pendant une période de maintenance ?', + 'skip_subscriber_verification' => 'Ne pas vérifier les utilisateurs ? (Attention, vous pourriez être spammé)', + 'automatic_localization' => 'Traduire automatiquement votre page de statut dans la langue du visiteur ?', + 'enable_external_dependencies' => 'Activer les dépendances tierces (Google Fonts, Trackers, etc.)', + 'show_timezone' => 'Afficher le fuseau horaire du site', + 'only_disrupted_days' => 'Afficher uniquement les jours contenant des incidents dans la timeline ?', + ], + 'analytics' => [ + 'analytics_google' => 'Code de Google Analytics', + 'analytics_gosquared' => 'Code de GoSquared Analytics', + 'analytics_piwik_url' => 'URL de votre instance Piwik', + 'analytics_piwik_siteid' => 'Id du site de Piwik', + ], + 'localization' => [ + 'site-timezone' => 'Fuseau horaire du site', + 'site-locale' => 'Langue du site', + 'date-format' => 'Format de la date', + 'incident-date-format' => 'Format de la date de l’incident', + ], + 'security' => [ + 'allowed-domains' => 'Domaines autorisés', + 'allowed-domains-help' => 'Les domaines définis ci-dessus sont automatiquement autorisés par défaut (séparés par des virgules).', + 'always-authenticate' => 'Authentification systématique', + 'always-authenticate-help' => 'Une authentification est nécessaire pour accéer à la moindre page Cachet.', + ], + 'stylesheet' => [ + 'custom-css' => 'Feuille de style personnalisée', + ], + 'theme' => [ + 'background-color' => 'Couleur de fond', + 'background-fills' => 'Couleur de remplissage de l’arrière-plan (services, incidents, pied-de-page)', + 'banner-background-color' => 'Couleur d’arrière-plan de l’entête', + 'banner-padding' => 'Marge de l’entête', + 'fullwidth-banner' => 'Activer la pleine largeur de bannière ?', + 'text-color' => 'Couleur du texte', + 'dashboard-login' => 'Afficher le bouton « Tableau de bord » dans le pied-de-page ?', + 'reds' => 'Rouge (utilisé pour les erreurs)', + 'blues' => 'Bleu (utilisé pour les informations)', + 'greens' => 'Vert (utilisé pour les succès)', + 'yellows' => 'Jaune (utilisé pour les alertes)', + 'oranges' => 'Orange (utilisé pour les informations)', + 'metrics' => 'Remplissage des données', + 'links' => 'Liens', + ], + ], + + 'user' => [ + 'username' => 'Nom d’utilisateur', + 'email' => 'Adresse électronique', + 'password' => 'Mot de passe', + 'api-token' => 'Jeton de l’API', + 'api-token-help' => 'Régénérer votre jeton API empêchera les applications existantes d’accéder à Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'Niveau de l’utilisateur', + 'levels' => [ + 'admin' => 'Administrateur', + 'user' => 'Utilisateur', + ], + '2fa' => [ + 'help' => 'Activer l’authentification à deux facteurs augmente la sécurité de votre compte. Vous aurez besoin de télécharger Google Authenticator ou une application similaire sur votre appareil mobile. Lorsque vous vous connectez, il vous sera demandé de fournir un jeton généré par l’application.', + ], + 'team' => [ + 'description' => 'Invitez les membres de votre équipe en entrant leurs adresses électroniques ici.', + 'email' => 'L’adresse électronique du membre de votre équipe', + ], + ], + + 'general' => [ + 'timezone' => 'Sélection du fuseau horaire', + ], + + 'seo' => [ + 'title' => 'Titre SEO', + 'description' => 'Description SEO', + ], + + // Buttons + 'add' => 'Ajouter', + 'save' => 'Enregistrer', + 'update' => 'Mettre à jour', + 'create' => 'Créer', + 'edit' => 'Modifier', + 'delete' => 'Supprimer', + 'submit' => 'Envoyer', + 'cancel' => 'Annuler', + 'remove' => 'Enlever', + 'invite' => 'Inviter', + 'signup' => 'Inscription', + 'manage_updates' => 'Gérer les mises-à-jour', + + // Other + 'optional' => '* Optionnel', +]; diff --git a/resources/lang/fr-FR/notifications.php b/resources/lang/fr-FR/notifications.php new file mode 100644 index 00000000000..1c14bca588e --- /dev/null +++ b/resources/lang/fr-FR/notifications.php @@ -0,0 +1,116 @@ +?php + +/* + * This file is part of Cachet. + * + * (c) Alt Three Services Limited + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +return [ + 'component' => [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Évolution du statut d’un service', + 'greeting' => 'Le statut d’un service a été mis-à-jour !', + 'content' => 'L’état du service :name est passé de :old_status à :new_status.', + 'action' => 'Voir le statut', + ], + 'slack' => [ + 'title' => 'Évolution du statut d’un service', + 'content' => 'L’état du service :name est passé de :old_status à :new_status.', + ], + 'sms' => [ + 'content' => 'L’état du service :name est passé de :old_status à :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Nouvel incident signalé', + 'greeting' => 'Un nouvel incident a été signalé pour :app_name.', + 'content' => 'L’incident :name a été signalé', + 'action' => 'Voir l’incident', + ], + 'slack' => [ + 'title' => 'Nouvel incident signalé', + 'content' => 'Un nouvel incident a été signalé pour :app_name.', + ], + 'sms' => [ + 'content' => 'Un nouvel incident a été signalé pour :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Mise-à-jour d’un incident', + 'content' => 'L’incident :name a été mis-à-jour.', + 'title' => 'L’incident :name est passé à :new_status', + 'action' => 'Voir l’incident', + ], + 'slack' => [ + 'title' => 'Mise-à-jour d’un incident', + 'content' => 'L’incident :name est passé à :new_status', + ], + 'sms' => [ + 'content' => 'L’incident :name a été mis-à-jour', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Nouvelle maintenance planifiée', + 'content' => 'Une maintenance :name a été planifiée pour le :date.', + 'title' => 'Une nouvelle maintenance est planifiée.', + 'action' => 'Voir la maintenance', + ], + 'slack' => [ + 'title' => 'Nouvelle maintenance planifiée !', + 'content' => 'Une maintenance :name a été planifiée pour le :date.', + ], + 'sms' => [ + 'content' => 'Une maintenance :name a été planifiée pour le :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Confirmez votre abonnement', + 'content' => 'Cliquez pour valider votre adresse mail et confirmer votre abonnement à la page de statut :app_name.', + 'title' => 'Confirmez votre abonnement à la page de statut :app_name.', + 'action' => 'Confirmer l’abonnement', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Gérez votre abonnement', + 'content' => 'Cliquez pour gérer votre abonnement à la page de statut :app_name.', + 'title' => 'Cliquez pour gérer votre abonnement à la page de statut :app_name.', + 'action' => 'Gérer l’abonnement', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping depuis Cachet!', + 'content' => 'Ceci est un test de notification depuis Cachet !', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Vous avez reçu une invitation…', + 'content' => 'Vous avez été invité à rejoindre la page de statut :app_name.', + 'title' => 'Vous êtes invité à rejoindre la page de statut :app_name.', + 'action' => 'Accepter', + ], + ], + ], +]; diff --git a/resources/lang/fr-FR/pagination.php b/resources/lang/fr-FR/pagination.php new file mode 100644 index 00000000000..e42562076df --- /dev/null +++ b/resources/lang/fr-FR/pagination.php @@ -0,0 +1,28 @@ + 'précédent', + 'next' => 'suivant', + +]; diff --git a/resources/lang/fr-FR/setup.php b/resources/lang/fr-FR/setup.php new file mode 100644 index 00000000000..58cb2ff7b4b --- /dev/null +++ b/resources/lang/fr-FR/setup.php @@ -0,0 +1,23 @@ + 'Installation', + 'title' => 'Configuration de Cachet', + 'service_details' => 'Détails du service', + 'env_setup' => 'Configuration de l’environnement', + 'status_page_setup' => 'Configuration de la page de statut', + 'show_support' => 'Afficher votre soutien à Cachet ?', + 'admin_account' => 'Compte administrateur', + 'complete_setup' => 'Terminer la configuration', + 'completed' => 'Cachet a été configuré avec succès !', + 'finish_setup' => 'Aller au tableau de bord', +]; diff --git a/resources/lang/fr-FR/validation.php b/resources/lang/fr-FR/validation.php new file mode 100644 index 00000000000..fdb23623f13 --- /dev/null +++ b/resources/lang/fr-FR/validation.php @@ -0,0 +1,122 @@ + ':attribute doit être accepté.', + 'active_url' => ':attribute n’est pas une URL valide.', + 'after' => ':attribute doit être une date supérieure à :date.', + 'alpha' => ':attribute ne doit contenir que des lettres.', + 'alpha_dash' => ':attribute doit contenir seulement des lettres, nombres et des tirets.', + 'alpha_num' => ':attribute ne doit contenir que des lettres et des nombres.', + 'array' => ':attribute doit être un tableau.', + 'before' => ':attribute doit être une date inférieur à :date.', + 'between' => [ + 'numeric' => ':attribute doit être compris entre :min et :max.', + 'file' => ':attribute doit être compris entre :min et :max kilo-octets.', + 'string' => ':attribute doit être entre :min et :max caractères.', + 'array' => 'attribute doit être entre :min et :max éléments.', + ], + 'boolean' => 'Le champ :attribute doit être vrai ou faux.', + 'confirmed' => 'La confirmation de :attribute ne correspond pas.', + 'date' => ':attribute n’est pas une date valide.', + 'date_format' => ':attribute ne correspond pas au format :format.', + 'different' => ':attribute et :other doivent être différents.', + 'digits' => ':attribute doit avoir :digits chiffres.', + 'digits_between' => ':attribute doit être entre :min et :max chiffres.', + 'email' => ':attribute doit être une adresse courriel valide.', + 'exists' => 'Le :attribute sélectionné est invalide.', + 'distinct' => ':attribute possède une valeur en double.', + 'filled' => 'Le champ :attribute est requis.', + 'image' => ':attribute doit être une image.', + 'in' => 'Le :attribute sélectionné est invalide.', + 'in_array' => 'Le champ :attribute n’existe pas dans :other.', + 'integer' => ':attribute doit être un nombre entier.', + 'ip' => ':attribute doit être une adresse IP valide.', + 'json' => ':attribut doit être une chaîne JSON valide.', + 'max' => [ + 'numeric' => ':attribute ne doit pas dépasser :max.', + 'file' => ':attribute ne peut être plus grand que :max kilo-octets.', + 'string' => ':attribute ne doit pas dépasser :max caractères.', + 'array' => ':attribute ne doit dépasser :max éléments.', + ], + 'mimes' => ':attribute doit être un fichier de type: :values.', + 'min' => [ + 'numeric' => ':attribute doit être au moins de :min.', + 'file' => ':attribute doit être au moins de :min kilo-octets.', + 'string' => ':attribute doit comporter au minimum :min caractères.', + 'array' => ':attribute doit contenir au moins :min éléments.', + ], + 'not_in' => 'Le :attribute sélectionné est invalide.', + 'numeric' => ':attribute doit être un nombre.', + 'present' => 'Le champs :attribute doit être rempli.', + 'regex' => 'Le format de :attribute n’est pas valide.', + 'required' => 'Le champ :attribute est requis.', + 'required_if' => 'Le champ :attribute est requis lorsque :other est :value.', + 'required_unless' => 'Le champ :attribute est requis sauf si :other est dans :values.', + 'required_with' => 'Le champ :attribute est requis lorsque :values est présent.', + 'required_with_all' => 'Le champ :attribute est requis lorsque :values est présent.', + 'required_without' => 'Le champ :attribute est nécessaire quand :values n’est pas présent.', + 'required_without_all' => 'Le champ :attribute est requis lorsque aucune des :values sont présentes.', + 'same' => 'Le :attribute et :other doivent correspondre.', + 'size' => [ + 'numeric' => ':attribute doit faire :size.', + 'file' => 'attribute doit être de :size kilo-octets.', + 'string' => 'L’attribut ":attribute" doit faire :size caractères.', + 'array' => ':attribute doit contenir :size éléments.', + ], + 'string' => ':attribut doit être une chaîne de caractères.', + 'timezone' => ':attribute doit être une zone valide.', + 'unique' => ':attribute a déjà été pris.', + 'url' => 'Le format de :attribute n’est pas valide.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'Message personnalisé', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/fr/cachet.php b/resources/lang/fr/cachet.php index 8582a3eb20e..ee6aa08fcac 100644 --- a/resources/lang/fr/cachet.php +++ b/resources/lang/fr/cachet.php @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "Vous avez été invité à la page de statut de l'équipe :app_name , veuillez suivre le lien suivant pour vous inscire \n:link\nMerci, :app_name", - 'html' => '

Vous avez été invité à la page de statut de l\'équipe :app_name, veuillez suivre le lien suivant pour vous inscrire.

:link

Merci, :app_name

', + 'text' => "Vous avez été invité à la page de statut de l'équipe :app_name , veuillez suivre le lien suivant pour vous inscire \n:link\nMerci, :app_name", + 'html' => '

Vous avez été invité à la page de statut de l\'équipe :app_name, veuillez suivre le lien suivant pour vous inscrire.

:link

Merci, :app_name

', ], ], ], diff --git a/resources/lang/fr/forms.php b/resources/lang/fr/forms.php index 46bea63c0e1..697e06afb2d 100644 --- a/resources/lang/fr/forms.php +++ b/resources/lang/fr/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Nom', 'template' => 'Modèle', - 'twig' => 'Vous pouvez utiliser Twig pour créer des modèles par langues pour les modèles d\'incidents.', + 'twig' => 'Vous pouvez utiliser Twig pour créer des modèles par langues pour les modèles d\'incidents.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Id du site de Piwik', ], 'localization' => [ - 'site-timezone' => 'Fuseau horaire du site', - 'site-locale' => 'Langue du site', - 'date-format' => 'Format de la date', - 'incident-date-format' => 'Format de la date de l\'incident', + 'site-timezone' => 'Fuseau horaire du site', + 'site-locale' => 'Langue du site', + 'date-format' => 'Format de la date', + 'incident-date-format' => 'Format de la date de l\'incident', ], 'security' => [ 'allowed-domains' => 'Domaines autorisés', diff --git a/resources/lang/he-IL/cachet.php b/resources/lang/he-IL/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/he-IL/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/he-IL/dashboard.php b/resources/lang/he-IL/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/he-IL/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/he-IL/forms.php b/resources/lang/he-IL/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/he-IL/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/he-IL/notifications.php b/resources/lang/he-IL/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/he-IL/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/he-IL/pagination.php b/resources/lang/he-IL/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/he-IL/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/he-IL/setup.php b/resources/lang/he-IL/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/he-IL/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/he-IL/validation.php b/resources/lang/he-IL/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/he-IL/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/he/cachet.php b/resources/lang/he/cachet.php index ee3e489907a..d7561f01cd8 100644 --- a/resources/lang/he/cachet.php +++ b/resources/lang/he/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/he/forms.php b/resources/lang/he/forms.php index 1c2805c1aff..ac48176943a 100644 --- a/resources/lang/he/forms.php +++ b/resources/lang/he/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'שם', 'template' => 'תבנית', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/hu-HU/cachet.php b/resources/lang/hu-HU/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/hu-HU/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/hu-HU/dashboard.php b/resources/lang/hu-HU/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/hu-HU/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/hu-HU/forms.php b/resources/lang/hu-HU/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/hu-HU/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/hu-HU/notifications.php b/resources/lang/hu-HU/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/hu-HU/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/hu-HU/pagination.php b/resources/lang/hu-HU/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/hu-HU/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/hu-HU/setup.php b/resources/lang/hu-HU/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/hu-HU/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/hu-HU/validation.php b/resources/lang/hu-HU/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/hu-HU/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/hu/cachet.php b/resources/lang/hu/cachet.php index 4a9525d627b..9105d39e68e 100644 --- a/resources/lang/hu/cachet.php +++ b/resources/lang/hu/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/hu/forms.php b/resources/lang/hu/forms.php index 1586c826c31..460e6493784 100644 --- a/resources/lang/hu/forms.php +++ b/resources/lang/hu/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Név', 'template' => 'Sablon', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/id-ID/cachet.php b/resources/lang/id-ID/cachet.php new file mode 100644 index 00000000000..6559e751e44 --- /dev/null +++ b/resources/lang/id-ID/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Update terakhir :timestamp', + 'status' => [ + 0 => 'Tidak diketahui', + 1 => 'Operasional', + 2 => 'Masalah Kinerja', + 3 => 'Gagal Sebagian', + 4 => 'Kegagalan Sistem', + ], + 'group' => [ + 'other' => 'Komponen Lain', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Tidak ada insiden yang dilaporkan', + 'past' => 'Insiden sebelumnya', + 'stickied' => 'Insiden sticky', + 'scheduled' => 'Pemeliharaan', + 'scheduled_at' => ', dijadwalkan pada :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Dikirim: :timestamp', + 'status' => [ + 1 => 'Investigasi', + 2 => 'Teridentifikasi', + 3 => 'Dimonitor', + 4 => 'Selesai', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Mendatang', + 1 => 'Sedang berlangsung', + 2 => 'Selesai', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]Sistem ini sedang mengalami masalah|[2,*]Beberapa sistem mengalami masalah', + 'major' => '[0,1]Sistem mengalami masalah besar|[2,*]Beberapa sistem mengalami masalah besar', + ], + + 'api' => [ + 'regenerate' => 'Buat ulang API Key', + 'revoke' => 'Cabut API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Jam terakhir', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Daftar', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifikasi', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'Anda saat ini terdaftar untuk semua update.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'Anda saat ini berlangganan update berikut.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Langganan update email.', + 'subscribed' => 'Anda berhasil terdaftar pada notifikasi email, mohon periksa email anda untuk mengkonfirmasi pendaftaran ini.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Pendaftaran newsletter anda berhasil dikonfirmasi. Terima kasih!', + 'manage' => 'Mengelola langganan Anda', + 'unsubscribe' => 'Hapus saya dari update email.', + 'unsubscribed' => 'Langganan email anda sudah dihentikan.', + 'failure' => 'Ada yang salah dengan sistem langganan email.', + 'already-subscribed' => 'Tidak bisa mendaftarkan :email karena sudah berlangganan.', + ], + ], + + 'signup' => [ + 'title' => 'Daftar', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Akun anda berhasil dibuat.', + 'failure' => 'Ada masalah dalam pendaftaran.', + ], + + 'system' => [ + 'update' => 'Ada versi terbaru Cachet yang tersedia. Anda dapat mempelajari cara update di sini!', + ], + + // Modal + 'modal' => [ + 'close' => 'Tutup', + 'subscribe' => [ + 'title' => 'Berlangganan update komponen', + 'body' => 'Masukkan alamat email Anda untuk berlangganan update komponen ini. Jika sudah berlangganan, Anda akan menerima email untuk komponen ini.', + 'button' => 'Daftar', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Rincian dan update tentang insiden :name yang terjadi pada :date', + 'schedule' => 'Rincian tentang jadwal pemeliharaan :name mulai :startDate', + 'subscribe' => 'Berlangganan :app untuk menerima update insiden dan jadwal pemeliharaan', + 'overview' => 'Tetap up to date dengan layanan terbaru dari :app.', + ], + ], + + // Other + 'home' => 'Depan', + 'powered_by' => 'Ditenagai oleh Cachet.', + 'timezone' => 'Waktu dalam :timezone.', + 'about_this_site' => 'Tentang situs ini', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Pasokan Status', + +]; diff --git a/resources/lang/id-ID/dashboard.php b/resources/lang/id-ID/dashboard.php new file mode 100644 index 00000000000..8fc4d62a6e6 --- /dev/null +++ b/resources/lang/id-ID/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Insiden & Penjadwalan', + 'incidents' => 'Insiden', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Buat Template', + 'incident-templates' => 'Template Insiden', + 'updates' => [ + 'title' => 'Update insiden untuk :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Buat update insiden baru', + 'success' => 'Update baru insiden anda berhasil dibuat.', + 'failure' => 'Ada masalah dengan update insiden ini.', + ], + 'edit' => [ + 'title' => 'Edit update insiden', + 'success' => 'Update insiden berhasil diupdate.', + 'failure' => 'Ada masalah saat memperbarui update insiden', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Tambahkan Insiden', + 'success' => 'Insiden sudah ditambahkan.', + 'failure' => 'Ada kesalahan saat menambahkan insiden, silakan coba lagi.', + ], + 'edit' => [ + 'title' => 'Edit insiden', + 'success' => 'Insiden sudah diperbarui.', + 'failure' => 'Ada kesalahan sat mengedit insiden, silakan coba lagi.', + ], + 'delete' => [ + 'success' => 'Insiden sudah dihapus dan tidak akan ditampilkan pada halaman status anda.', + 'failure' => 'Insiden tidak dapat dihapus, silakan coba lagi.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Template Insiden', + 'add' => [ + 'title' => 'Buat template insiden', + 'message' => 'Create your first incident template.', + 'success' => 'Template insiden baru telah dibuat.', + 'failure' => 'Ada masalah dengan template insiden ini.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'Template insiden telah diperbarui.', + 'failure' => 'Ada masalah saat memperbarui template insiden ini', + ], + 'delete' => [ + 'success' => 'Template insiden telah dihapus.', + 'failure' => 'Template insiden tidak dapat dihapus, silakan coba lagi.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Pemeliharaan', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Dijadwalkan pada :timestamp', + 'add' => [ + 'title' => 'Tambahkan Jadwal Pemeliharaan', + 'success' => 'Jadwal sudah ditambahkan.', + 'failure' => 'Ada masalah saat menambahkan jadwal, silakan coba lagi.', + ], + 'edit' => [ + 'title' => 'Edit Jadwal Pemeliharaan', + 'success' => 'Jadwal sudah diperbarui!', + 'failure' => 'Ada masalah saat mengedit jadwal, silakan coba lagi.', + ], + 'delete' => [ + 'success' => 'Pemeliharaan terjadwal telah dihapus dan tidak akan ditampilkan pada halaman status anda.', + 'failure' => 'Pemeliharaan terjadwal tidak bisa dihapus, silakan coba lagi.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Komponen', + 'component_statuses' => 'Status Komponen', + 'listed_group' => 'Dikelompokkan dalam :name', + 'add' => [ + 'title' => 'Tambahkan Komponen', + 'message' => 'Anda perlu menambahkan komponen.', + 'success' => 'Komponen sudah dibuat.', + 'failure' => 'Ada masalah dalam grup komponen, silakan coba lagi.', + ], + 'edit' => [ + 'title' => 'Edit komponen', + 'success' => 'Komponen sudah diperbarui.', + 'failure' => 'Ada masalah dalam grup komponen, silakan coba lagi.', + ], + 'delete' => [ + 'success' => 'Komponen sudah dihapus!', + 'failure' => 'Komponen tidak bisa dihapus, silakan coba lagi.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Grup komponen|Grup komponen', + 'no_components' => 'Anda perlu menambahkan grup komponen.', + 'add' => [ + 'title' => 'Tambahkan grup komponen', + 'success' => 'Grup komponen sudah ditambahkan.', + 'failure' => 'Ada masalah dalam grup komponen, silakan coba lagi.', + ], + 'edit' => [ + 'title' => 'Edit grup komponen', + 'success' => 'Grup komponen sudah diperbarui.', + 'failure' => 'Ada masalah dalam grup komponen, silakan coba lagi.', + ], + 'delete' => [ + 'success' => 'Grup komponen sudah dihapus!', + 'failure' => 'Grup komponen tidak bisa dihapus, silakan coba lagi.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrik', + 'add' => [ + 'title' => 'Buat metrik', + 'message' => 'Anda harus menambahkan metrik.', + 'success' => 'Metrik sudah dibuat.', + 'failure' => 'Ada masalah dalam metrik, silakan coba lagi.', + ], + 'edit' => [ + 'title' => 'Edit metrik', + 'success' => 'Metrik sudah diperbarui.', + 'failure' => 'Ada masalah dalam metrik, silakan coba lagi.', + ], + 'delete' => [ + 'success' => 'Metrik sudah dihapus dan tidak akan ditampilkan pada halaman status anda.', + 'failure' => 'Metrik tidak bisa dihapus, silakan coba lagi.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Berlangganan', + 'description' => 'Pelanggan akan menerima update email ketika insiden dibuat atau komponen diperbarui.', + 'description_disabled' => 'Untuk menggunakan fitur ini, Anda perlu mengizinkan orang untuk mendaftar notifikasi.', + 'verified' => 'Terverifikasi', + 'not_verified' => 'Belum Diverifikasi', + 'subscriber' => ':email, berlangganan :date', + 'no_subscriptions' => 'Berlangganan semua update', + 'global' => 'Berlangganan secara global', + 'add' => [ + 'title' => 'Tambah Pelanggan Baru', + 'success' => 'Pelanggan sudah ditambahkan.', + 'failure' => 'Ada masalah saat menambah langganan, silakan coba lagi.', + 'help' => 'Masukkan setiap pelanggan pada baris baru.', + ], + 'edit' => [ + 'title' => 'Perbarui Pelanggan', + 'success' => 'Pelanggan sudah diupdate.', + 'failure' => 'Ada masalah saat mengedit langganan, silakan coba lagi.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Tim', + 'member' => 'Anggota', + 'profile' => 'Profil', + 'description' => 'Anggota Tim akan bisa menambahkan, mengubah & mengedit komponen dan insiden.', + 'add' => [ + 'title' => 'Tambahkan Anggota Tim', + 'success' => 'Anggota Tim sudah ditambahkan.', + 'failure' => 'Anggota Tim tidak bisa ditambahkan, silakan coba lagi.', + ], + 'edit' => [ + 'title' => 'Perbarui profil', + 'success' => 'Profil sudah diperbarui.', + 'failure' => 'Ada masalah saat memperbarui profil, silakan coba lagi.', + ], + 'delete' => [ + 'success' => 'Pengguna sudah dihapus.', + 'failure' => 'Anggota Tim tidak bisa ditambahkan, silakan coba lagi.', + ], + 'invite' => [ + 'title' => 'Undang Anggota Tim Baru', + 'success' => 'Pengguna sudah diundang.', + 'failure' => 'Undangan tidak terkirim, silakan coba lagi.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Pengaturan', + 'app-setup' => [ + 'app-setup' => 'Pengaturan Aplikasi', + 'images-only' => 'Hanya gambar yang bisa diunggah.', + 'too-big' => 'Berkas yang anda unggah terlalu besar. Mohon unggah gambar dengan ukuran tidak lebih dari :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Kustomisasi', + 'header' => 'Header HTML Kustom', + 'footer' => 'Footer HTML Kustom', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Keamanan', + 'two-factor' => 'User tanpa otentikasi dua-faktor', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Pengaturan sudah disimpan.', + 'failure' => 'Pengaturan tidak bisa disimpan.', + ], + 'credits' => [ + 'credits' => 'Kredit', + 'contributors' => 'Kontributor', + 'license' => 'Cachet adalah proyek open source berlisensi BSD, dirilis oleh Alt Three Services Limited.', + 'backers-title' => 'Pendukung & Sponsor', + 'backers' => 'Jika anda ingin mendukung pengembangan selanjutnya, silakan kunjungi kampanye Cachet di Patreon.', + 'thank-you' => 'Terima kasih pada seluruh :count kontributor.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Masuk', + 'logged_in' => 'Anda sudah login.', + 'welcome' => 'Halo!', + 'two-factor' => 'Silakan masukkan token anda.', + ], + + // Sidebar footer + 'help' => 'Panduan', + 'status_page' => 'Halaman Status', + 'logout' => 'Keluar', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifikasi', + 'awesome' => 'Keren.', + 'whoops' => 'Waduh.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Dukung Cachet', + 'support_subtitle' => 'Lihat halaman Patreon kami!', + 'news' => 'Berita Terbaru', + 'news_subtitle' => 'Dapatkan update terbaru', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Selamat datang di halaman status baru anda :username!', + 'message' => 'Halaman status anda hampir siap! Anda masih perlu mengkonfigurasi beberapa pengaturan', + 'close' => 'Terima kasih!', + 'steps' => [ + 'component' => 'Buat komponen', + 'incident' => 'Buat insiden', + 'customize' => 'Kustomisasi', + 'team' => 'Tambah user', + 'api' => 'Buat token API', + 'two-factor' => 'Otentikasi Dua Faktor', + ], + ], + +]; diff --git a/resources/lang/id-ID/forms.php b/resources/lang/id-ID/forms.php new file mode 100644 index 00000000000..e2005e25bfe --- /dev/null +++ b/resources/lang/id-ID/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Nama Situs', + 'site_domain' => 'Domain', + 'site_timezone' => 'Pilih Zona Waktu', + 'site_locale' => 'Pilih Bahasa', + 'enable_google2fa' => 'Aktifkan Otentikasi Dua Faktor dengan Google', + 'cache_driver' => 'Driver Cache', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Driver Sesi', + 'mail_driver' => 'Driver Email', + 'mail_host' => 'Host Email', + 'mail_address' => 'Alamat Email Pengirim', + 'mail_username' => 'Username Email', + 'mail_password' => 'Password Email', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username atau Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Kode Otentikasi', + 'invalid' => 'Username atau password tidak benar', + 'invalid-token' => 'Token tidak benar', + 'cookies' => 'Mohon aktifkan cookies untuk login.', + 'rate-limit' => 'Melebihi batas.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Nama', + 'status' => 'Status', + 'component' => 'Komponen', + 'component_status' => 'Status Komponen', + 'message' => 'Pesan', + 'message-help' => 'Anda juga bisa menggunakan Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Beritahu subscriber', + 'notify_disabled' => 'Karena adanya pemeliharaan, notifikasi insiden ini atau komponennya akan diprioritaskan.', + 'visibility' => 'Tampilan Insiden', + 'stick_status' => 'Buat Insiden Sticky', + 'stickied' => 'Sticky', + 'not_stickied' => 'Tidak Sticky', + 'public' => 'Bisa dilihat oleh publik', + 'logged_in_only' => 'Hanya bisa dilihat oleh yang login', + 'templates' => [ + 'name' => 'Nama', + 'template' => 'Template', + 'twig' => 'Template Insiden ini bisa menggunakan bahasa template Twig.', + ], + ], + + 'schedules' => [ + 'name' => 'Nama', + 'status' => 'Status', + 'message' => 'Pesan', + 'message-help' => 'Anda juga bisa menggunakan Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Nama', + 'template' => 'Template', + 'twig' => 'Template Insiden ini bisa menggunakan bahasa template Twig.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Nama', + 'status' => 'Status', + 'group' => 'Grup', + 'description' => 'Deskripsi', + 'link' => 'Link', + 'tags' => 'Tag', + 'tags-help' => 'Pisahkan dengan koma.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Nama', + 'collapsing' => 'Buka/Tutup opsi', + 'visible' => 'Selalu buka', + 'collapsed' => 'Standarnya tutup grup', + 'collapsed_incident' => 'Tutup grup, tetapi buka jika ada masalah', + 'visibility' => 'Visibilitas', + 'visibility_public' => 'Terlihat bagi publik', + 'visibility_authenticated' => 'Terlihat hanya untuk yang sudah login', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Nama', + 'description' => 'Deskripsi', + 'start_at' => 'Waktu mulai jadwal', + 'timezone' => 'Zona waktu', + 'schedule_frequency' => 'Frekuensi jadwal (dalam detik)', + 'completion_latency' => 'Latensi penyelesaian (dalam detik)', + 'group' => 'Grup', + 'active' => 'Aktif?', + 'groups' => [ + 'name' => 'Nama Grup', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Nama', + 'suffix' => 'Akhiran', + 'description' => 'Deskripsi', + 'description-help' => 'Anda juga bisa menggunakan Markdown.', + 'display-chart' => 'Tampilkan grafik di halaman status?', + 'default-value' => 'Nilai default', + 'calc_type' => 'Kalkulasi metrik', + 'type_sum' => 'Jumlah', + 'type_avg' => 'Rata-rata', + 'places' => 'Digit Desimal', + 'default_view' => 'Tampilan default', + 'threshold' => 'Dalam rentang berapa menit antara poin metrik?', + 'visibility' => 'Visibilitas', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Nilai', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Nama Situs', + 'site-url' => 'URL', + 'display-graphs' => 'Tampilkan grafik di halaman status?', + 'about-this-page' => 'Tentang halaman ini', + 'days-of-incidents' => 'Berapa hari insiden akan ditampilkan?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Gambar Banner', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Bolehkan pengunjung mendaftar notifikasi email?', + 'suppress_notifications_in_maintenance' => 'Paksa munculnya notifikasi ketika insiden terjadi saat periode pemeliharaan?', + 'skip_subscriber_verification' => 'Lewatkan verifikasi user? (Hati-hati, anda bisa kena spam)', + 'automatic_localization' => 'Otomatis ganti bahasa halaman status anda ke bahasa pengunjung?', + 'enable_external_dependencies' => 'Aktifkan Dependensi Pihak Ketiga (Font Google, Trackers, dll...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Hanya tampilkan hari yang berisi insiden dalam linimasa?', + ], + 'analytics' => [ + 'analytics_google' => 'Kode Google Analytics', + 'analytics_gosquared' => 'Kode GoSquared Analytics', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'ID situs Piwik', + ], + 'localization' => [ + 'site-timezone' => 'Zona Waktu', + 'site-locale' => 'Bahasa', + 'date-format' => 'Format Tanggal', + 'incident-date-format' => 'Format Waktu Insiden', + ], + 'security' => [ + 'allowed-domains' => 'Domain yang dibolehkan', + 'allowed-domains-help' => 'Pisahkan dengan koma. Domain yang ada di atas otomatis akan dibolehkan.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Stylesheet Kustom', + ], + 'theme' => [ + 'background-color' => 'Warna latar belakang', + 'background-fills' => 'Isian latar belakang (Komponen, Insiden, Footer)', + 'banner-background-color' => 'Banner Background Color', + 'banner-padding' => 'Banner Padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Warna teks', + 'dashboard-login' => 'Tampilkan tombol dashboard di footer?', + 'reds' => 'Merah (Digunakan jika ada kesalahan)', + 'blues' => 'Biru (Digunakan jika ada informasi)', + 'greens' => 'Hijau (Digunakan saat operasi berhasil)', + 'yellows' => 'Kuning (Digunakan sebagai peringatan)', + 'oranges' => 'Jingga (Digunakan sebagai pemberitahuan)', + 'metrics' => 'Isian metrik', + 'links' => 'Tautan', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'Token API', + 'api-token-help' => 'Pembuatan ulang token API akan bermasalah jika sudah ada aplikasi lain yang mengakses Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'Tingkatan pengguna', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Mengaktifkan otentikasi dua faktor akan memperkuat keamanan akun anda. Anda perlu mengunduh Google Authenticator atau app sejenis di gadget anda. Saat login anda akan ditanyakan untuk mengisi token yang dibuat oleh app tersebut.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Alamat Email Anggota Tim Anda', + ], + ], + + 'general' => [ + 'timezone' => 'Pilih zona waktu', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Tambah', + 'save' => 'Simpan', + 'update' => 'Perbarui', + 'create' => 'Buat', + 'edit' => 'Edit', + 'delete' => 'Hapus', + 'submit' => 'Kirim', + 'cancel' => 'Batalkan', + 'remove' => 'Buang', + 'invite' => 'Undang', + 'signup' => 'Daftar', + 'manage_updates' => 'Kelola Update', + + // Other + 'optional' => '* Tidak wajib', +]; diff --git a/resources/lang/id-ID/notifications.php b/resources/lang/id-ID/notifications.php new file mode 100644 index 00000000000..62533cbb208 --- /dev/null +++ b/resources/lang/id-ID/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Status Komponen Telah Diperbarui', + 'greeting' => 'Sebuah status komponen telah diperbarui!', + 'content' => 'Status :name telah berubah dari :old_status ke :new_status.', + 'action' => 'Lihat', + ], + 'slack' => [ + 'title' => 'Status Komponen Telah Diperbarui', + 'content' => 'Status :name telah berubah dari :old_status ke :new_status.', + ], + 'sms' => [ + 'content' => 'Status :name telah berubah dari :old_status ke :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Insiden baru telah dilaporkan', + 'greeting' => 'Sebuah insiden baru dilaporkan di :app_name.', + 'content' => 'Insiden :name dilaporkan', + 'action' => 'Lihat', + ], + 'slack' => [ + 'title' => 'Insiden :name Dilaporkan', + 'content' => 'Sebuah insiden baru dilaporkan di :app_name', + ], + 'sms' => [ + 'content' => 'Sebuah insiden baru dilaporkan di :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Insiden Diperbarui', + 'content' => ':name telah diperbarui', + 'title' => ':name telah diperbarui menjadi :new_status', + 'action' => 'Lihat', + ], + 'slack' => [ + 'title' => ':name Diperbarui', + 'content' => ':name telah diperbarui menjadi :new_status', + ], + 'sms' => [ + 'content' => 'Insiden :name telah diperbarui', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Jadwal Baru Sudah Dibuat', + 'content' => ':name dijadwalkan pada :date', + 'title' => 'Pemeliharaan terjadwal baru telah dibuat.', + 'action' => 'Lihat', + ], + 'slack' => [ + 'title' => 'Jadwal Baru Sudah Dibuat!', + 'content' => ':name dijadwalkan pada :date', + ], + 'sms' => [ + 'content' => ':name dijadwalkan pada :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verifikasi Langganan Anda', + 'content' => 'Klik untuk memverifikasi langganan Anda ke halaman status :app_name.', + 'title' => 'Verifikasi langganan Anda ke status halaman :app_name.', + 'action' => 'Verifikasi', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping dari Cachet!', + 'content' => 'Ini adalah test notifikasi dari Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Undangan kamu ada di dalamnya...', + 'content' => 'Anda diundang untuk bergabung dalam halaman status :app_name.', + 'title' => 'Anda diundang untuk bergabung halaman status :app_name.', + 'action' => 'Terima', + ], + ], + ], +]; diff --git a/resources/lang/id-ID/pagination.php b/resources/lang/id-ID/pagination.php new file mode 100644 index 00000000000..ce3d99177ae --- /dev/null +++ b/resources/lang/id-ID/pagination.php @@ -0,0 +1,28 @@ + 'Sebelumnya', + 'next' => 'Berikutnya', + +]; diff --git a/resources/lang/id-ID/setup.php b/resources/lang/id-ID/setup.php new file mode 100644 index 00000000000..7a044deb1e3 --- /dev/null +++ b/resources/lang/id-ID/setup.php @@ -0,0 +1,23 @@ + 'Instalasi', + 'title' => 'Instalasi Cachet', + 'service_details' => 'Detail Layanan', + 'env_setup' => 'Setup lingkungan', + 'status_page_setup' => 'Penyiapan Halaman Status', + 'show_support' => 'Tunjukkan dukungan untuk Cachet? Tampilkan catatan di bawah halaman yang bertaut ke situs Cachet.', + 'admin_account' => 'Akun Administrator', + 'complete_setup' => 'Selesaikan Instalasi', + 'completed' => 'Cachet berhasil dikonfigurasi!', + 'finish_setup' => 'Ke dashboard', +]; diff --git a/resources/lang/id-ID/validation.php b/resources/lang/id-ID/validation.php new file mode 100644 index 00000000000..0a30f4a5809 --- /dev/null +++ b/resources/lang/id-ID/validation.php @@ -0,0 +1,122 @@ + 'Anda harus menerima :attribute .', + 'active_url' => ':attribute bukan merupakan URL yang benar.', + 'after' => ':attribute harus merupakan tanggal setelah :date.', + 'alpha' => ':attribute hanya boleh berisi huruf.', + 'alpha_dash' => ':attribute hanya boleh berisi huruf, angka dan tanda minus.', + 'alpha_num' => ':attribute hanya boleh berisi huruf dan angka.', + 'array' => ':attribute harus merupakan array.', + 'before' => ':attribute harus merupakan tanngga sebelum :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => ':attribute harus antara :min dan :max item.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => ':attribute memiliki nilai duplikasi.', + 'filled' => 'The :attribute field is required.', + 'image' => ':attribute harus merupakan gambar.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => ':attribute tidak ada dalam :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => ':attribute harus merupakan string JSON yang valid.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => ':attribute tidak boleh lebih dari :max item.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => ':attribute minimal harus :min kilobyte.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => ':attribute harus ada.', + 'regex' => 'Format :attribute tidak benar.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'Bagian :attribute harus diisi kecuali :other :values.', + 'required_with' => ':attribute harus diisi jika ada :values.', + 'required_with_all' => ':attribute harus diisi jika ada :values.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => ':attribute harus :size kilobyte.', + 'string' => ':attribute harus :size karakter.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => ':attribute harus merupakan zona yang benar.', + 'unique' => ':attribute sudah ada.', + 'url' => 'Format :attribute tidak benar.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/id/cachet.php b/resources/lang/id/cachet.php index 36934e93da1..1e366f9f185 100644 --- a/resources/lang/id/cachet.php +++ b/resources/lang/id/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "Anda diundang dalam tim Halaman Status :app_name, untuk mendaftar silakan klik tautan berikut \n:link\nTerima kasih, :app_name", - 'html' => '

Anda diundang dalam tim Halaman Status :app_name, untuk mendaftar silakan klik tautan berikut.

:link

Terima kasih, :app_name

', + 'text' => "Anda diundang dalam tim Halaman Status :app_name, untuk mendaftar silakan klik tautan berikut \n:link\nTerima kasih, :app_name", + 'html' => '

Anda diundang dalam tim Halaman Status :app_name, untuk mendaftar silakan klik tautan berikut.

:link

Terima kasih, :app_name

', ], ], ], diff --git a/resources/lang/id/forms.php b/resources/lang/id/forms.php index 1d6721a6d6d..4f941592743 100644 --- a/resources/lang/id/forms.php +++ b/resources/lang/id/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Nama', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'ID situs Piwik', ], 'localization' => [ - 'site-timezone' => 'Zona Waktu', - 'site-locale' => 'Bahasa', - 'date-format' => 'Format Tanggal', - 'incident-date-format' => 'Format Waktu Insiden', + 'site-timezone' => 'Zona Waktu', + 'site-locale' => 'Bahasa', + 'date-format' => 'Format Tanggal', + 'incident-date-format' => 'Format Waktu Insiden', ], 'security' => [ 'allowed-domains' => 'Domain yang dibolehkan', diff --git a/resources/lang/it-IT/cachet.php b/resources/lang/it-IT/cachet.php new file mode 100644 index 00000000000..1bfd09cbba0 --- /dev/null +++ b/resources/lang/it-IT/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Ultimo aggiornamento :timestamp', + 'status' => [ + 0 => 'Sconosciuto', + 1 => 'Operativo', + 2 => 'Problemi sulle prestazioni', + 3 => 'Disservizio parziale', + 4 => 'Interruzione del servizio', + ], + 'group' => [ + 'other' => 'Altri componenti', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Nessun incidente segnalato', + 'past' => 'Problemi passati', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', programmata il :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Analisi', + 2 => 'Identificato', + 3 => 'Osservazione', + 4 => 'Risolto', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In corso', + 2 => 'Completato', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Rigenera API Key', + 'revoke' => 'Revoca API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Ultima Ora', + 'hourly' => 'Ultime 12 Ore', + 'weekly' => 'Settimana', + 'monthly' => 'Mese', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Iscriviti', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifiche', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'Sei attualmente iscritto a tutti gli aggiornamenti.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'Sei attualmente iscritto ai seguenti suggerimenti.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Iscriviti agli aggiornamenti via email.', + 'subscribed' => 'Ti sei appena iscritto agli aggiornamenti email, controlla la tua casella per confermare la sottoscrizione', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'La tua iscrizione è stata confermata. Grazie!', + 'manage' => 'Gestisci la tua iscrizione', + 'unsubscribe' => 'Annulla l\'iscrizione agli aggiornamenti email.', + 'unsubscribed' => 'La tua iscrizione è stata rimossa.', + 'failure' => 'Qualcosa è andato storto con l\'iscrizione.', + 'already-subscribed' => 'Non è possibile iscrivere :email perchè risulta già iscritto.', + ], + ], + + 'signup' => [ + 'title' => 'Registrati', + 'username' => 'Nome Utente', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Il tuo account è stato creato.', + 'failure' => 'Qualcosa non ha funzionato durante la procedura d\'iscrizione.', + ], + + 'system' => [ + 'update' => 'E\' disponibile una nuova versione di Cachet. Scopri come fare qui!', + ], + + // Modal + 'modal' => [ + 'close' => 'Chiudi', + 'subscribe' => [ + 'title' => 'Iscriviti agli aggiornamenti dei componenti', + 'body' => 'Inserisci il tuo indirizzo e-mail per iscriverti agli aggiornamenti di questo componente. Se sei già iscritto, riceverai già email relative a questo componente.', + 'button' => 'Iscriviti', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Resta informato sugli ultimi aggiornamenti dei servizi di :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'Informazioni sul sito', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/it-IT/dashboard.php b/resources/lang/it-IT/dashboard.php new file mode 100644 index 00000000000..188d9a18af4 --- /dev/null +++ b/resources/lang/it-IT/dashboard.php @@ -0,0 +1,304 @@ + 'Pannello amministrativo', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidenti', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Crea Modello', + 'incident-templates' => 'Modelli di segnalazione', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Riporta un problema', + 'success' => 'Segnalazione aggiunta.', + 'failure' => 'C\'è stato un problema con l\'aggiunta dela segnalazione, si prega di riprovare.', + ], + 'edit' => [ + 'title' => 'Modifica una segnalazione', + 'success' => 'Segnalazione aggiornata.', + 'failure' => 'C\'è stato un problema con la modifica della segnalazione, si prega di riprovare.', + ], + 'delete' => [ + 'success' => 'La segnalazione è stata eliminata e non verrà visualizzata sulla tua pagina di stato.', + 'failure' => 'Non è stato possibile eliminare la segnalazione, si prega di riprovare.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Modelli di segnalazione', + 'add' => [ + 'title' => 'Crea un modello di segnalazione', + 'message' => 'Create your first incident template.', + 'success' => 'Il tuo nuovo modello di segnalazione è stato creato.', + 'failure' => 'Qualcosa è andato storto con il modello di segnalazione.', + ], + 'edit' => [ + 'title' => 'Modifica Modello', + 'success' => 'Il modello di segnalazione è stato aggiornato.', + 'failure' => 'Qualcosa è andato storto con l\'aggiornamento del modello di segnalazione', + ], + 'delete' => [ + 'success' => 'Il modello di segnalazione è stato eliminato.', + 'failure' => 'Non è stato possibile eliminare il modello di segnalazione, si prega di riprovare.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Pianificato alle :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Componenti', + 'component_statuses' => 'Stati del componente', + 'listed_group' => 'Raggruppati sotto :name', + 'add' => [ + 'title' => 'Aggiungi un componente', + 'message' => 'È necessario aggiungere un componente.', + 'success' => 'Componente creato.', + 'failure' => 'Qualcosa è andato storto con il componente, si prega di riprovare.', + ], + 'edit' => [ + 'title' => 'Modifica un componente', + 'success' => 'Componente aggiornato.', + 'failure' => 'Qualcosa è andato storto con il componente, si prega di riprovare.', + ], + 'delete' => [ + 'success' => 'Il componente è stato eliminato!', + 'failure' => 'Non è stato possibile eliminare il componente, si prega di riprovare.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Gruppo del componente | Gruppi del componente', + 'no_components' => 'È necessario aggiungere un gruppo di componenti.', + 'add' => [ + 'title' => 'Aggiungi un gruppo di componenti', + 'success' => 'Gruppo di componenti aggiunto.', + 'failure' => 'Qualcosa è andato storto con il componente, si prega di riprovare.', + ], + 'edit' => [ + 'title' => 'Modifica un gruppo di componenti', + 'success' => 'Gruppo di componenti aggiornato.', + 'failure' => 'Qualcosa è andato storto con il componente, si prega di riprovare.', + ], + 'delete' => [ + 'success' => 'Il gruppo di componenti è stato eliminato!', + 'failure' => 'Non è stato possibile eliminare il gruppo di componenti, si prega di riprovare.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metriche', + 'add' => [ + 'title' => 'Crea una metrica', + 'message' => 'Si dovrebbe aggiungere un metodo di misura.', + 'success' => 'Metrica creata.', + 'failure' => 'Qualcosa è andato storto con il metodo di misura, si prega di riprovare.', + ], + 'edit' => [ + 'title' => 'Modifica un metodo di misura', + 'success' => 'Metodo di misura aggiornato.', + 'failure' => 'Qualcosa è andato storto con il metodo di misura, si prega di riprovare.', + ], + 'delete' => [ + 'success' => 'Il metodo di misura è stato eliminato e non verrà più visualizzato nella tua pagina di stato.', + 'failure' => 'Non è stato possibile eliminare il metodo di misura, si prega di riprovare.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Iscritti', + 'description' => 'Gli iscritti riceveranno aggiornamenti via email quando vengono create le segnalazioni o vengono aggiornati i componenti vengono.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verificato', + 'not_verified' => 'Non Verificato', + 'subscriber' => ': email, iscritta :date', + 'no_subscriptions' => 'Iscritto a tutti gli aggiornamenti', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Aggiungi un nuovo iscritto', + 'success' => 'L\'iscritto è stato aggiunto!', + 'failure' => 'Qualcosa è andato storto con l\'aggiunta dell\'iscritto, si prega di riprovare.', + 'help' => 'Immettere ogni iscritto su una nuova riga.', + ], + 'edit' => [ + 'title' => 'Aggiorna l\'iscritto', + 'success' => 'L\'iscritto è stato aggiornato!', + 'failure' => 'Qualcosa è andato storto con la modifica dell\'iscritto, si prega di riprovare.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Gruppo', + 'member' => 'Membro', + 'profile' => 'Profilo', + 'description' => 'I membri del gruppo potranno aggiungere, modificare ed editare componenti e segnalazioni.', + 'add' => [ + 'title' => 'Aggiungi un nuovo membro del gruppo', + 'success' => 'Membro del gruppo aggiunto.', + 'failure' => 'Non è stato possibile aggiungere il membro del gruppo, si prega di riprovare.', + ], + 'edit' => [ + 'title' => 'Aggiorna il profilo', + 'success' => 'Profilo aggiornato.', + 'failure' => 'Qualcosa è andato storto con l\'aggiornamento del profilo, si prega di riprovare.', + ], + 'delete' => [ + 'success' => 'Il membro del gruppo è stato eliminato e non avrà più accesso al pannello amministrativo!', + 'failure' => 'Non è stato possibile aggiungere il membro del gruppo, si prega di riprovare.', + ], + 'invite' => [ + 'title' => 'Invita un nuovo membro del gruppo', + 'success' => 'Un invito è stato inviato', + 'failure' => 'Non è stato possibile inviare l\'invito, si prega di riprovare.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Impostazioni', + 'app-setup' => [ + 'app-setup' => 'Installazione dell\'applicazione', + 'images-only' => 'Possono essere caricate solo le immagini.', + 'too-big' => 'Il file che hai caricato è troppo grande. Caricare un\'immagine più piccola di :size', + ], + 'analytics' => [ + 'analytics' => 'Statistiche', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localizzazione', + ], + 'customization' => [ + 'customization' => 'Personalizzazione', + 'header' => 'Header HTML personalizzato', + 'footer' => 'Footer HTML personalizzato', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Sicurezza', + 'two-factor' => 'Utenti senza autenticazione in due passaggi', + ], + 'stylesheet' => [ + 'stylesheet' => 'Foglio di stile', + ], + 'theme' => [ + 'theme' => 'Tema', + ], + 'edit' => [ + 'success' => 'Impostazioni salvate.', + 'failure' => 'Le impostazioni non possono essere salvate.', + ], + 'credits' => [ + 'credits' => 'Riconoscimenti', + 'contributors' => 'Collaboratori', + 'license' => 'Cachet è un progetto open source con licenza BSD-3, rilasciato da Alt tre Services Limited.', + 'backers-title' => 'Sostenitori e sponsor', + 'backers' => 'Se si desidera sostenere lo sviluppo futuro, scopri la campagna Cachet Patreon.', + 'thank-you' => 'Grazie a tutti i :count contributori.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Accedi', + 'logged_in' => 'Sei connesso.', + 'welcome' => 'Bentornato!', + 'two-factor' => 'Inserisci il tuo token.', + ], + + // Sidebar footer + 'help' => 'Aiuto', + 'status_page' => 'Pagina di Stato', + 'logout' => 'Disconnetti', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifiche', + 'awesome' => 'Meraviglioso.', + 'whoops' => 'Ops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Supporta Cachet', + 'support_subtitle' => 'Visita la nostra pagina Patreon!', + 'news' => 'Utime notizie', + 'news_subtitle' => 'Ottieni l\'aggiornamento più recente', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Benvenuto nella tua nuova pagina di stato!', + 'message' => 'La pagina di stato è quasi pronta! È possibile configurare queste impostazioni supplementari', + 'close' => 'Portami direttamente al mio pannello amministrativo', + 'steps' => [ + 'component' => 'Crea componenti', + 'incident' => 'Crea segnalazioni', + 'customize' => 'Personalizza', + 'team' => 'Aggiungi utenti', + 'api' => 'Genera un API token', + 'two-factor' => 'Autenticazione con verifica in due passaggi', + ], + ], + +]; diff --git a/resources/lang/it-IT/forms.php b/resources/lang/it-IT/forms.php new file mode 100644 index 00000000000..50d1263aeda --- /dev/null +++ b/resources/lang/it-IT/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Nome Utente', + 'password' => 'Password', + 'site_name' => 'Nome del sito', + 'site_domain' => 'Dominio del sito', + 'site_timezone' => 'Seleziona il tuo fuso orario', + 'site_locale' => 'Seleziona la lingua', + 'enable_google2fa' => 'Abilita la Verifica in Due Passaggi di Google', + 'cache_driver' => 'Driver per la cache', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Driver per la sessione', + 'mail_driver' => 'Driver di posta elettronica', + 'mail_host' => 'Host di posta elettronica', + 'mail_address' => 'Posta dall\'indirizzo', + 'mail_username' => 'Nome utente di posta', + 'mail_password' => 'Password di posta elettronica', + ], + + // Login form fields + 'login' => [ + 'login' => 'Nome Utente o Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Codice di Autenticazione', + 'invalid' => 'Il nome utente o la password non sono validi', + 'invalid-token' => 'Token non valido', + 'cookies' => 'È necessario abilitare i cookie per effettuare l\'accesso.', + 'rate-limit' => 'Sei troppo veloce.', + 'remember_me' => 'Ricordami', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Nome', + 'status' => 'Stato', + 'component' => 'Componente', + 'component_status' => 'Component Status', + 'message' => 'Messaggio', + 'message-help' => 'Si può anche utilizzare il linguaggio di Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notificare gli iscritti?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Visibilità segnalazione', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Visibile al pubblico', + 'logged_in_only' => 'Visibile solo agli utenti registrati', + 'templates' => [ + 'name' => 'Nome', + 'template' => 'Modello', + 'twig' => 'I modelli di segnalazione possono usare il linguaggio di templating Twig.', + ], + ], + + 'schedules' => [ + 'name' => 'Nome', + 'status' => 'Stato', + 'message' => 'Messaggio', + 'message-help' => 'Si può anche utilizzare il linguaggio di Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Nome', + 'template' => 'Modello', + 'twig' => 'I modelli di segnalazione possono usare il linguaggio di templating Twig.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Nome', + 'status' => 'Stato', + 'group' => 'Gruppo', + 'description' => 'Descrizione', + 'link' => 'Collegamento', + 'tags' => 'Etichette', + 'tags-help' => 'Separati da virgole.', + 'enabled' => 'Componente abilitato?', + + 'groups' => [ + 'name' => 'Nome', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Sempre espanso', + 'collapsed' => 'Comprimere il gruppo come impostazione predefinita', + 'collapsed_incident' => 'Comprimere il gruppo, ma espandere se ci sono problemi', + 'visibility' => 'Visibilità', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Nome', + 'description' => 'Descrizione', + 'start_at' => 'Schedule start time', + 'timezone' => 'Fuso orario', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Gruppo', + 'active' => 'Attivo?', + 'groups' => [ + 'name' => 'Nome del Gruppo', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Nome', + 'suffix' => 'Suffisso', + 'description' => 'Descrizione', + 'description-help' => 'Si può anche utilizzare il linguaggio di Markdown.', + 'display-chart' => 'Visualizzare il grafico nella pagina di stato?', + 'default-value' => 'Valore predefinito', + 'calc_type' => 'Calcolo del metodo di misura', + 'type_sum' => 'Somma', + 'type_avg' => 'Media', + 'places' => 'Cifre decimali', + 'default_view' => 'Vista predefinita', + 'threshold' => 'Quanti minuti di soglia tra metriche punti?', + 'visibility' => 'Visibilità', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Sempre nascosto', + + 'points' => [ + 'value' => 'Valore', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Nome del sito', + 'site-url' => 'URL del Sito', + 'display-graphs' => 'Visualizzare i grafici nella pagina di stato?', + 'about-this-page' => 'Informazioni sulla pagina', + 'days-of-incidents' => 'Quanti giorni di segnalazioni mostrare?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Immagine del banner', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Permettere alle persone di iscriversi alle notifiche via email?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Tradurre automaticamente la tua pagina di stato nella lingua del visitatore?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Codice Google Analytics', + 'analytics_gosquared' => 'Codice GoSquared Analytics', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Id del sito Piwik', + ], + 'localization' => [ + 'site-timezone' => 'Fuso orario del sito', + 'site-locale' => 'Lingua del sito', + 'date-format' => 'Formato della data', + 'incident-date-format' => 'Formato timestamp della segnalazione', + ], + 'security' => [ + 'allowed-domains' => 'Domini consentiti', + 'allowed-domains-help' => 'Separati da virgola. Il dominio impostato sopra è automaticamente consentito per impostazione predefinita.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Foglio di stile personalizzato', + ], + 'theme' => [ + 'background-color' => 'Colore di sfondo', + 'background-fills' => 'Riempimento sfondo (componenti, segnalazioni, footer)', + 'banner-background-color' => 'Colore di sfondo del banner', + 'banner-padding' => 'Padding del banner', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Colore del testo', + 'dashboard-login' => 'Mostrare pulsante del pannello amministrativo nel footer?', + 'reds' => 'Rosso (utilizzato per gli errori)', + 'blues' => 'Blu (usato per le informazioni)', + 'greens' => 'Verde (usato per operazioni andate a buon fine)', + 'yellows' => 'Giallo (utilizzato per gli avvisi)', + 'oranges' => 'Orange (usato per notifiche)', + 'metrics' => 'Riempimento di metriche', + 'links' => 'Collegamenti', + ], + ], + + 'user' => [ + 'username' => 'Nome Utente', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Rigenerare il tuo API token impedirà alle applicazioni esistenti di accedere a Cachet.', + 'gravatar' => 'Cambia la tua immagine del profilo presso Gravatar.', + 'user_level' => 'Livello utente', + 'levels' => [ + 'admin' => 'Amministratore', + 'user' => 'Utente', + ], + '2fa' => [ + 'help' => 'L\'attivazione dell\'autenticazione in due passaggi aumenta la sicurezza del tuo account. Sarà necessario scaricare Google Authenticator o un\'app simile sul tuo dispositivo mobile. Quando si effettua l\'accesso dovrai fornire un token generato dall\'applicazione.', + ], + 'team' => [ + 'description' => 'Invita i membri del gruppo inserendo qui i loro indirizzi e-mail.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Aggiungi', + 'save' => 'Salva', + 'update' => 'Aggiorna', + 'create' => 'Crea', + 'edit' => 'Modifica', + 'delete' => 'Elimina', + 'submit' => 'Invia', + 'cancel' => 'Cancella', + 'remove' => 'Rimuovi', + 'invite' => 'Invita', + 'signup' => 'Registrati', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Opzionale', +]; diff --git a/resources/lang/it-IT/notifications.php b/resources/lang/it-IT/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/it-IT/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/it-IT/pagination.php b/resources/lang/it-IT/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/it-IT/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/it-IT/setup.php b/resources/lang/it-IT/setup.php new file mode 100644 index 00000000000..2808e17393c --- /dev/null +++ b/resources/lang/it-IT/setup.php @@ -0,0 +1,23 @@ + 'Installazione', + 'title' => 'Installa Cachet', + 'service_details' => 'Dettagli del Servizio', + 'env_setup' => 'Configurazione dell\'Ambiente', + 'status_page_setup' => 'Installazione della Pagina di Stato', + 'show_support' => 'Mostrare supporto per Cachet?', + 'admin_account' => 'Account Amministratore', + 'complete_setup' => 'Installazione Completata', + 'completed' => 'Cachet è stato configurato con successo!', + 'finish_setup' => 'Vai alla bacheca', +]; diff --git a/resources/lang/it-IT/validation.php b/resources/lang/it-IT/validation.php new file mode 100644 index 00000000000..5fccb3f3438 --- /dev/null +++ b/resources/lang/it-IT/validation.php @@ -0,0 +1,122 @@ + ':attribute deve essere accettato.', + 'active_url' => ':attribute non è un URL valido.', + 'after' => ':attribute deve essere una data successiva al :date.', + 'alpha' => ':attribute può contenere solo lettere.', + 'alpha_dash' => ':attribute può contenere solo lettere, numeri e trattini.', + 'alpha_num' => ':attribute può contenere solo lettere e numeri.', + 'array' => ':attribute deve essere un array.', + 'before' => ':attribute deve contenere una data precedente al :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => ':attributo deve avere tra :min e :max elementi.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'Il campo :attribute ha un valore duplicato.', + 'filled' => 'The :attribute field is required.', + 'image' => ':attribute deve contenere un\'immagine.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'Il campo :attribute non esiste in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => ':attribute deve essere una stringa JSON valida.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => ':attribute non può avere più di :max elementi.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => ':attribute deve essere almeno :min kilobyte.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'Il campo :attribute deve essere presente.', + 'regex' => 'Il formato di :attribute non è valido.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'Il campo :attribute è obbligatorio a meno che :other è presente in :values.', + 'required_with' => 'Il campo :attribute è obbligatorio quando :values è presente.', + 'required_with_all' => 'Il campo :attribute è obbligatorio quando :values è presente.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => ':attribute deve essere di :size kilobytes.', + 'string' => ':attribute deve essere di :size caratteri.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => ':attribute deve essere una zona valida.', + 'unique' => 'Il valore del campo :attribute è già stato preso.', + 'url' => 'Il formato di :attribute non è valido.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'messaggio personalizzato', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/it/cachet.php b/resources/lang/it/cachet.php index 394934bba42..954fdf51b21 100644 --- a/resources/lang/it/cachet.php +++ b/resources/lang/it/cachet.php @@ -81,8 +81,8 @@ 'failure' => 'Qualcosa è andato storto con l\'iscrizione.', 'already-subscribed' => 'Non è possibile iscrivere :email perchè risulta già iscritto.', 'verify' => [ - 'text' => "Please confirm your email subscription to :app_name status updates.\n:link", - 'html' => '

Please confirm your email subscription to :app_name status updates.

', + 'text' => "Conferma l'iscrizione a :app_name. \n:link", + 'html' => 'Per favore conferma la tua iscrizione tramite email su :app_name', 'button' => 'Conferma iscrizione', ], 'maintenance' => [ @@ -93,8 +93,8 @@ ], 'component' => [ 'subject' => 'Aggiornamento di stato del componente', - 'text' => 'Lo stato del componente: nome_componente è cambiato. Il nuovo stato del componente è :component_human_status.\nGrazie,: app_name', - 'html' => '

Lo stato del componente: nome_componente è cambiato. Il nuovo stato del componente è :component_human_status.

Grazie, :app_name

', + 'text' => 'Lo stato del componente: :component_name è cambiato. Il nuovo stato del componente è :component_human_status.\nGrazie, :app_name', + 'html' => '

Lo stato del componente :component_name è cambiato. Il nuovo stato del componente è :component_human_status.

Grazie, :app_name

', 'tooltip-title' => 'Iscriviti alle notifiche di :component_name.', ], ], @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "Sei stato invitato nel team :app_name status page, per iscriverti segui il prossimo link.\n:link\nGrazie, :app_name", - 'html' => '

Sei stato invitato nel team :app_name status page, per iscriverti segui il prossimo link.

:link

Grazie, :app_name

', + 'text' => "Sei stato invitato nel team :app_name status page, per iscriverti segui il prossimo link.\n:link\nGrazie, :app_name", + 'html' => '

Sei stato invitato nel team :app_name status page, per iscriverti segui il prossimo link.

:link

Grazie, :app_name

', ], ], ], diff --git a/resources/lang/it/forms.php b/resources/lang/it/forms.php index 685a1e2f559..5d583803243 100644 --- a/resources/lang/it/forms.php +++ b/resources/lang/it/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Nome', 'template' => 'Modello', - 'twig' => 'I modelli di segnalazione possono usare il linguaggio di templating Twig.', + 'twig' => 'I modelli di segnalazione possono usare il linguaggio di templating Twig.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Id del sito Piwik', ], 'localization' => [ - 'site-timezone' => 'Fuso orario del sito', - 'site-locale' => 'Lingua del sito', - 'date-format' => 'Formato della data', - 'incident-date-format' => 'Formato timestamp della segnalazione', + 'site-timezone' => 'Fuso orario del sito', + 'site-locale' => 'Lingua del sito', + 'date-format' => 'Formato della data', + 'incident-date-format' => 'Formato timestamp della segnalazione', ], 'security' => [ 'allowed-domains' => 'Domini consentiti', diff --git a/resources/lang/ja-JP/cachet.php b/resources/lang/ja-JP/cachet.php new file mode 100644 index 00000000000..4240b90f77e --- /dev/null +++ b/resources/lang/ja-JP/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => '最終更新 :timestamp', + 'status' => [ + 0 => '不明', + 1 => '稼働中', + 2 => 'パフォーマンスに関する問題あり', + 3 => '一部停止中', + 4 => '大規模な停止中', + ], + 'group' => [ + 'other' => 'その他のコンポーネント', + ], + 'select_all' => '全て選択', + 'deselect_all' => '全て選択解除', + ], + + // Incidents + 'incidents' => [ + 'none' => 'インシデントはありません', + 'past' => 'インシデント履歴', + 'stickied' => '固定している障害情報', + 'scheduled' => '計画メンテナンス', + 'scheduled_at' => ', 予定日時 :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => '掲載日時 :timestamp', + 'status' => [ + 1 => '調査中', + 2 => '特定済み', + 3 => '監視中', + 4 => '修正済み', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => '近日中', + 1 => '進行中', + 2 => '完了', + ], + ], + + // Service Status + 'service' => [ + 'good' => '全システムが正常に稼働しています', + 'bad' => '一部のシステムに問題が発生しています', + 'major' => 'システムに深刻な問題が発生しています', + ], + + 'api' => [ + 'regenerate' => 'APIキーの再生成', + 'revoke' => 'APIキーの削除', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => '過去1時間', + 'hourly' => '過去12時間', + 'weekly' => '週', + 'monthly' => '月', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => '購読の解除', + 'button' => '購読', + 'manage_subscription' => '購読の管理', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => '通知の管理', + 'no_subscriptions' => '現在、すべてのアップデートを購読しています。', + 'update_subscription' => '購読の管理', + 'my_subscriptions' => '現在、以下のアップデートを購読しています。', + 'manage_at_link' => '購読の管理', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'メールによるアップデート情報の購読', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'あなたのメール購読を確認しました。ありがとうございます!', + 'manage' => '購読の管理', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'メールの購読が取り消されました。', + 'failure' => '購読に失敗しました。', + 'already-subscribed' => '既に購読しているので :email の購読ができません。', + ], + ], + + 'signup' => [ + 'title' => '新規登録', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'アカウントが作成されました。', + 'failure' => '新規登録に失敗しました。', + ], + + 'system' => [ + 'update' => 'Cachetの新しいバージョンがあります。アップデートの方法についてはこちらを参照して下さい!', + ], + + // Modal + 'modal' => [ + 'close' => '閉じる', + 'subscribe' => [ + 'title' => 'コンポーネントのアップデート情報を購読する', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => '購読', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => ':date に発生した:nameの障害情報', + 'schedule' => ':startDate に予定している:name のメンテナンスの詳細', + 'subscribe' => ':app の障害情報とメンテナンス情報を購読する', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'ホーム', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'このサイトについて', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'ステータスフィード', + +]; diff --git a/resources/lang/ja-JP/dashboard.php b/resources/lang/ja-JP/dashboard.php new file mode 100644 index 00000000000..1c90b57b581 --- /dev/null +++ b/resources/lang/ja-JP/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => '計画メンテナンス', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/ja-JP/forms.php b/resources/lang/ja-JP/forms.php new file mode 100644 index 00000000000..cc51002bd6c --- /dev/null +++ b/resources/lang/ja-JP/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => '新規登録', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/ja-JP/notifications.php b/resources/lang/ja-JP/notifications.php new file mode 100644 index 00000000000..d0165184dc6 --- /dev/null +++ b/resources/lang/ja-JP/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => '購読の管理', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/ja-JP/pagination.php b/resources/lang/ja-JP/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/ja-JP/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/ja-JP/setup.php b/resources/lang/ja-JP/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/ja-JP/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/ja-JP/validation.php b/resources/lang/ja-JP/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/ja-JP/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/ja/cachet.php b/resources/lang/ja/cachet.php index 9a77e6293dc..a4e1c132176 100644 --- a/resources/lang/ja/cachet.php +++ b/resources/lang/ja/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/ja/forms.php b/resources/lang/ja/forms.php index 2e509548773..f88b14f8fe2 100644 --- a/resources/lang/ja/forms.php +++ b/resources/lang/ja/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => '名前', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/ko-KR/cachet.php b/resources/lang/ko-KR/cachet.php new file mode 100644 index 00000000000..e55e925fce2 --- /dev/null +++ b/resources/lang/ko-KR/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => '이전 문제', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', :timestamp 에 예정됨', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => '확인됨', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => '구독', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => '이메일 구독 신청.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => '이메일 구독 취소', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => '구독', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => '이 사이트에 대해', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => '상태 ', + +]; diff --git a/resources/lang/ko-KR/dashboard.php b/resources/lang/ko-KR/dashboard.php new file mode 100644 index 00000000000..fd0835171a7 --- /dev/null +++ b/resources/lang/ko-KR/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => '문제 추가', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => '문제 수정', + 'success' => '문제가 수정되었습니다.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => '문제 템플릿 생성하기', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => '문제 템플릿 수정', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => '구성요소 추가', + 'message' => '구성요소를 추가해야 합니다.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => '구성요소 수정', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => '구성요소 그룹 추가', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => '구성요소 그룹 수정', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => '통계', + 'add' => [ + 'title' => '통계 추가', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => '통계 수정', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => '팀 멤버는 구성요소와 문제를 추가하고 수정 할 수 있습니다.', + 'add' => [ + 'title' => '새 팀 멤버 추가', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => '프로필 수정', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => '애플리케이션 설정', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => '좋아요.', + 'whoops' => '이런...', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => '상태 페이지는 거의 다 준비 되었습니다! 추가 설정을 해보세요', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/ko-KR/forms.php b/resources/lang/ko-KR/forms.php new file mode 100644 index 00000000000..a00cd8cb042 --- /dev/null +++ b/resources/lang/ko-KR/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => '잘못된 토큰n', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => '구성요소', + 'component_status' => 'Component Status', + 'message' => '메시지', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => '구독자에게 알림', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => '로그인한 사용자만 볼 수 있음', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => '메시지', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => '쉼표로 구분.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => '상태 페이지에 차트 보이기', + 'default-value' => '기본값', + 'calc_type' => '통계 계산', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => '상태 페이지에 그래프 보이기', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => '이메일 알림을 받기 위한 회원가입 허용', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics 코드', + 'analytics_gosquared' => 'GoSquared Analytics 코드', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik 사이트 id', + ], + 'localization' => [ + 'site-timezone' => '사이트 시간대', + 'site-locale' => '사이트 언어', + 'date-format' => '날짜 형식', + 'incident-date-format' => '문제 Timestamp 형식', + ], + 'security' => [ + 'allowed-domains' => '허용된 도메인', + 'allowed-domains-help' => '쉼표로 구분. 위에 설정된 도메인은 기본적으로 자동 허용 됩니다.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner Background Color', + 'banner-padding' => 'Banner Padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => '수정', + 'create' => '생성', + 'edit' => '수정', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* 선택사항', +]; diff --git a/resources/lang/ko-KR/notifications.php b/resources/lang/ko-KR/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/ko-KR/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/ko-KR/pagination.php b/resources/lang/ko-KR/pagination.php new file mode 100644 index 00000000000..6c89ecad750 --- /dev/null +++ b/resources/lang/ko-KR/pagination.php @@ -0,0 +1,28 @@ + '이전', + 'next' => '다음', + +]; diff --git a/resources/lang/ko-KR/setup.php b/resources/lang/ko-KR/setup.php new file mode 100644 index 00000000000..8b940c6d6cf --- /dev/null +++ b/resources/lang/ko-KR/setup.php @@ -0,0 +1,23 @@ + '설치', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Cachet 에 대한 지원을 표시', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/ko-KR/validation.php b/resources/lang/ko-KR/validation.php new file mode 100644 index 00000000000..3c1b6e1e899 --- /dev/null +++ b/resources/lang/ko-KR/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => ':attribute 는 문자, 숫자, -만 포함할 수 있습니다.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => ':attribute 는 :date 이전의 날짜 여야 합니다.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/ko/cachet.php b/resources/lang/ko/cachet.php index 6e4b3869c61..fb97101243e 100644 --- a/resources/lang/ko/cachet.php +++ b/resources/lang/ko/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => ":app_name 팀의 상태페이지에 초대되었습니다. 가입하시려면 다음 링크를 눌러주세요.\n:link\n감사합니다, :app_name", - 'html' => '

:app_name 팀의 상태페이지에 초대되었습니다. 가입하시려면 다음 링크를 눌러주세요.

+ 'text' => ":app_name 팀의 상태페이지에 초대되었습니다. 가입하시려면 다음 링크를 눌러주세요.\n:link\n감사합니다, :app_name", + 'html' => '

:app_name 팀의 상태페이지에 초대되었습니다. 가입하시려면 다음 링크를 눌러주세요.

:link

감사합니다, :app_name

', ], ], diff --git a/resources/lang/ko/dashboard.php b/resources/lang/ko/dashboard.php index 308c37ef50f..abb34a6de13 100644 --- a/resources/lang/ko/dashboard.php +++ b/resources/lang/ko/dashboard.php @@ -11,15 +11,17 @@ return [ - 'dashboard' => '대시보드', + 'dashboard' => '대시보드', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', // Incidents 'incidents' => [ - 'title' => '문제 및 예정', + 'title' => 'Incidents & Schedule', 'incidents' => '문제', 'logged' => '{0} 아무 문제가 없습니다, 잘하고 있어요.|하나의 문제에 대한 로깅이 있습니다.|:count 개의 문제가 리포트 되었습니다.', 'incident-create-template' => '템플릿 생성', 'incident-templates' => '문제 템플릿', + 'updates' => '{0} Zero Updates|One Update|:count Updates', 'add' => [ 'title' => '문제 추가', 'success' => 'Incident added.', @@ -34,6 +36,10 @@ 'success' => 'The incident has been deleted and will not show on your status page.', 'failure' => 'The incident could not be deleted, please try again.', ], + 'update' => [ + 'title' => 'Create new incident update', + 'subtitle' => 'Add an update to :incident', + ], // Incident templates 'templates' => [ @@ -58,17 +64,17 @@ // Incident Maintenance 'schedule' => [ - 'schedule' => '예약 된 유지 관리', + 'schedule' => '예정된 유지 보수', 'logged' => '{0} There are no schedules, good work.|You have logged one schedule.|You have reported :count schedules.', 'scheduled_at' => ':timestamp 에 예정됨', 'add' => [ 'title' => 'Add Scheduled Maintenance', - 'success' => 'Schedule added.', + 'success' => '일정이 추가되었습니다.', 'failure' => 'Something went wrong adding the schedule, please try again.', ], 'edit' => [ 'title' => 'Edit Scheduled Maintenance', - 'success' => 'Schedule has been updated!', + 'success' => '일정이 업데이트 되었습니다!', 'failure' => 'Something went wrong editing the schedule, please try again.', ], 'delete' => [ @@ -85,13 +91,13 @@ 'add' => [ 'title' => '구성요소 추가', 'message' => '구성요소를 추가해야 합니다.', - 'success' => 'Component created.', - 'failure' => 'Something went wrong with the component, please try again.', + 'success' => '구성요소가 생성되었습니다.', + 'failure' => 'Something went wrong with the component group, please try again.', ], 'edit' => [ 'title' => '구성요소 수정', - 'success' => 'Component updated.', - 'failure' => 'Something went wrong with the component, please try again.', + 'success' => '구성요소가 수정되었습니다.', + 'failure' => 'Something went wrong with the component group, please try again.', ], 'delete' => [ 'success' => 'The component has been deleted!', @@ -104,16 +110,16 @@ 'no_components' => '구성 요소 그룹을 추가 해야 합니다.', 'add' => [ 'title' => '구성요소 그룹 추가', - 'success' => 'Component group added.', + 'success' => '구성요소 그룹이 추가되었습니다.', 'failure' => 'Something went wrong with the component group, please try again.', ], 'edit' => [ 'title' => '구성요소 그룹 수정', - 'success' => 'Component group updated.', + 'success' => '구성요소 그룹이 수정되었습니다.', 'failure' => 'Something went wrong with the component group, please try again.', ], 'delete' => [ - 'success' => 'Component group has been deleted!', + 'success' => '구성 요소 그룹이 삭제 되었습니다!', 'failure' => 'The component group could not be deleted, please try again.', ], ], @@ -164,15 +170,15 @@ 'team' => '팀', 'member' => '멤버', 'profile' => '프로필', - 'description' => '팀 멤버는 구성요소와 문제를 추가하고 수정 할 수 있습니다.', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', 'add' => [ 'title' => '새 팀 멤버 추가', - 'success' => 'Team member added.', + 'success' => '팀 멤버가 추가되었습니다', 'failure' => 'The team member could not be added, please try again.', ], 'edit' => [ 'title' => '프로필 수정', - 'success' => 'Profile updated.', + 'success' => '프로필이 수정되었습니다.', 'failure' => 'Something went wrong updating the profile, please try again.', ], 'delete' => [ @@ -197,13 +203,24 @@ 'analytics' => [ 'analytics' => 'Analytics', ], + 'log' => [ + 'log' => 'Log', + ], 'localization' => [ 'localization' => 'Localization', ], 'customization' => [ - 'customization' => 'Customization', - 'header' => 'Custom Header HTML', - 'footer' => 'Custom Footer HTML', + 'customization' => '사용자 설정', + 'header' => '사용자 지정 헤더 HTML', + 'footer' => '사용자 지정 바닥글 HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], ], 'security' => [ 'security' => '보안', @@ -220,8 +237,8 @@ 'failure' => '설정을 저장할 수 없습니다.', ], 'credits' => [ - 'credits' => 'Credits', - 'contributors' => 'Contributors', + 'credits' => '제작진', + 'contributors' => '도움 주신 분들', 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', 'backers-title' => 'Backers & Sponsors', 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', @@ -254,14 +271,14 @@ 'support' => 'Support Cachet', 'support_subtitle' => 'Check out our Patreon page!', 'news' => 'Latest News', - 'news_subtitle' => 'Get the latest updates', + 'news_subtitle' => 'Get the latest update', ], // Welcome modal 'welcome' => [ - 'welcome' => 'Welcome to your new status page!', + 'welcome' => 'Welcome to your new status page, :username!', 'message' => '상태 페이지는 거의 다 준비 되었습니다! 추가 설정을 해보세요', - 'close' => 'Take me straight to my dashboard', + 'close' => 'I\'m good thanks!', 'steps' => [ 'component' => '구성요소 만들기', 'incident' => '문제 만들기', diff --git a/resources/lang/ko/forms.php b/resources/lang/ko/forms.php index 3f3de773a86..41c461516e3 100644 --- a/resources/lang/ko/forms.php +++ b/resources/lang/ko/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => '이름', 'template' => '템플릿', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik 사이트 id', ], 'localization' => [ - 'site-timezone' => '사이트 시간대', - 'site-locale' => '사이트 언어', - 'date-format' => '날짜 형식', - 'incident-date-format' => '문제 Timestamp 형식', + 'site-timezone' => '사이트 시간대', + 'site-locale' => '사이트 언어', + 'date-format' => '날짜 형식', + 'incident-date-format' => '문제 Timestamp 형식', ], 'security' => [ 'allowed-domains' => '허용된 도메인', diff --git a/resources/lang/mn-MN/cachet.php b/resources/lang/mn-MN/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/mn-MN/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/mn-MN/dashboard.php b/resources/lang/mn-MN/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/mn-MN/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/mn-MN/forms.php b/resources/lang/mn-MN/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/mn-MN/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/mn-MN/notifications.php b/resources/lang/mn-MN/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/mn-MN/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/mn-MN/pagination.php b/resources/lang/mn-MN/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/mn-MN/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/mn-MN/setup.php b/resources/lang/mn-MN/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/mn-MN/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/mn-MN/validation.php b/resources/lang/mn-MN/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/mn-MN/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/nl-NL/cachet.php b/resources/lang/nl-NL/cachet.php new file mode 100644 index 00000000000..1e1377ac375 --- /dev/null +++ b/resources/lang/nl-NL/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Laatst bijgewerkt :timestamp', + 'status' => [ + 0 => 'Onbekend', + 1 => 'Operationeel', + 2 => 'Prestatieproblemen', + 3 => 'Gedeeltelijke Storing', + 4 => 'Grote Storing', + ], + 'group' => [ + 'other' => 'Andere componenten', + ], + 'select_all' => 'Alles selecteren', + 'deselect_all' => 'Alles deselecteren', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Geen incidenten gemeld', + 'past' => 'Oude incidenten', + 'stickied' => 'Vastgezette incidenten', + 'scheduled' => 'Gepland onderhoud', + 'scheduled_at' => ', gepland :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Geplaatst op :timestamp', + 'status' => [ + 1 => 'In onderzoek', + 2 => 'Geïdentificeerd', + 3 => 'Aan het opvolgen', + 4 => 'Opgelost', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Aankomend', + 1 => 'In Behandeling', + 2 => 'Voltooid', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]Systeem operationeel|[2,*]Alle systemen zijn operationeel', + 'bad' => '[0,1] Het systeem ondervindt momenteel problemen |[2,Inf] Sommige systemen ondervinden momenteel problemen', + 'major' => '[0,1] Het systeem ondervindt momenteel een grote storing|[2,Inf] Sommige systemen ondervinden momenteel een grote storing', + ], + + 'api' => [ + 'regenerate' => 'Hergenereer API-sleutel', + 'revoke' => 'API-sleutel Intrekken', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Laatste uur', + 'hourly' => 'Laatste 12 uur', + 'weekly' => 'Wekelijks', + 'monthly' => 'Maandelijks', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Abonneer je op statuswijzigingen en incident updates', + 'unsubscribe' => 'Abonnement opzeggen', + 'button' => 'Abonneren', + 'manage_subscription' => 'Abonnement beheren', + 'manage' => [ + 'notifications' => 'Notificaties', + 'notifications_for' => 'Beheer meldingen voor', + 'no_subscriptions' => 'Je bent momenteel geabonneerd op alle updates.', + 'update_subscription' => 'Abonnement bijwerken', + 'my_subscriptions' => 'Je bent momenteel geabonneerd op de volgende updates.', + 'manage_at_link' => 'Beheer uw abonnementen op: link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Abonneren op e-mail updates.', + 'subscribed' => 'U bent geabonneerd op e-mail notificaties, controleer uw e-mail om uw abonnement te bevestigen.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Uw e-mail abonnement is bevestigd. Bedankt!', + 'manage' => 'Beheer je abonnement', + 'unsubscribe' => 'Afmelden voor e-mail updates.', + 'unsubscribed' => 'Uw e-mail abonnement is opgezegd.', + 'failure' => 'Er ging iets fout tijdens het aanmelden.', + 'already-subscribed' => 'Kan niet aanmelden voor :email omdat deze momenteel al is aangemeld.', + ], + ], + + 'signup' => [ + 'title' => 'Registreer', + 'username' => 'Gebruikersnaam', + 'email' => 'E-mail', + 'password' => 'Wachtwoord', + 'success' => 'Uw account is aangemaakt.', + 'failure' => 'Er is iets misgegaan met het inschrijven.', + ], + + 'system' => [ + 'update' => 'Er is een nieuwere versie van Cachet beschikbaar. Kijk hoe je moet updaten hier!', + ], + + // Modal + 'modal' => [ + 'close' => 'Sluiten', + 'subscribe' => [ + 'title' => 'Abonneren voor component updates', + 'body' => 'Vul uw e-mailadres in om updates te krijgen voor dit component. Als u al ingeschreven bent, krijgt u al emails voor dit component.', + 'button' => 'Abonneren', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Informatie en updates over het :name incident van :date', + 'schedule' => 'Informatie over het :name onderhoud gepland op :startDate', + 'subscribe' => 'Abonneer je op :app om updates te ontvangen van incidenten en geplande onderhoudsperioden', + 'overview' => 'Blijf op de hoogte van de laatste service updates over :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Mogelijk gemaakt door Cachet.', + 'timezone' => 'Tijden worden getoond in :timezone.', + 'about_this_site' => 'Over deze website', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/nl-NL/dashboard.php b/resources/lang/nl-NL/dashboard.php new file mode 100644 index 00000000000..7faeb6b609f --- /dev/null +++ b/resources/lang/nl-NL/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'De Cachet instellingen-map is niet schrijfbaar. Zorg er voor dat ./bootstrap/cachet schrijfbaar is voor de webserver.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidenten & Onderhoud', + 'incidents' => 'Incidenten', + 'logged' => '{0}Top, er zijn geen incidenten.|[1]Je hebt één incident gerapporteerd.|[2,*]Je hebt :count incidenten gerapporteerd.', + 'incident-create-template' => 'Maak template', + 'incident-templates' => 'Incident Sjablonen', + 'updates' => [ + 'title' => 'Incident updates voor :incident', + 'count' => '{0}Geen updates|[1]Één update|[2]Twee updates|[3,*]Meerdere updates', + 'add' => [ + 'title' => 'Maak een nieuwe incident update', + 'success' => 'Je nieuwe incident update is aangemaakt.', + 'failure' => 'Er is iets misgegaan met de incident update.', + ], + 'edit' => [ + 'title' => 'Incident update bewerken', + 'success' => 'De incident update is bijgewerkt.', + 'failure' => 'Er is een fout opgetreden bij het wijzigen van de incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Meld een incident', + 'success' => 'Incident toegevoegd.', + 'failure' => 'Er is een fout opgetreden tijdens het toevoegen van het incident, probeer het opnieuw.', + ], + 'edit' => [ + 'title' => 'Wijzig een incident', + 'success' => 'Incident bijgewerkt.', + 'failure' => 'Er is een fout opgetreden bij het wijzigen van het incident, probeer het opnieuw.', + ], + 'delete' => [ + 'success' => 'Het incident is verwijderd en zal niet meer worden weergegeven op de statuspagina.', + 'failure' => 'Het incident kon niet worden verwijderd, probeer het opnieuw.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Sjablonen', + 'add' => [ + 'title' => 'Creëer een incident template', + 'message' => 'Voeg een incident template toe.', + 'success' => 'Je nieuwe incident template is aangemaakt.', + 'failure' => 'Er is iets misgegaan met de incident template.', + ], + 'edit' => [ + 'title' => 'Wijzig template', + 'success' => 'De incident template is bijgewerkt.', + 'failure' => 'Er is een fout opgetreden bij het wijzigen van het incident template', + ], + 'delete' => [ + 'success' => 'De incident template is verwijderd.', + 'failure' => 'De incident template kon niet worden verwijderd, probeer het opnieuw.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Gepland onderhoud', + 'logged' => '{0}Er zijn geen geplande onderhoudsmomenten.|[1]Er is één onderhoudsmoment gepland.|[2,*]Er zijn :count geplande onderhoudsmomenten.', + 'scheduled_at' => 'Gepland op :timestamp', + 'add' => [ + 'title' => 'Gepland onderhoud toevoegen', + 'success' => 'Onderhoud toegevoegd.', + 'failure' => 'Er ging iets mis met het toevoegen van het geplande onderhoud, probeer het opnieuw.', + ], + 'edit' => [ + 'title' => 'Gepland onderhoud bewerken', + 'success' => 'Gepland onderhoud is bijgewerkt!', + 'failure' => 'Er ging iets mis met het wijzigen van het geplande onderhoud, probeer het opnieuw.', + ], + 'delete' => [ + 'success' => 'Het geplande onderhoud is verwijderd en zal niet worden getoond op de statuspagina.', + 'failure' => 'Het geplande onderhoud kon niet worden verwijderd, probeer het opnieuw.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Componenten', + 'component_statuses' => 'Onderdeel statussen', + 'listed_group' => 'Gegroepeerd onder :name', + 'add' => [ + 'title' => 'Voeg een component toe', + 'message' => 'Gelieve een onderdeel toe te voegen.', + 'success' => 'Onderdeel aangemaakt.', + 'failure' => 'Er ging iets mis met de component group, probeer het opnieuw.', + ], + 'edit' => [ + 'title' => 'Wijzig een component', + 'success' => 'Onderdeel bijgewerkt.', + 'failure' => 'Er ging iets mis met de component group, probeer het opnieuw.', + ], + 'delete' => [ + 'success' => 'Het component is verwijderd!', + 'failure' => 'Het component kon niet worden verwijderd, probeer het opnieuw.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Onderdeel groep|Onderdeel groepen', + 'no_components' => 'U moet een componentgroep toevoegen.', + 'add' => [ + 'title' => 'Componentgroep toevoegen', + 'success' => 'Componentengroep toegevoegd.', + 'failure' => 'Er ging iets mis met de component group, probeer het opnieuw.', + ], + 'edit' => [ + 'title' => 'Componentgroep bewerken', + 'success' => 'Componentengroep bijgewerkt.', + 'failure' => 'Er ging iets mis met de component group, probeer het opnieuw.', + ], + 'delete' => [ + 'success' => 'De componentgroep is verwijderd!', + 'failure' => 'De componentengroep kon niet worden verwijderd, probeer het opnieuw.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Statistieken', + 'add' => [ + 'title' => 'Meting aanmaken', + 'message' => 'Voeg een meting toe.', + 'success' => 'Meting aangemaakt.', + 'failure' => 'Er ging iets mis met de metingen, probeer het opnieuw.', + ], + 'edit' => [ + 'title' => 'Meting bewerken', + 'success' => 'Meting bijgewerkt.', + 'failure' => 'Er ging iets mis met de metingen, probeer het opnieuw.', + ], + 'delete' => [ + 'success' => 'De meting is verwijderd en zal niet meer worden weergegeven op de statuspagina.', + 'failure' => 'De meting kon niet verwijderd worden, probeer het opnieuw.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Abonnees', + 'description' => 'Abonnees ontvangen een email update wanneer er incidenten zijn gemaakt of componenten worden bijgewerkt.', + 'description_disabled' => 'Om deze functie te gebruiken, moet u mensen aanmelden voor meldingen toestaan.', + 'verified' => 'Geverifiëerd', + 'not_verified' => 'Niet geverifiëerd', + 'subscriber' => ':email, geabonneerd op :date', + 'no_subscriptions' => 'Geabonneerd op alle updates', + 'global' => 'Globaal geabonneerd', + 'add' => [ + 'title' => 'Voeg een nieuwe abonnee toe', + 'success' => 'Abonnee is toegevoegd!', + 'failure' => 'Er ging iets mis met het toevoegen van de abonnee, probeer het opnieuw.', + 'help' => 'Vul elke abonnee in op een nieuwe regel.', + ], + 'edit' => [ + 'title' => 'Abonnee bijwerken', + 'success' => 'Abonnee is gewijzigd!', + 'failure' => 'Er ging iets verkeerd met bewerken van de abonnee, probeer het opnieuw.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Lid', + 'profile' => 'Profiel', + 'description' => 'Teamleden zullen onderdelen en incidenten kunnen aanpassen & toevoegen.', + 'add' => [ + 'title' => 'Voeg een nieuw teamlid toe', + 'success' => 'Teamlid toegevoegd.', + 'failure' => 'Het teamlid kon niet worden toegevoegd, probeer het opnieuw.', + ], + 'edit' => [ + 'title' => 'Profiel bijwerken', + 'success' => 'Profiel bijgewerkt.', + 'failure' => 'Er ging iets mis met het bijwerken van het profiel, probeer het opnieuw.', + ], + 'delete' => [ + 'success' => 'Het teamlid is verwijderd en heeft geen toegang meer tot het dashboard!', + 'failure' => 'Het teamlid kon niet worden toegevoegd, probeer het opnieuw.', + ], + 'invite' => [ + 'title' => 'Nodig een nieuw teamlid uit', + 'success' => 'De uitnodiging is verzonden', + 'failure' => 'De uitnodiging kon niet verzonden worden, probeer het opnieuw.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Instellingen', + 'app-setup' => [ + 'app-setup' => 'Applicatie Installatie', + 'images-only' => 'Alleen afbeeldingen kunnen worden geüpload.', + 'too-big' => 'Het bestand dat u heeft geüpload is te groot. Upload een afbeelding kleiner dan :size', + ], + 'analytics' => [ + 'analytics' => 'Analyses', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Lokalisatie', + ], + 'customization' => [ + 'customization' => 'Aanpassing', + 'header' => 'Aangepaste Header HTML', + 'footer' => 'Aangepaste voettekst HTML', + ], + 'mail' => [ + 'mail' => 'E-mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notificatie van Cachet', + 'body' => 'Dit is een test notificatie van Cachet.', + ], + ], + 'security' => [ + 'security' => 'Beveiliging', + 'two-factor' => 'Gebruikers zonder authenticatie in twee stappen', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Thema', + ], + 'edit' => [ + 'success' => 'Instellingen bewaard.', + 'failure' => 'Instellingen kunnen niet worden opgeslagen.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Bijdragers', + 'license' => 'Cachet is een open source product onder de BSD-3 licentie, uitgebracht door Alt Three Services Limited.', + 'backers-title' => 'Donateurs & Sponsoren', + 'backers' => 'Als u de toekomstige ontwikkeling wilt ondersteunen, bezoek de Cachet Patreon campagne.', + 'thank-you' => 'Onze dank gaat uit naar elk van de :count verschillende bijdragers.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'U bent ingelogd.', + 'welcome' => 'Welkom Terug!', + 'two-factor' => 'Voer uw token in.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Pagina', + 'logout' => 'Uitloggen', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notificaties', + 'awesome' => 'Geweldig.', + 'whoops' => 'Oepsie.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Steun Cachet', + 'support_subtitle' => 'Bekijk onze Patreon pagina!', + 'news' => 'Laatste nieuws', + 'news_subtitle' => 'Ontvang de laatste updates', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welkom op je statuspagina!', + 'message' => 'Uw statuspagina is bijna klaar! U kunt deze extra instellingen configureren', + 'close' => 'Stuur me direct naar mijn dashboard', + 'steps' => [ + 'component' => 'Onderdelen maken', + 'incident' => 'Incidenten aanmaken', + 'customize' => 'Aanpassen', + 'team' => 'Gebruikers toevoegen', + 'api' => 'API-token genereren', + 'two-factor' => 'Authenticatie in twee stappen', + ], + ], + +]; diff --git a/resources/lang/nl-NL/forms.php b/resources/lang/nl-NL/forms.php new file mode 100644 index 00000000000..f8cdc67b7ff --- /dev/null +++ b/resources/lang/nl-NL/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'E-mail', + 'username' => 'Gebruikersnaam', + 'password' => 'Wachtwoord', + 'site_name' => 'Site naam', + 'site_domain' => 'Site Domein', + 'site_timezone' => 'Selecteer uw tijdzone', + 'site_locale' => 'Selecteer uw taal', + 'enable_google2fa' => 'Schakel Google twee factor authenticatie in', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Sessie Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Server', + 'mail_address' => 'Mail Van-Adres', + 'mail_username' => 'Mail Gebruikersnaam', + 'mail_password' => 'Mail Wachtwoord', + ], + + // Login form fields + 'login' => [ + 'login' => 'Gebruikersnaam of e-mail', + 'email' => 'E-mail', + 'password' => 'Wachtwoord', + '2fauth' => 'Authenticatie Code', + 'invalid' => 'Ongeldige gebruikersnaam of wachtwoord', + 'invalid-token' => 'Ongeldig token', + 'cookies' => 'U moet cookies inschakelen om in te loggen.', + 'rate-limit' => 'Snelheids limiet overschreden.', + 'remember_me' => 'Blijf ingelogd', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Naam', + 'status' => 'Status', + 'component' => 'Onderdeel', + 'component_status' => 'Onderdeel status', + 'message' => 'Boodschap', + 'message-help' => 'U kan ook gebruik maken van Markdown.', + 'occurred_at' => 'Wanneer heeft dit incident plaatsgevonden?', + 'notify_subscribers' => 'Houd abonnees op de hoogte?', + 'notify_disabled' => 'Vanwege geplande onderhoudswerken zullen meldingen over dit incident of onderdelen hiervan worden onderdrukt.', + 'visibility' => 'Incident Zichtbaarheid', + 'stick_status' => 'Incident Vastzetten', + 'stickied' => 'Vastgezet', + 'not_stickied' => 'Niet Vastgezet', + 'public' => 'Zichtbaar voor publiek', + 'logged_in_only' => 'Alleen zichtbaar voor ingelogde gebruikers', + 'templates' => [ + 'name' => 'Naam', + 'template' => 'Sjabloon', + 'twig' => 'Incident Templates kunnen gebruik maken van de Twig template taal.', + ], + ], + + 'schedules' => [ + 'name' => 'Naam', + 'status' => 'Status', + 'message' => 'Boodschap', + 'message-help' => 'U kan ook gebruik maken van Markdown.', + 'scheduled_at' => 'Voor wanneer is dit onderhoudsschema bedoeld?', + 'completed_at' => 'Wanneer was dit onderhoud voltooid?', + 'templates' => [ + 'name' => 'Naam', + 'template' => 'Sjabloon', + 'twig' => 'Incident Templates kunnen gebruik maken van de Twig template taal.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Naam', + 'status' => 'Status', + 'group' => 'Groep', + 'description' => 'Omschrijving', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Komma gescheiden.', + 'enabled' => 'Component ingeschakeld?', + + 'groups' => [ + 'name' => 'Naam', + 'collapsing' => 'Opties uitklappen/inklappen', + 'visible' => 'Altijd uitgevouwen', + 'collapsed' => 'Vouw de groep standaard samen', + 'collapsed_incident' => 'De groep samenvouwen, maar uitklappen als er problemen zijn.', + 'visibility' => 'Zichtbaarheid', + 'visibility_public' => 'Zichtbaar voor iedereen', + 'visibility_authenticated' => 'Alleen zichtbaar voor ingelogde gebruikers', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Naam', + 'description' => 'Omschrijving', + 'start_at' => 'Geplande starttijd', + 'timezone' => 'Tijdzone', + 'schedule_frequency' => 'Geplande frequentie (in seconden)', + 'completion_latency' => 'Oplostijd (in seconden)', + 'group' => 'Groep', + 'active' => 'Actief?', + 'groups' => [ + 'name' => 'Groepsnaam', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Naam', + 'suffix' => 'Achtervoegsel', + 'description' => 'Omschrijving', + 'description-help' => 'U kan ook gebruik maken van Markdown.', + 'display-chart' => 'Grafiek tonen op statuspagina?', + 'default-value' => 'Standaardwaarde', + 'calc_type' => 'Berekening van de metingen', + 'type_sum' => 'Som', + 'type_avg' => 'Gemiddelde', + 'places' => 'Decimalen', + 'default_view' => 'Standaardweergave', + 'threshold' => 'Hoeveel minuten tussen de metrische punten?', + 'visibility' => 'Zichtbaarheid', + 'visibility_authenticated' => 'Zichtbaar voor ingelogde gebruikers', + 'visibility_public' => 'Zichtbaar voor iedereen', + 'visibility_hidden' => 'Altijd verborgen', + + 'points' => [ + 'value' => 'Waarde', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site naam', + 'site-url' => 'Site URL', + 'display-graphs' => 'Grafieken tonen op statuspagina?', + 'about-this-page' => 'Over deze pagina', + 'days-of-incidents' => 'Hoeveel dagen moeten incidenten getoond worden?', + 'time_before_refresh' => 'Statuspagina verversingssnelheid (in seconden)', + 'major_outage_rate' => 'Drempelwaarde voor grote onderbreking (in %)', + 'banner' => 'Banner afbeelding', + 'banner-help' => 'Bij voorkeur geen afbeeldingen breder dan 930 pixels uploaden', + 'subscribers' => 'Bezoekers toestaan om te abonneren op e-mail notificaties?', + 'suppress_notifications_in_maintenance' => 'Onderdruk meldingen wanneer incident tijdens de onderhoudingsperiode voordoet?', + 'skip_subscriber_verification' => 'Verificatie van gebruikers overslaan? (Let op, je kunt gespamd worden)', + 'automatic_localization' => 'Stel de taal van de bezoeker in als standaardtaal voor deze bezoeker?', + 'enable_external_dependencies' => 'Schakel afhankelijkheden van derden in (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Toon de tijdzone op de statuspagina', + 'only_disrupted_days' => 'Alleen dagen met incidenten op de tijdlijn tonen?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics-code', + 'analytics_gosquared' => 'GoSquared Analytics-code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Site-id van Piwik', + ], + 'localization' => [ + 'site-timezone' => 'Website tijdzone', + 'site-locale' => 'Taal van de site', + 'date-format' => 'Datum formaat', + 'incident-date-format' => 'Incident tijdsaanduiding', + ], + 'security' => [ + 'allowed-domains' => 'Toegestane domeinen', + 'allowed-domains-help' => 'Door komma\'s gescheiden. Het hierboven ingestelde domein is automatisch standaard toegelaten.', + 'always-authenticate' => 'Altijd aanmelden', + 'always-authenticate-help' => 'Aanmelding vereist om ieder Cachet pagina te bekijken', + ], + 'stylesheet' => [ + 'custom-css' => 'Aangepaste Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Achtergrondkleur', + 'background-fills' => 'Achtergrond opvulling (components, incidents, footer)', + 'banner-background-color' => 'Banner achtergrond kleur', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Banner op volledige breedte tonen?', + 'text-color' => 'Tekstkleur', + 'dashboard-login' => 'Laat dashboard knop zien in de footer?', + 'reds' => 'Rood (voor errors)', + 'blues' => 'Blauw (voor informatie)', + 'greens' => 'Groen (voor succes)', + 'yellows' => 'Geel (voor waarschuwingen)', + 'oranges' => 'Oranje (voor notificaties)', + 'metrics' => 'Metrics opvulling', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Gebruikersnaam', + 'email' => 'E-mail', + 'password' => 'Wachtwoord', + 'api-token' => 'API-token', + 'api-token-help' => 'Het opnieuw genereren van je API-token zorgt ervoor dat bestaande applicaties geen toegang meer hebben tot Cachet.', + 'gravatar' => 'Verander je profielfoto op Gravatar.', + 'user_level' => 'Gebruikersniveau', + 'levels' => [ + 'admin' => 'Beheerder', + 'user' => 'Gebruiker', + ], + '2fa' => [ + 'help' => 'Het inschakelen van two-factor authenticatie verhoogt de veiligheid van uw account. U zult een applicatie zoals Google Authenticator of een vergelijkbare applicatie moeten downloaden op uw mobiele apparaat. Wanneer u inlogt wordt u gevraagd om een token in te voeren welke door de applicatie wordt gegenereerd.', + ], + 'team' => [ + 'description' => 'Nodig je teamleden uit door hier hun e-mailadres in te vullen.', + 'email' => 'Mailadres van uw teamleden', + ], + ], + + 'general' => [ + 'timezone' => 'Selecteer Tijdzone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Toevoegen', + 'save' => 'Opslaan', + 'update' => 'Bijwerken', + 'create' => 'Aanmaken', + 'edit' => 'Bewerken', + 'delete' => 'Verwijderen', + 'submit' => 'Versturen', + 'cancel' => 'Annuleren', + 'remove' => 'Verwijderen', + 'invite' => 'Uitnodigen', + 'signup' => 'Registreer', + 'manage_updates' => 'Updates beheren', + + // Other + 'optional' => '* Optioneel', +]; diff --git a/resources/lang/nl-NL/notifications.php b/resources/lang/nl-NL/notifications.php new file mode 100644 index 00000000000..f163b799ca0 --- /dev/null +++ b/resources/lang/nl-NL/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component status bijgewerkt', + 'greeting' => 'De status van een component is bijgewerkt!', + 'content' => ':name status is veranderd van :old_status naar :new_status.', + 'action' => 'Tonen', + ], + 'slack' => [ + 'title' => 'Component status bijgewerkt', + 'content' => ':name status is veranderd van :old_status naar :new_status.', + ], + 'sms' => [ + 'content' => ':name status is veranderd van :old_status naar :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Nieuw incident gemeld', + 'greeting' => 'Er is een nieuw incident gemeld voor :app_name.', + 'content' => 'Incident :name is gerapporteerd', + 'action' => 'Tonen', + ], + 'slack' => [ + 'title' => 'Incident :name is gerapporteerd', + 'content' => 'Er is een nieuw incident gemeld voor :app_name', + ], + 'sms' => [ + 'content' => 'Er is een nieuw incident gemeld voor :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident bijgewerkt', + 'content' => ':name is bijgewerkt', + 'title' => ':name is bijgewerkt naar :new_status', + 'action' => 'Tonen', + ], + 'slack' => [ + 'title' => ':name is bijgewerkt', + 'content' => ':name is bijgewerkt naar :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name is bijgewerkt', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Nieuw tijdschema aangemaakt', + 'content' => ':name is ingepland voor :date', + 'title' => 'Nieuw gepland onderhoud aangemaakt.', + 'action' => 'Tonen', + ], + 'slack' => [ + 'title' => 'Nieuw tijdschema aangemaakt!', + 'content' => ':name is ingepland voor :date', + ], + 'sms' => [ + 'content' => ':name is ingepland voor :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Bevestig je inschrijving', + 'content' => 'Klik om je inschrijving op :app_name statuspagina te bevestigen.', + 'title' => 'Bevestig je inschrijving voor de :app_name statuspagina.', + 'action' => 'Verifiëren', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Abonnement beheren', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping van Cachet!', + 'content' => 'Dit is een testnotificatie van Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Je uitnodiging zit in deze e-mail...', + 'content' => 'Je bent uitgenodigd voor de :app_name statuspagina.', + 'title' => 'Je bent uitgenodigd voor :app_name statuspagina.', + 'action' => 'Accepteer', + ], + ], + ], +]; diff --git a/resources/lang/nl-NL/pagination.php b/resources/lang/nl-NL/pagination.php new file mode 100644 index 00000000000..7810e8a7083 --- /dev/null +++ b/resources/lang/nl-NL/pagination.php @@ -0,0 +1,28 @@ + 'Vorige', + 'next' => 'Volgende', + +]; diff --git a/resources/lang/nl-NL/setup.php b/resources/lang/nl-NL/setup.php new file mode 100644 index 00000000000..ccd676774a2 --- /dev/null +++ b/resources/lang/nl-NL/setup.php @@ -0,0 +1,23 @@ + 'Installatie', + 'title' => 'Installeer Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Omgevingsconfiguratie', + 'status_page_setup' => 'Installatie statuspagina', + 'show_support' => 'Steun voor Cachet tonen?', + 'admin_account' => 'Beheerdersaccount', + 'complete_setup' => 'Voltooi Installatie', + 'completed' => 'Cachet is succesvol geconfigureerd!', + 'finish_setup' => 'Ga naar het dashboard', +]; diff --git a/resources/lang/nl-NL/validation.php b/resources/lang/nl-NL/validation.php new file mode 100644 index 00000000000..555418621f3 --- /dev/null +++ b/resources/lang/nl-NL/validation.php @@ -0,0 +1,122 @@ + ':attribute moet worden aanvaard.', + 'active_url' => ':attribute is geen correcte URL.', + 'after' => ':attribute moet een datum later dan :date zijn.', + 'alpha' => ':attribute mag alleen letters bevatten.', + 'alpha_dash' => ':attribute mag alleen letters, cijfers, en streepjes bevatten.', + 'alpha_num' => ':attribute mag enkel letters en nummers bevatten.', + 'array' => ':attribute moet een reeks zijn.', + 'before' => ':attribute moet een datum vóór :date zijn.', + 'between' => [ + 'numeric' => ':attribute moet tussen :min en de :max zijn.', + 'file' => ':attribute moet tussen de :min en de :max aantal kilobytes zijn.', + 'string' => ':attribute moet tussen de :min en :max karakters lang zijn.', + 'array' => ':attribute moet tussen :min en :max items hebben.', + ], + 'boolean' => 'Het :attribute veld moet waar of onwaar zijn.', + 'confirmed' => 'De :attribute bevestiging komt niet overeen.', + 'date' => ':attribute is geen geldige datum.', + 'date_format' => ':attribute komt niet overeen met het volgende formaat :format.', + 'different' => ':attribute en :other mogen niet hetzelfde zijn.', + 'digits' => ':attribute moet uit :digits cijfers bestaan.', + 'digits_between' => ':attribute moet tussen de :min en :max cijfers zijn.', + 'email' => ':attribute moet een geldig e-mail adres zijn.', + 'exists' => 'Het geselecteerde :attribute is ongeldig.', + 'distinct' => 'Het :attribute veld heeft een dubbele waarde.', + 'filled' => 'Het :attribute veld is verplicht.', + 'image' => ':attribute moet een afbeelding zijn.', + 'in' => 'Het geselecteerde :attribute is ongeldig.', + 'in_array' => 'Het :attribute veld bestaat niet in :other.', + 'integer' => ':attribute moet een geheel getal zijn.', + 'ip' => 'Het :attribute moet een geldig IP-adres zijn.', + 'json' => ':attribute moet een valide JSON tekst zijn.', + 'max' => [ + 'numeric' => ':attribute mag niet groter zijn dan :max.', + 'file' => ':attribute mag niet groter zijn dan :max kilobytes.', + 'string' => ':attribute mag niet groter zijn dan :max tekens.', + 'array' => ':attribute mag niet meer dan :max items hebben.', + ], + 'mimes' => ':attribute moet een :values bestand zijn.', + 'min' => [ + 'numeric' => ':attribute moet tenminste :min zijn.', + 'file' => ':attribute moet minstens :min kilobytes groot zijn.', + 'string' => ':attribute moet minimaal :min tekens zijn.', + 'array' => ':attribute moet tenminste :min onderdelen hebben.', + ], + 'not_in' => 'Het geselecteerde :attribute is ongeldig.', + 'numeric' => ':attribute moet een getal zijn.', + 'present' => 'Het :attribute veld moet aanwezig zijn.', + 'regex' => 'Het :attribute-formaat is ongeldig.', + 'required' => 'Het :attribute veld is verplicht.', + 'required_if' => 'Het :attribute veld is verplicht als :other :value is.', + 'required_unless' => 'Het :attribute veld is verplicht tenzij :other is in :values.', + 'required_with' => ':attribute veld is verplicht wanneer :values aanwezig zijn.', + 'required_with_all' => ':attribute veld is verplicht wanneer :values aanwezig zijn.', + 'required_without' => 'Het :attribute veld is verplicht als er geen :values zijn.', + 'required_without_all' => 'Het :attribute veld is verplicht als geen van :values aanwezig zijn.', + 'same' => ':attribute en :other moeten overeenkomen.', + 'size' => [ + 'numeric' => ':attribute moet :size zijn.', + 'file' => ':attribute moet :size kilobytes groot zijn.', + 'string' => ':attribute moet :size karakters zijn.', + 'array' => ':attribute moet :size onderdelen bevatten.', + ], + 'string' => ':attribute moet een woord zijn.', + 'timezone' => ':attribute moet een geldige zone zijn.', + 'unique' => ':attribute is reeds in gebruik.', + 'url' => 'Het :attribute-formaat is ongeldig.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/nl/cachet.php b/resources/lang/nl/cachet.php index f568cff0016..75ec21b8512 100644 --- a/resources/lang/nl/cachet.php +++ b/resources/lang/nl/cachet.php @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "U bent uitgenodigd voor team :app_name status pagina, om u in te schrijven klik op de volgende link.\n:link\nBedankt, :app_name", - 'html' => '

U bent uitgenodigd voor team :app_name status pagina, om u in te schrijven klik op de volgende link.

:link

Bedankt, :app_name

', + 'text' => "U bent uitgenodigd voor team :app_name status pagina, om u in te schrijven klik op de volgende link.\n:link\nBedankt, :app_name", + 'html' => '

U bent uitgenodigd voor team :app_name status pagina, om u in te schrijven klik op de volgende link.

:link

Bedankt, :app_name

', ], ], ], diff --git a/resources/lang/nl/forms.php b/resources/lang/nl/forms.php index cd1b47b077c..e7a49176c5e 100644 --- a/resources/lang/nl/forms.php +++ b/resources/lang/nl/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Naam', 'template' => 'Sjabloon', - 'twig' => 'Incident Templates kunnen gebruik maken van de Twig template taal.', + 'twig' => 'Incident Templates kunnen gebruik maken van de Twig template taal.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Site-id van Piwik', ], 'localization' => [ - 'site-timezone' => 'Website tijdzone', - 'site-locale' => 'Taal van de site', - 'date-format' => 'Datum formaat', - 'incident-date-format' => 'Incident tijdsaanduiding', + 'site-timezone' => 'Website tijdzone', + 'site-locale' => 'Taal van de site', + 'date-format' => 'Datum formaat', + 'incident-date-format' => 'Incident tijdsaanduiding', ], 'security' => [ 'allowed-domains' => 'Toegestane domeinen', diff --git a/resources/lang/no-NO/cachet.php b/resources/lang/no-NO/cachet.php new file mode 100644 index 00000000000..992858316fa --- /dev/null +++ b/resources/lang/no-NO/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Sist oppdatert :timestamp', + 'status' => [ + 0 => 'Ukjent', + 1 => 'Ingen problemer', + 2 => 'Ytelsesproblemer', + 3 => 'Delvis brudd', + 4 => 'Større brudd', + ], + 'group' => [ + 'other' => 'Andre komponenter', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Ingen hendelser rapportert', + 'past' => 'Tidligere hendelser', + 'stickied' => 'Festede hendelser', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', planlagt :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Undersøkes', + 2 => 'Identifisert', + 3 => 'Observerer', + 4 => 'Løst', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Kommende', + 1 => 'Pågår', + 2 => 'Fullført', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerer API-nøkkel', + 'revoke' => 'Tilbakekall API-nøkkel', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Siste time', + 'hourly' => 'Siste 12 timer', + 'weekly' => 'Uke', + 'monthly' => 'Måned', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Abonner', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'Du abonnerer for øyeblikket på alle oppdateringer.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'Du abonnerer for øyeblikket på følgende oppdateringer.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Abonner på e-postoppdateringer.', + 'subscribed' => 'Du abonnerer nå på e-postvarslinger, sjekk din e-post for å bekrefte abonneringen.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Ditt epost abonnement er bekreftet!', + 'manage' => 'Administrer ditt abonnement', + 'unsubscribe' => 'Meld av e-postvarsling.', + 'unsubscribed' => 'Ditt e-postabonnement har blitt kansellert.', + 'failure' => 'Noe gikk galt med abonneringen.', + 'already-subscribed' => 'Kan ikke abonnere: email fordi de allerede er abonnenter.', + ], + ], + + 'signup' => [ + 'title' => 'Registerer deg', + 'username' => 'Brukernavn', + 'email' => 'E-post', + 'password' => 'Passord', + 'success' => 'Din konto er opprettet.', + 'failure' => 'Noe gikk galt med registreringsprosessen.', + ], + + 'system' => [ + 'update' => 'Det finnes en nyere versjon av Cachet. Du kan lære hvordan å oppdatere her!', + ], + + // Modal + 'modal' => [ + 'close' => 'Lukk', + 'subscribe' => [ + 'title' => 'Abonner for å motta varslinger for komponenten på e-post', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Abonner', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Hold deg oppdatert med de nyeste service-oppdateringene fra :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Tider vises i :timezone.', + 'about_this_site' => 'Om denne siden', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/no-NO/dashboard.php b/resources/lang/no-NO/dashboard.php new file mode 100644 index 00000000000..3fbb64f11cc --- /dev/null +++ b/resources/lang/no-NO/dashboard.php @@ -0,0 +1,304 @@ + 'Dashbord', + 'writeable_settings' => 'Mappen for Cachet instillinger er ikke skrivbar. Kontroller at ./bootstrap/cachet er skrivbar av webserveren.', + + // Incidents + 'incidents' => [ + 'title' => 'Hendelser & vedlikehold', + 'incidents' => 'Incidents', + 'logged' => '{0}Det er ingen hendelser, godt jobbet.|[1]Du har logget en hendelse.|[2,*]Du har rapportert :count hendelser.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Hendelseoppdateringer for :incident', + 'count' => '{0}Ingen Oppdateringer|[1]Èn Oppdatering|[2]To Oppdateringer|[3,*]Flere Oppdateringer', + 'add' => [ + 'title' => 'Opprett ny hendelseoppdatering', + 'success' => 'Din nye hendelsesoppdatering ble opprettet.', + 'failure' => 'Noe gikk galt med hendelsesoppdateringen.', + ], + 'edit' => [ + 'title' => 'Rediger hendelsesoppdatering', + 'success' => 'Hendelsesoppdateringen har blitt oppdatert.', + 'failure' => 'Noe gikk galt ved oppdatering av hendelsesoppdateringen', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Opprett din første hendelsesmal.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}Det har ikke vært noe vedlikehold, godtjobbet.|[1]Du har logget èn tidsplan.|[2,*]Du har rapportert :count planlagte vedlikehold.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Legg til planlagt vedlikehold', + 'success' => 'Vedlikehold lagt til.', + 'failure' => 'Noe gikk galt med å legge til vedlikeholdet, vennligst prøv igjen.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Noe gikk galt med å redigere vedlikeholdet, vennligst prøv igjen.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'Hvis du vil bruke denne funksjonen, må du tillate folk å melde seg på for varsler.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globalt abonnert', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Logg', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'E-post', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Testnotifikasjon fra Cachet', + 'body' => 'Dette er en testnotifikasjon fra Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Velkommen tilbake!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Støtt Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/no-NO/forms.php b/resources/lang/no-NO/forms.php new file mode 100644 index 00000000000..3763f61e6d4 --- /dev/null +++ b/resources/lang/no-NO/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'E-post', + 'username' => 'Brukernavn', + 'password' => 'Passord', + 'site_name' => 'Nettstedsnavn', + 'site_domain' => 'Nettstedsdomene', + 'site_timezone' => 'Velg din tidssone', + 'site_locale' => 'Velg ditt språk', + 'enable_google2fa' => 'Aktiver Google to-faktor autentisering', + 'cache_driver' => 'Cache-Driver', + 'queue_driver' => 'Kø-Driver', + 'session_driver' => 'Økt Driver', + 'mail_driver' => 'E-post driver', + 'mail_host' => 'E-post tjener', + 'mail_address' => 'E-post-fra adresse', + 'mail_username' => 'E-post brukernavn', + 'mail_password' => 'E-post passord', + ], + + // Login form fields + 'login' => [ + 'login' => 'Brukernavn eller e-post', + 'email' => 'E-post', + 'password' => 'Passord', + '2fauth' => 'Autentiseringskode', + 'invalid' => 'Ugyldig brukernavn eller passord', + 'invalid-token' => 'Ugyldig token', + 'cookies' => 'Du må aktivere informasjonskapsler for å logge inn.', + 'rate-limit' => 'Hyppighetsgrense overskredet.', + 'remember_me' => 'Husk meg', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Navn', + 'status' => 'Status', + 'component' => 'Komponent', + 'component_status' => 'Komponentstatus', + 'message' => 'Melding', + 'message-help' => 'Du kan også bruke Markdown.', + 'occurred_at' => 'Når inntraff denne hendelsen?', + 'notify_subscribers' => 'Varsle abonnenter?', + 'notify_disabled' => 'På grunn av planlagt vedlikehold vil meldinger om denne hendelsen eller komponentene bli utelatt.', + 'visibility' => 'Hendelsens synlighet', + 'stick_status' => 'Fest hendelsen', + 'stickied' => 'Festet', + 'not_stickied' => 'Ikke festet', + 'public' => 'Offentlig synlig', + 'logged_in_only' => 'Bare synlig for innloggede brukere', + 'templates' => [ + 'name' => 'Navn', + 'template' => 'Mal', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Navn', + 'status' => 'Status', + 'message' => 'Melding', + 'message-help' => 'Du kan også bruke Markdown.', + 'scheduled_at' => 'Når er dette vedlikeholdet planlagt for?', + 'completed_at' => 'Når er dette vedlikeholdet fullført?', + 'templates' => [ + 'name' => 'Navn', + 'template' => 'Mal', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Navn', + 'status' => 'Status', + 'group' => 'Gruppe', + 'description' => 'Beskrivelse', + 'link' => 'Lenke', + 'tags' => 'Etiketter', + 'tags-help' => 'Atskilt med komma.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Navn', + 'collapsing' => 'Vis/skjul alternativer', + 'visible' => 'Always expanded', + 'collapsed' => 'Skjul gruppen som standard', + 'collapsed_incident' => 'Skjul gruppen, men utvid hvis det er problemer', + 'visibility' => 'Synlighet', + 'visibility_public' => 'Synlig for offentligheten', + 'visibility_authenticated' => 'Vises bare for påloggede brukere', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Navn', + 'description' => 'Beskrivelse', + 'start_at' => 'Planlagte starttidspunkt', + 'timezone' => 'Tidssone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Gruppe', + 'active' => 'Aktiv?', + 'groups' => [ + 'name' => 'Gruppenavn', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Navn', + 'suffix' => 'Suffiks', + 'description' => 'Beskrivelse', + 'description-help' => 'Du kan også bruke Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Standardverdi', + 'calc_type' => 'Kalkulering av beregninger', + 'type_sum' => 'Sum', + 'type_avg' => 'Gjennomsnittlig', + 'places' => 'Decimal places', + 'default_view' => 'Standardvisning', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Synlighet', + 'visibility_authenticated' => 'Synlig for innloggede brukere', + 'visibility_public' => 'Synlig for alle', + 'visibility_hidden' => 'Alltid skjult', + + 'points' => [ + 'value' => 'Verdi', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Nettstedsnavn', + 'site-url' => 'Site URL', + 'display-graphs' => 'Vis grafer på statussiden?', + 'about-this-page' => 'Om denne siden', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Statusside oppdateringsfrekvens (i sekunder)', + 'major_outage_rate' => 'Større brudd terskel (i %)', + 'banner' => 'Bannerbilde', + 'banner-help' => 'Det anbefales at du ikke laster opp bilder bredere enn 930 piksler', + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Utelat notifikasjoner når hendelse inntreffer under vedlikeholdsperiode?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Vis tidssonen statussiden kjører med', + 'only_disrupted_days' => 'Bare vis dager som inneholder hendelser i tidslinjen?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Alltid autentiser', + 'always-authenticate-help' => 'Krev innlogging for å vise alle Cachet sider', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Bakgrunnsfarge', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Aktivere fullbredde banner?', + 'text-color' => 'Tekstfarge', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Brukernavn', + 'email' => 'E-post', + 'password' => 'Passord', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'Bruker', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Velg tidssone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Registerer deg', + 'manage_updates' => 'Administrer oppdateringer', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/no-NO/notifications.php b/resources/lang/no-NO/notifications.php new file mode 100644 index 00000000000..473b893027b --- /dev/null +++ b/resources/lang/no-NO/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Komponentstatus oppdatert', + 'greeting' => 'En komponents status ble oppdatert!', + 'content' => ':name status endret fra :old_status til :new_status.', + 'action' => 'Vis', + ], + 'slack' => [ + 'title' => 'Komponentstatus oppdatert', + 'content' => ':name status endret fra :old_status til :new_status.', + ], + 'sms' => [ + 'content' => ':name status endret fra :old_status til :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Ny hendelse rapportert', + 'greeting' => 'En ny hendelse ble rapportert på :app_name.', + 'content' => 'Hendelsen :name ble rapportert', + 'action' => 'Vis', + ], + 'slack' => [ + 'title' => 'Hendelse :name rapportert', + 'content' => 'En ny hendelse ble rapportert på :app_name', + ], + 'sms' => [ + 'content' => 'En ny hendelse ble rapportert på :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Hendelse oppdatert', + 'content' => ':name ble oppdatert', + 'title' => ':name ble oppdatert til :new_status', + 'action' => 'Vis', + ], + 'slack' => [ + 'title' => ':name oppdatert', + 'content' => ':name ble oppdatert til :new_status', + ], + 'sms' => [ + 'content' => 'Hendelse :name ble oppdatert', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Ny tidsplan opprettet', + 'content' => ':name ble planlagt for :dato', + 'title' => 'En ny planlagt vedlikehold ble opprettet.', + 'action' => 'Vis', + ], + 'slack' => [ + 'title' => 'Ny tidsplan opprettet!', + 'content' => ':name ble planlagt for :dato', + ], + 'sms' => [ + 'content' => ':name ble planlagt for :dato', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Bekreft ditt abonnement', + 'content' => 'Klikk for å bekrefte abonnementet til :app_name statussiden.', + 'title' => 'Bekreft abonnementet til :app_name statussiden.', + 'action' => 'Bekreft', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping fra Cachet!', + 'content' => 'Dette er en testnotifikasjon fra Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Din invitasjon er her...', + 'content' => 'Du har blitt invitert til å ta del i :app_name statussiden.', + 'title' => 'Du er invitert til å ta del i :app_name statussiden.', + 'action' => 'Aksepter', + ], + ], + ], +]; diff --git a/resources/lang/no-NO/pagination.php b/resources/lang/no-NO/pagination.php new file mode 100644 index 00000000000..466ef5db575 --- /dev/null +++ b/resources/lang/no-NO/pagination.php @@ -0,0 +1,28 @@ + 'Forrige', + 'next' => 'Neste', + +]; diff --git a/resources/lang/no-NO/setup.php b/resources/lang/no-NO/setup.php new file mode 100644 index 00000000000..dc75a6dcd8d --- /dev/null +++ b/resources/lang/no-NO/setup.php @@ -0,0 +1,23 @@ + 'Oppsett', + 'title' => 'Installer Cachet', + 'service_details' => 'Tjenestedetaljer', + 'env_setup' => 'Miljøoppsett', + 'status_page_setup' => 'Statusside-oppsett', + 'show_support' => 'Vis at du støtter Cachet?', + 'admin_account' => 'Administratorkonto', + 'complete_setup' => 'Fullfør oppsett', + 'completed' => 'Konfigurering av Cachet var vellykket!', + 'finish_setup' => 'Gå til dashbord', +]; diff --git a/resources/lang/no-NO/validation.php b/resources/lang/no-NO/validation.php new file mode 100644 index 00000000000..bcf3ccdc781 --- /dev/null +++ b/resources/lang/no-NO/validation.php @@ -0,0 +1,122 @@ + ':attribute må være godkjent.', + 'active_url' => ':attribute er ikke en gyldig URL.', + 'after' => ':attribute må være en dato etter :date.', + 'alpha' => ':attribute kan kun inneholde bokstaver.', + 'alpha_dash' => ':attribute kan kun inneholde bokstaver, tall og bindestreker.', + 'alpha_num' => ':attribute kan bare inneholde bokstaver og tall.', + 'array' => 'The :attribute must be an array.', + 'before' => ':attribute må være en dato før :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => ':attribute må være mellom :min og :max kilobyte.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => ':attribute bekreftelsen samsvarer ikke.', + 'date' => ':attribute er ikke en gyldig dato.', + 'date_format' => ':attribute passer ikke med formatet :format.', + 'different' => ':attribute og :other må være forskjellige.', + 'digits' => ':attribute må være :digits sifre.', + 'digits_between' => ':attribute må være mellom :min og :max sifre.', + 'email' => ':attribute må være en gyldig e-postadresse.', + 'exists' => 'Valgte :attribute er ugyldig.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'Feltet :attribute er påkrevd.', + 'image' => ':attribute må være et bilde.', + 'in' => 'Valgte :attribute er ugyldig.', + 'in_array' => ':attribute feltet finnes ikke i :other.', + 'integer' => ':attribute må være et heltall.', + 'ip' => ':attribute må være en gyldig IP-adresse.', + 'json' => ':attribute må være en gyldig JSON streng.', + 'max' => [ + 'numeric' => ':attribute kan ikke være større enn :max.', + 'file' => ':attribute kan ikke være større enn :max kilobyte.', + 'string' => ':attribute kan ikke være større enn :max tegn.', + 'array' => ':attribute kan ikke har mer enn :max elementer.', + ], + 'mimes' => ':attribute må være en fil av typen: :values.', + 'min' => [ + 'numeric' => ':attribute må være minst :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => ':attribute må ha minst :min tegn.', + 'array' => ':attribute må ha minst :min elementer.', + ], + 'not_in' => 'Valgte :attribute er ugyldig.', + 'numeric' => ':attribute må være et nummer.', + 'present' => ':attribute må finnes.', + 'regex' => ':attribute formatet er ugyldig.', + 'required' => 'Feltet :attribute er påkrevd.', + 'required_if' => ':attribute er påkrevd når :other er :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => ':attribute feltet kreves når :values er til stede.', + 'required_with_all' => ':attribute feltet kreves når :values er til stede.', + 'required_without' => ':attribute er påkrevd når :values ikke er tilstede.', + 'required_without_all' => ':attribute kreves når ingen av :values er tilstede.', + 'same' => ':attribute og :other må være like.', + 'size' => [ + 'numeric' => ':attribute må være :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => ':attribute må være :size tegn.', + 'array' => ':attribute må inneholde :size elementer.', + ], + 'string' => ':attribute må være en tekst.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => ':attribute formatet er ugyldig.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/no/cachet.php b/resources/lang/no/cachet.php index 1d267b1f4e3..82260a14445 100644 --- a/resources/lang/no/cachet.php +++ b/resources/lang/no/cachet.php @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/no/dashboard.php b/resources/lang/no/dashboard.php index 509e872f2d4..7935f2b4146 100644 --- a/resources/lang/no/dashboard.php +++ b/resources/lang/no/dashboard.php @@ -11,47 +11,53 @@ return [ - 'dashboard' => 'Dashbord', + 'dashboard' => 'Dashbord', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', // Incidents 'incidents' => [ - 'title' => 'Hendelser & Timeplan', + 'title' => 'Incidents & Schedule', 'incidents' => 'Hendelser', 'logged' => '{0} Det er ingen hendelser, bra jobbet.|Du har en logget hendelse.|Du har rapportert :count hendelser.', 'incident-create-template' => 'Opprett mal', 'incident-templates' => 'Hendelsesmaler', + 'updates' => '{0} null oppdateringer | Én oppdatering |: telle oppdateringer', 'add' => [ - 'title' => 'Report an incident', - 'success' => 'Incident added.', - 'failure' => 'There was an error adding the incident, please try again.', + 'title' => 'Rapportere en hendelse', + 'success' => 'Hendelse lagt til.', + 'failure' => 'Det oppstod en feil når du la til til hendelsen, prøv igjen.', ], 'edit' => [ - 'title' => 'Edit an incident', + 'title' => 'Rediger en hendelse', 'success' => 'Hendelse oppdatert.', - 'failure' => 'There was an error editing the incident, please try again.', + 'failure' => 'Det oppstod en feil under redigering av hendelsen, prøv igjen.', ], 'delete' => [ - 'success' => 'The incident has been deleted and will not show on your status page.', - 'failure' => 'The incident could not be deleted, please try again.', + 'success' => 'Hendelsen er slettet og vil ikke vises på statussiden din.', + 'failure' => 'Hendelsen kunne ikke slettes, prøv igjen.', + ], + 'update' => [ + 'title' => 'Opprett ny hendelseoppdatering', + 'subtitle' => 'Legge til oppdatering av : hendelsen', ], // Incident templates 'templates' => [ 'title' => 'Hendelsesmaler', 'add' => [ - 'title' => 'Create an incident template', - 'message' => 'You should add an incident template.', - 'success' => 'Your new incident template has been created.', - 'failure' => 'Something went wrong with the incident template.', + 'title' => 'Lag en hendelsesmal', + 'message' => 'Du bør legge til en hendelsesmal.', + 'success' => 'Din nye hendelsesmal er opprettet.', + 'failure' => 'Noe gikk galt med hendelsesmalen.', ], 'edit' => [ - 'title' => 'Edit Template', - 'success' => 'The incident template has been updated.', - 'failure' => 'Something went wrong updating the incident template', + 'title' => 'Rediger mal', + 'success' => 'Hendelsensmalen er oppdatert.', + 'failure' => 'Noe gikk galt under oppdatering av hendelsesmalen', ], 'delete' => [ - 'success' => 'The incident template has been deleted.', - 'failure' => 'The incident template could not be deleted, please try again.', + 'success' => 'Hendelsesmalen er slettet.', + 'failure' => 'Hendelsesmalen kunne ikke slettes, prøv igjen.', ], ], ], @@ -59,21 +65,21 @@ // Incident Maintenance 'schedule' => [ 'schedule' => 'Planlagt vedlikehold', - 'logged' => '{0} There are no schedules, good work.|You have logged one schedule.|You have reported :count schedules.', + 'logged' => '{0} Det er ingen tidsplaner, bra jobbet. | Du har logget en hendelse. | Du har rapportert : antall tidsplaner.', 'scheduled_at' => 'Planlagt til :timestamp', 'add' => [ - 'title' => 'Add Scheduled Maintenance', - 'success' => 'Schedule added.', - 'failure' => 'Something went wrong adding the schedule, please try again.', + 'title' => 'Legg til planlagt vedlikehold', + 'success' => 'Tidsplan lagt til.', + 'failure' => 'Noe gikk galt med å legge til tidsplanen, prøv igjen.', ], 'edit' => [ - 'title' => 'Edit Scheduled Maintenance', - 'success' => 'Schedule has been updated!', - 'failure' => 'Something went wrong editing the schedule, please try again.', + 'title' => 'Redigere planlagt vedlikehold', + 'success' => 'Tidsplanen er oppdatert!', + 'failure' => 'Noe gikk galt med å redigere tidsplanen, prøv igjen.', ], 'delete' => [ - 'success' => 'The scheduled maintenance has been deleted and will not show on your status page.', - 'failure' => 'The scheduled maintenance could not be deleted, please try again.', + 'success' => 'Planlagt vedlikehold er slettet og vil ikke vises på statussiden din.', + 'failure' => 'Planlagt vedlikehold kunne ikke slettes, prøv igjen.', ], ], @@ -83,19 +89,19 @@ 'component_statuses' => 'Komponentstatus', 'listed_group' => 'Gruppert under :name', 'add' => [ - 'title' => 'Add a component', + 'title' => 'Legg til komponent', 'message' => 'Du burde legge til en komponent.', - 'success' => 'Component created.', - 'failure' => 'Something went wrong with the component, please try again.', + 'success' => 'Komponent lagt til.', + 'failure' => 'Noe gikk galt med komponentgruppen, prøv igjen.', ], 'edit' => [ - 'title' => 'Edit a component', - 'success' => 'Component updated.', - 'failure' => 'Something went wrong with the component, please try again.', + 'title' => 'Redigere en komponent', + 'success' => 'Komponent oppdatert.', + 'failure' => 'Noe gikk galt med komponentgruppen, prøv igjen.', ], 'delete' => [ - 'success' => 'The component has been deleted!', - 'failure' => 'The component could not be deleted, please try again.', + 'success' => 'Komponenten har blitt slettet!', + 'failure' => 'Komponenten kunne ikke slettes, prøv igjen.', ], // Component groups @@ -103,18 +109,18 @@ 'groups' => 'Komponentgruppe | Komponentgrupper', 'no_components' => 'Du burde legge til en komponentgruppe.', 'add' => [ - 'title' => 'Add a component group', - 'success' => 'Component group added.', - 'failure' => 'Something went wrong with the component group, please try again.', + 'title' => 'Legg til en komponentgruppe', + 'success' => 'Komponentgruppe lagt til.', + 'failure' => 'Noe gikk galt med komponentgruppen, prøv igjen.', ], 'edit' => [ - 'title' => 'Edit a component group', - 'success' => 'Component group updated.', - 'failure' => 'Something went wrong with the component group, please try again.', + 'title' => 'Rediger komponentgruppe', + 'success' => 'Komponentgruppe oppdatert.', + 'failure' => 'Noe gikk galt med komponentgruppen, prøv igjen.', ], 'delete' => [ - 'success' => 'Component group has been deleted!', - 'failure' => 'The component group could not be deleted, please try again.', + 'success' => 'Komponentgruppen har blitt slettet!', + 'failure' => 'Komponentgruppen kunne ikke slettes, prøv igjen.', ], ], ], @@ -123,39 +129,39 @@ 'metrics' => [ 'metrics' => 'Beregninger', 'add' => [ - 'title' => 'Create a metric', - 'message' => 'You should add a metric.', - 'success' => 'Metric created.', - 'failure' => 'Something went wrong with the metric, please try again.', + 'title' => 'Opprett en beregning', + 'message' => 'Du bør legge til en beregning.', + 'success' => 'Beregning opprettet.', + 'failure' => 'Noe gikk galt med beregningen, prøv igjen.', ], 'edit' => [ - 'title' => 'Edit a metric', - 'success' => 'Metric updated.', - 'failure' => 'Something went wrong with the metric, please try again.', + 'title' => 'Rediger en beregning', + 'success' => 'Beregning oppdatert.', + 'failure' => 'Noe gikk galt med beregningen, prøv igjen.', ], 'delete' => [ - 'success' => 'The metric has been deleted and will no longer display on your status page.', - 'failure' => 'The metric could not be deleted, please try again.', + 'success' => 'Beregningen er slettet og vises ikke lenger på statussiden.', + 'failure' => 'Beregningen kunne ikke slettes, prøv igjen.', ], ], // Subscribers 'subscribers' => [ - 'subscribers' => 'Subscribers', - 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', - 'verified' => 'Verified', - 'not_verified' => 'Not verified', - 'subscriber' => ':email, subscribed :date', - 'no_subscriptions' => 'Subscribed to all updates', + 'subscribers' => 'Abonnenter', + 'description' => 'Abonnenter mottar e-postoppdateringer når hendelser opprettes eller komponenter er oppdatert.', + 'verified' => 'Verifisert', + 'not_verified' => 'Ikke verifisert', + 'subscriber' => ': e-post, abonnert: dato', + 'no_subscriptions' => 'Abonnerer på alle oppdateringer', 'add' => [ - 'title' => 'Add a new subscriber', - 'success' => 'Subscriber has been added!', - 'failure' => 'Something went wrong adding the subscriber, please try again.', - 'help' => 'Enter each subscriber on a new line.', + 'title' => 'Legge til en ny abonnent', + 'success' => 'Abonnenten er lagt til!', + 'failure' => 'Noe gikk galt med å legge til abonnenten, prøv igjen.', + 'help' => 'Angi hver enkelt abonnent på en ny linje.', ], 'edit' => [ - 'title' => 'Update subscriber', - 'success' => 'Subscriber has been updated!', - 'failure' => 'Something went wrong editing the subscriber, please try again.', + 'title' => 'Oppdatering abonnent', + 'success' => 'Abonnenten er oppdatert!', + 'failure' => 'Noe gikk galt med å redigere abonnenten, prøv igjen.', ], ], @@ -166,23 +172,23 @@ 'profile' => 'Profil', 'description' => 'Team Members will be able to add, modify & edit components and incidents.', 'add' => [ - 'title' => 'Add a new team member', - 'success' => 'Team member added.', - 'failure' => 'The team member could not be added, please try again.', + 'title' => 'Legge til nytt gruppemedlem', + 'success' => 'Gruppemedlem lagt til.', + 'failure' => 'Gruppemedlemmet kunne ikke legges til, prøv på nytt.', ], 'edit' => [ - 'title' => 'Update profile', - 'success' => 'Profile updated.', - 'failure' => 'Something went wrong updating the profile, please try again.', + 'title' => 'Oppdater profil', + 'success' => 'Profilen oppdatert.', + 'failure' => 'Noe gikk galt med å oppdatere profilen, prøv igjen.', ], 'delete' => [ - 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', - 'failure' => 'The team member could not be added, please try again.', + 'success' => 'Gruppemedlemmet er slettet og vil ikke lenger ha tilgang til oversikten!', + 'failure' => 'Gruppemedlemmet kunne ikke legges til, prøv på nytt.', ], 'invite' => [ - 'title' => 'Invite a new team member', - 'success' => 'An invite has been sent', - 'failure' => 'The invite could not be sent, please try again.', + 'title' => 'Inviter en ny medarbeider', + 'success' => 'Invitasjon er sendt', + 'failure' => 'Invitasjonen kunne ikke sendes, vennligst prøv igjen.', ], ], @@ -191,23 +197,34 @@ 'settings' => 'Innstillinger', 'app-setup' => [ 'app-setup' => 'Applikasjonsoppsett', - 'images-only' => 'Only images may be uploaded.', - 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + 'images-only' => 'Bare bilder kan lastes opp.', + 'too-big' => 'Filen du lastet opp er for stor. Last opp et bilde som er mindre enn :size', ], 'analytics' => [ 'analytics' => 'Analytics', ], + 'log' => [ + 'log' => 'Logg', + ], 'localization' => [ - 'localization' => 'Localization', + 'localization' => 'Regioninnstillinger', ], 'customization' => [ - 'customization' => 'Customization', - 'header' => 'Custom Header HTML', - 'footer' => 'Custom Footer HTML', + 'customization' => 'Tilpasninger', + 'header' => 'Egendefinert topptekst HTML', + 'footer' => 'Egendefinert bunntekst HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], ], 'security' => [ 'security' => 'Sikkerhet', - 'two-factor' => 'Users without two-factor authentication', + 'two-factor' => 'Brukere uten to-faktor autentifisering', ], 'stylesheet' => [ 'stylesheet' => 'Stilark', @@ -216,25 +233,25 @@ 'theme' => 'Tema', ], 'edit' => [ - 'success' => 'Settings saved.', - 'failure' => 'Settings could not be saved.', + 'success' => 'Innstillinger lagret.', + 'failure' => 'Kan ikke lagre innstillingene.', ], 'credits' => [ - 'credits' => 'Credits', - 'contributors' => 'Contributors', - 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', - 'backers-title' => 'Backers & Sponsors', - 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', - 'thank-you' => 'Thank you to each and every one of the :count contributors.', + 'credits' => 'Medvirkende', + 'contributors' => 'Bidragsytere', + 'license' => 'Cachet er en BSD-3-lisensiert åpen kildekode-prosjekt, utgitt av Alt tre Services Limited.', + 'backers-title' => 'Støttespillere & sponsorer', + 'backers' => 'Hvis du ønsker å støtte fremtidig utvikling, sjekk ut Cachet Patreon kampanjen.', + 'thank-you' => 'Takk til hver og en av de :count bidragsytere.', ], ], // Login 'login' => [ - 'login' => 'Login', - 'logged_in' => 'You\'re logged in.', - 'welcome' => 'Welcome Back!', - 'two-factor' => 'Please enter your token.', + 'login' => 'Logg inn', + 'logged_in' => 'Du er logget inn.', + 'welcome' => 'Velkommen tilbake!', + 'two-factor' => 'Skriv inn din token.', ], // Sidebar footer @@ -245,30 +262,30 @@ // Notifications 'notifications' => [ 'notifications' => 'Varslinger', - 'awesome' => 'Awesome.', - 'whoops' => 'Whoops.', + 'awesome' => 'Fantastisk.', + 'whoops' => 'Uff da.', ], // Widgets 'widgets' => [ - 'support' => 'Support Cachet', - 'support_subtitle' => 'Check out our Patreon page!', - 'news' => 'Latest News', - 'news_subtitle' => 'Get the latest updates', + 'support' => 'Støtt Cachet', + 'support_subtitle' => 'Sjekk ut vår Patreon side!', + 'news' => 'Siste nyheter', + 'news_subtitle' => 'Hent nyeste oppdatering', ], // Welcome modal 'welcome' => [ - 'welcome' => 'Welcome to your new status page!', - 'message' => 'Your status page is almost ready! You might want to configure these extra settings', - 'close' => 'Take me straight to my dashboard', + 'welcome' => 'Velkommen til den nye statussiden, :username!', + 'message' => 'Du er nesten klar, men du vil kanskje konfigurere disse ekstra innstillingene først...', + 'close' => 'Jeg har det bra takk!', 'steps' => [ - 'component' => 'Create components', - 'incident' => 'Create incidents', - 'customize' => 'Customize', - 'team' => 'Add users', - 'api' => 'Generate API token', - 'two-factor' => 'Two Factor Authentication', + 'component' => 'Legg til dine komponenter', + 'incident' => 'Opprette en hendelse', + 'customize' => 'Tilpass siden din', + 'team' => 'Legg til gruppen din', + 'api' => 'Generere et API-token', + 'two-factor' => 'Sett opp to-faktor autentisering', ], ], diff --git a/resources/lang/no/forms.php b/resources/lang/no/forms.php index 76640cff0d9..92bd98fed98 100644 --- a/resources/lang/no/forms.php +++ b/resources/lang/no/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Navn', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/pl-PL/cachet.php b/resources/lang/pl-PL/cachet.php new file mode 100644 index 00000000000..b46c6ed4c87 --- /dev/null +++ b/resources/lang/pl-PL/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Ostatnia aktualizacja :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Funktionsfähig', + 2 => 'Leistungsprobleme', + 3 => 'Teilweiser Ausfall', + 4 => 'Schwerer Ausfall', + ], + 'group' => [ + 'other' => 'Pozostałe komponenty', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Brak zgłoszonych incydentów', + 'past' => 'Vergangene Vorfälle', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', geplant :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Untersuchungen laufen', + 2 => 'Identifiziert', + 3 => 'Unter Beobachtung', + 4 => 'Behoben', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'API-Schlüssel neu generieren', + 'revoke' => 'API-Schlüssel widerrufen', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Ostatnia godzina', + 'hourly' => 'Letzte 12 Stunden', + 'weekly' => 'Wöchentlich', + 'monthly' => 'Monatlich', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Abonnieren', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Benachrichtigungen', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'Jesteś obecnie zapisany na wszystkie aktualizacje.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'Jesteś obecnie zapisany na poniższe aktualizacje.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Aktualisierungen per E-Mail abonnieren.', + 'subscribed' => 'Sie haben E-Mail-Benachrichtigungen abonniert, überprüfen Sie bitte Ihre E-Mail, um Ihr Abonnement zu bestätigen.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Ihre E-Mail-Abonnement ist bestätigt worden. Danke!', + 'manage' => 'Zarządzanie subskrypcją', + 'unsubscribe' => 'Von E-Mail-Updates deabonnieren.', + 'unsubscribed' => 'Ihre E-Mail-Abonnement wurde gekündigt.', + 'failure' => 'Etwas ist mit dem Abonnement schief gelaufen.', + 'already-subscribed' => 'Subskrypcja niemożliwa, :email jest już zapisany.', + ], + ], + + 'signup' => [ + 'title' => 'Zarejestruj się', + 'username' => 'Nazwa Użytkownika', + 'email' => 'E-Mail', + 'password' => 'Hasło', + 'success' => 'Twoje konto zostało utworzone.', + 'failure' => 'Coś poszło nie tak w trakcje rejestracji.', + ], + + 'system' => [ + 'update' => 'Nowsza wersja Cachet\'a jest dostępna. Kliknij tutaj, aby dowiedzieć się jak dokonać aktualizacji!', + ], + + // Modal + 'modal' => [ + 'close' => 'Zamknij', + 'subscribe' => [ + 'title' => 'Subskrybuj aktualizacje komponentu', + 'body' => 'Podaj swój adres email w celu subskrypcji aktualizacji dla tego komponentu. Jeśli byłeś już zapisany, otrzymujesz aktualizacje dla tego komponentu.', + 'button' => 'Abonnieren', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Bądź na bieżąco z aktualizacjami z :app.', + ], + ], + + // Other + 'home' => 'Strona Główna', + 'powered_by' => 'Obsługiwany przez Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'Über diese Seite', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status-Feed', + +]; diff --git a/resources/lang/pl-PL/dashboard.php b/resources/lang/pl-PL/dashboard.php new file mode 100644 index 00000000000..2de72d14a8d --- /dev/null +++ b/resources/lang/pl-PL/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'Nie można zapisać zmian w pliku konfiguracyjnym Cachet. Proszę sprawdzić uprawnienia do katalogu ./bootstrap/cachet, serwer www musi mieć możliwość zapisu w tym katalogu.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Vorfälle', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Vorlage erstellen', + 'incident-templates' => 'Vorfall Vorlagen', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Utwórz nową aktualizację zdarzenia', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Vorfall hinzufügen', + 'success' => 'Dodano zdarzenie.', + 'failure' => 'Wystąpił błąd podczas dodawania wydarzenia, proszę spróbować ponownie.', + ], + 'edit' => [ + 'title' => 'Vorfall bearbeiten', + 'success' => 'Vorfall aktualisiert.', + 'failure' => 'Wystąpił błąd podczas edytowania wydarzenia, proszę spróbować ponownie.', + ], + 'delete' => [ + 'success' => 'Wydarzenie zostało usunięte i nie będzie widoczne na stronie statusu.', + 'failure' => 'Wydarzenie nie mogło zostać usunięte, proszę spróbować ponownie.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Vorfall Vorlagen', + 'add' => [ + 'title' => 'Vorfallvorlage erstellen', + 'message' => 'Create your first incident template.', + 'success' => 'Twój nowy szablon wydarzenia został utworzony.', + 'failure' => 'Coś poszło nie tak z szablonem wydarzenia.', + ], + 'edit' => [ + 'title' => 'Vorlage bearbeiten', + 'success' => 'Szablon wydarzenia został zaktualizowany.', + 'failure' => 'Coś poszło nie tak podczas aktualizacji szablonu wydarzenia', + ], + 'delete' => [ + 'success' => 'Szablon wydarzenia został usunięty.', + 'failure' => 'Szablon wydarzenia nie mógł zostać usunięty, proszę spróbować ponownie.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Geplant am :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Komponenten', + 'component_statuses' => 'Komponentenstatus', + 'listed_group' => 'Gruppiert unter :name', + 'add' => [ + 'title' => 'Komponente hinzufügen', + 'message' => 'Sie sollten eine Komponente erstellen.', + 'success' => 'Utworzono komponent.', + 'failure' => 'Coś poszło nie tak z komponentem, proszę spróbować ponownie.', + ], + 'edit' => [ + 'title' => 'Komponente bearbeiten', + 'success' => 'Zaktualizowano komponent.', + 'failure' => 'Coś poszło nie tak z komponentem, proszę spróbować ponownie.', + ], + 'delete' => [ + 'success' => 'Komponent został usunięty!', + 'failure' => 'Komponent nie mógł zostać usunięty, proszę spróbować ponownie.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Komponentgruppe|Komponentgruppen', + 'no_components' => 'Sie sollten eine Komponentengruppe hinzufügen.', + 'add' => [ + 'title' => 'Eine Komponentengruppe hinzufügen', + 'success' => 'Dodano grupę komponentów.', + 'failure' => 'Coś poszło nie tak z komponentem, proszę spróbować ponownie.', + ], + 'edit' => [ + 'title' => 'Komponentengruppe bearbeiten', + 'success' => 'Zaktualizowano grupę komponentów.', + 'failure' => 'Coś poszło nie tak z komponentem, proszę spróbować ponownie.', + ], + 'delete' => [ + 'success' => 'Grupa komponentów została usunięta!', + 'failure' => 'Grupa komponentów nie mogła zostać usunięta, proszę spróbować ponownie.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metriken', + 'add' => [ + 'title' => 'Metrik erstellen', + 'message' => 'Powinieneś dodać metrykę.', + 'success' => 'Utworzono metrykę.', + 'failure' => 'Coś poszło nie tak z metryką, proszę próbować ponownie.', + ], + 'edit' => [ + 'title' => 'Metrik bearbeiten', + 'success' => 'Zaktualizowano metrykę.', + 'failure' => 'Coś poszło nie tak z metryką, proszę próbować ponownie.', + ], + 'delete' => [ + 'success' => 'Metryka została usunięta i nie będzie wyświetlana na stronie statusu.', + 'failure' => 'Metryka nie mogła zostać usunięta, proszę spróbować ponownie.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Abonnenten', + 'description' => 'Subskrybenci będą otrzymywać powiadomienia, gdy wydarzenia zostaną utworzone lub komponenty zaktualizowane.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verifiziert', + 'not_verified' => 'Nicht verifiziert', + 'subscriber' => ':email, subskrybowany :data', + 'no_subscriptions' => 'Zapisano do wszystkich aktualizacji', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Einen neuen Abonnenten hinzufügen', + 'success' => 'Abonnent hinzugefügt.', + 'failure' => 'Coś poszło nie tak podczas dodawania subskrybenta, proszę spróbować ponownie.', + 'help' => 'Wpisz każdego subskrybenta w nowym wierszu.', + ], + 'edit' => [ + 'title' => 'Abonnent aktualisieren', + 'success' => 'Abonnent aktualisiert.', + 'failure' => 'Coś poszło nie tak podczas edytowania subskrybenta, proszę spróbować ponownie.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Mitglied', + 'profile' => 'Profil', + 'description' => 'Teammitglieder werden die Möglichkeit haben, Komponente sowie Vorfälle hinzuzufügen und zu verändern.', + 'add' => [ + 'title' => 'Neues Teammitglied hinzufügen', + 'success' => 'Dodano członka zespołu.', + 'failure' => 'Członek zespołu nie mógł zostać dodany, proszę spróbować ponownie.', + ], + 'edit' => [ + 'title' => 'Profil aktualisieren', + 'success' => 'Zaktualizowano profil.', + 'failure' => 'Coś poszło nie tak podczas aktualizacji profilu, proszę spróbować ponownie.', + ], + 'delete' => [ + 'success' => 'Benutzer aktualisiert.', + 'failure' => 'Członek zespołu nie mógł zostać dodany, proszę spróbować ponownie.', + ], + 'invite' => [ + 'title' => 'Zaproś nowego członka zespołu', + 'success' => 'Zaproszenie zostało wysłane', + 'failure' => 'Zaproszenie nie mogło zostać wysłane, proszę spróbować ponownie.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Einstellungen', + 'app-setup' => [ + 'app-setup' => 'Anwendungsinstallation', + 'images-only' => 'Es können nur Bilder hochgeladen werden.', + 'too-big' => 'Die von Ihnen hochgeladene Datei ist zu groß. Laden Sie ein Bild welches kleiner als :size ist hoch', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Logi', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Dostosowywanie', + 'header' => 'Niestandardowy nagłówek HTML', + 'footer' => 'Niestandardowa stopka HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Sicherheit', + 'two-factor' => 'Nutzer ohne Zwei-Faktor-Authentifizierung', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Einstellungen gespeichert.', + 'failure' => 'Einstellungen konnten nicht gespeichert werden.', + ], + 'credits' => [ + 'credits' => 'Autorzy', + 'contributors' => 'Współtwórcy', + 'license' => 'Catchet jest otwartym źródłem z licencją BSD utworzonym przez Alt Three Services Limited.', + 'backers-title' => 'Patronaci i sponsorzy', + 'backers' => 'Jeśli chciałbyś wspomóc przyszły rozwój sprawdź kampanię Cachet Patreon.', + 'thank-you' => 'Dziękujemy każdemu :count współtwórcy.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Anmelden', + 'logged_in' => 'Sie sind angemeldet.', + 'welcome' => 'Willkommen zurück!', + 'two-factor' => 'Bitte geben Sie Ihren Token ein.', + ], + + // Sidebar footer + 'help' => 'Hilfe', + 'status_page' => 'Statusseite', + 'logout' => 'Abmelden', + + // Notifications + 'notifications' => [ + 'notifications' => 'Benachrichtigungen', + 'awesome' => 'Großartig.', + 'whoops' => 'Hoppla.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Wspomóż Cachet', + 'support_subtitle' => 'Sprawdź również naszą stronę na Patreon!', + 'news' => 'Aktualności', + 'news_subtitle' => 'Pobierz najnowszą aktualizację', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Witamy w nowym statusie strony!', + 'message' => 'Ihre Statusseite ist fast fertig! Vielleicht möchten Sie diese zusätzlichen Einstellungen konfigurieren', + 'close' => 'Przejdź prosto do panelu głównego', + 'steps' => [ + 'component' => 'Komponenten erstellen', + 'incident' => 'Vorfälle erstellen', + 'customize' => 'Personalisieren', + 'team' => 'Benutzer hinzufügen', + 'api' => 'API Token generieren', + 'two-factor' => 'Zwei-Faktor-Authentifizierung', + ], + ], + +]; diff --git a/resources/lang/pl-PL/forms.php b/resources/lang/pl-PL/forms.php new file mode 100644 index 00000000000..0c1f804b920 --- /dev/null +++ b/resources/lang/pl-PL/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'E-Mail', + 'username' => 'Nazwa Użytkownika', + 'password' => 'Hasło', + 'site_name' => 'Nazwa strony', + 'site_domain' => 'Domena', + 'site_timezone' => 'Wybierz swoją strefę czasową', + 'site_locale' => 'Wybierz swój język', + 'enable_google2fa' => 'Włącz weryfikację dwuetapową Google Authenticator', + 'cache_driver' => 'Sposób przechowywania cache', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Sposób przechowywania sesji', + 'mail_driver' => 'Sposób wysyłania wiadomości e-mail', + 'mail_host' => 'Adres hosta poczty', + 'mail_address' => 'Nadawca wiadomości', + 'mail_username' => 'Nazwa użytkownika poczty', + 'mail_password' => 'Hasło użytkownika poczty', + ], + + // Login form fields + 'login' => [ + 'login' => 'Nazwa użytkownika lub e-mail', + 'email' => 'E-Mail', + 'password' => 'Hasło', + '2fauth' => 'Kod autoryzacyjny', + 'invalid' => 'Nieprawidłowa nazwa użytkownika lub hasło', + 'invalid-token' => 'Nieprawidłowy token', + 'cookies' => 'Musisz włączyć obsługę cookies, aby móc się zalogować.', + 'rate-limit' => 'Przekroczono limit.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Nazwa', + 'status' => 'Status', + 'component' => 'Komponent', + 'component_status' => 'Component Status', + 'message' => 'Nachricht', + 'message-help' => 'Można użyć również języka znaczników.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Powiadomić subskrybentów?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Widoczność zdarzenia', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Widoczne publicznie', + 'logged_in_only' => 'Widoczne tylko dla zalogowanych użytkowników', + 'templates' => [ + 'name' => 'Nazwa', + 'template' => 'Szablon', + 'twig' => 'Szablony wydarzeń mogą korzystać z języka szablonów Twig.', + ], + ], + + 'schedules' => [ + 'name' => 'Nazwa', + 'status' => 'Status', + 'message' => 'Nachricht', + 'message-help' => 'Można użyć również języka znaczników.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Nazwa', + 'template' => 'Szablon', + 'twig' => 'Szablony wydarzeń mogą korzystać z języka szablonów Twig.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Nazwa', + 'status' => 'Status', + 'group' => 'Gruppe', + 'description' => 'Beschreibung', + 'link' => 'Link', + 'tags' => 'Schlagwörter', + 'tags-help' => 'Durch Kommata trennen.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Nazwa', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Zawsze rozwinięte', + 'collapsed' => 'Domyślnie zwiń grupę', + 'collapsed_incident' => 'Zwiń grupę, ale rozwiń ją w razie problemów', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Nazwa', + 'description' => 'Beschreibung', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Gruppe', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Nazwa', + 'suffix' => 'Przyrostek', + 'description' => 'Beschreibung', + 'description-help' => 'Można użyć również języka znaczników.', + 'display-chart' => 'Pokazać diagram na stronie statusu?', + 'default-value' => 'Warość domyślna', + 'calc_type' => 'Obliczanie metryk', + 'type_sum' => 'Suma', + 'type_avg' => 'Średnia', + 'places' => 'Miejsca dziesiętne', + 'default_view' => 'Domyślny widok', + 'threshold' => 'Ile minut przerwy między punktami metrycznymi?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Wartość', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Nazwa strony', + 'site-url' => 'Adres URL strony', + 'display-graphs' => 'Pokazać wykresy na stronie statusu?', + 'about-this-page' => 'Informacje o tej stronie', + 'days-of-incidents' => 'Z ilu ostatnich dni pokazywać incydenty?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Baner', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Czy zezwolić użytkownikom na subskrypcje e-mail w celu otrzymywania powiadomień?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatycznie tłumaczyć twoją stronę statusu na język odwiedzającego?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Kod Google Analytics', + 'analytics_gosquared' => 'Kod GoSquared Analytics', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'ID strony Piwik', + ], + 'localization' => [ + 'site-timezone' => 'Strefa czasowa strony', + 'site-locale' => 'Język strony', + 'date-format' => 'Format daty', + 'incident-date-format' => 'Format daty przy zdarzeniach', + ], + 'security' => [ + 'allowed-domains' => 'Dozwolone domeny', + 'allowed-domains-help' => 'Oddzielone przecinkami. Domena jest automatycznie ustawiona wyżej domyślnie, jako dozwolona.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Niestandardowy arkusz stylów', + ], + 'theme' => [ + 'background-color' => 'Kolor tła', + 'background-fills' => 'Wypełnianie tła (komponenty, zdarzenia, stopka)', + 'banner-background-color' => 'Kolor tła pod banerem', + 'banner-padding' => 'Odstęp banera', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Kolor tekstu', + 'dashboard-login' => 'Pokazywać przycisk panelu głównego w stopce?', + 'reds' => 'Czerwony (używany przy błędach)', + 'blues' => 'Niebieski (używany przy informacjach)', + 'greens' => 'Zielony (używany przy powodzeniu)', + 'yellows' => 'Żółty (używany przy ostrzeżeniach)', + 'oranges' => 'Pomarańczowy (używany przy ogłoszeniach)', + 'metrics' => 'Wypełnienie metryki', + 'links' => 'Łącza', + ], + ], + + 'user' => [ + 'username' => 'Nazwa Użytkownika', + 'email' => 'E-Mail', + 'password' => 'Hasło', + 'api-token' => 'Token API', + 'api-token-help' => 'Ponowne wygenerowanie nowego tokenu API spowoduje, że aplikacje korzystające obecnie z Cachet utracą do niego dostęp.', + 'gravatar' => 'Zmień swój awatar na Gravatar.', + 'user_level' => 'Poziom użytkownika', + 'levels' => [ + 'admin' => 'Administrator', + 'user' => 'Użytkownik', + ], + '2fa' => [ + 'help' => 'Włączenie weryfikacji dwuetapowej zwiększa bezpieczeństwo. Pobierz Google Authenticator lub podobną aplikację. Po zalogowaniu zostaniesz poproszony o podanie kodu wygenerowanego przez aplikację.', + ], + 'team' => [ + 'description' => 'Zaproś nowych członków do swojego zespołu. Wpisz ich adresy e-mail tutaj.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Dodaj', + 'save' => 'Zapisz', + 'update' => 'Zaktualizuj', + 'create' => 'Utwórz', + 'edit' => 'Edytuj', + 'delete' => 'Usuń', + 'submit' => 'Prześlij', + 'cancel' => 'Anuluj', + 'remove' => 'Skasuj', + 'invite' => 'Zaproś', + 'signup' => 'Zarejestruj się', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Opcjonalnie', +]; diff --git a/resources/lang/pl-PL/notifications.php b/resources/lang/pl-PL/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/pl-PL/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/pl-PL/pagination.php b/resources/lang/pl-PL/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/pl-PL/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/pl-PL/setup.php b/resources/lang/pl-PL/setup.php new file mode 100644 index 00000000000..a298117818b --- /dev/null +++ b/resources/lang/pl-PL/setup.php @@ -0,0 +1,23 @@ + 'Instalacja', + 'title' => 'Skonfiguruj Cachet', + 'service_details' => 'Szczegóły usługi', + 'env_setup' => 'Konfiguracja środowiska', + 'status_page_setup' => 'Skonfiguruj stronę statusu', + 'show_support' => 'Pokazać wsparcie dla Cachet?', + 'admin_account' => 'Konto Administratora', + 'complete_setup' => 'Zakończ instalację', + 'completed' => 'Cachet został pomyślnie skonfigurowany!', + 'finish_setup' => 'Przejdź do pulpitu', +]; diff --git a/resources/lang/pl-PL/validation.php b/resources/lang/pl-PL/validation.php new file mode 100644 index 00000000000..27272da7a26 --- /dev/null +++ b/resources/lang/pl-PL/validation.php @@ -0,0 +1,122 @@ + ':attribute muss akzeptiert werden.', + 'active_url' => ':attribute ist keine gültige Internet-Adresse.', + 'after' => ':attribute muss ein Datum nach dem :date sein.', + 'alpha' => ':attribute darf nur aus Buchstaben bestehen.', + 'alpha_dash' => ':attribute darf nur aus Buchstaben, Zahlen, Binde- und Unterstrichen bestehen. Umlaute (ä, ö, ü) und Eszett (ß) sind nicht erlaubt.', + 'alpha_num' => ':attribute darf nur aus Buchstaben, Zahlen, Binde- und Unterstrichen bestehen. Umlaute (ä, ö, ü) und Eszett (ß) sind nicht erlaubt.', + 'array' => ':attribute muss ein Array sein.', + 'before' => ':attribute muss ein Datum vor dem :date sein.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => ':attribute muss zwischen :min & :max Elemente haben.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'Pole :attribute zawiera podwójną wartość.', + 'filled' => 'The :attribute field is required.', + 'image' => ':attribute muss ein Bild sein.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'Pole :attribute nie istnieje w :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => ':attribute musi być prawidłowym węzłem JSON.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => ':attribute darf nicht mehr als :max Elemente haben.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => ':attribute muss mindestens :min Kilobytes groß sein.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'Pole :attribute musi być obecne.', + 'regex' => 'Format atrybutu ":attribute" jest nieprawidłowy.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'Pole :attribute jest wymagane, chyba że :other jest w :values.', + 'required_with' => 'Pole :attribute jest wymagane kiedy obecne jest :values.', + 'required_with_all' => 'Pole :attribute jest wymagane kiedy obecne jest :values.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => ':attribute muss :size Kilobytes groß sein.', + 'string' => ':attribute muss :size Zeichen lang sein.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => ':attribute muss eine gültige Zeitzone sein.', + 'unique' => ':attribute ist schon vergeben.', + 'url' => 'Format atrybutu ":attribute" jest nieprawidłowy.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'Individuelle Nachricht', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/pl/cachet.php b/resources/lang/pl/cachet.php index 5977c7e2df7..5c0879baf9b 100644 --- a/resources/lang/pl/cachet.php +++ b/resources/lang/pl/cachet.php @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "Zostałeś zaproszony do strony statusowej zespołu :app_name. Aby się zapisać, kliknij na link umieszczony dalej.\n:link\nDziękujemy, :app_name", - 'html' => '

Zostałeś zaproszony do strony statusowej zespołu :app_name. Aby się zapisać, kliknij na link umieszczony dalej.

:link

Dziękujemy, :app_name

', + 'text' => "Zostałeś zaproszony do strony statusowej zespołu :app_name. Aby się zapisać, kliknij na link umieszczony dalej.\n:link\nDziękujemy, :app_name", + 'html' => '

Zostałeś zaproszony do strony statusowej zespołu :app_name. Aby się zapisać, kliknij na link umieszczony dalej.

:link

Dziękujemy, :app_name

', ], ], ], diff --git a/resources/lang/pl/dashboard.php b/resources/lang/pl/dashboard.php index 53d4e9b8bab..28bc7e996c7 100644 --- a/resources/lang/pl/dashboard.php +++ b/resources/lang/pl/dashboard.php @@ -11,15 +11,17 @@ return [ - 'dashboard' => 'Dashboard', + 'dashboard' => 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', // Incidents 'incidents' => [ - 'title' => 'Ereignisse & Termine', + 'title' => 'Incidents & Schedule', 'incidents' => 'Vorfälle', 'logged' => '{0} Es gibt keine Vorfälle, gute Arbeit.|Du hast einen Vorfall gemeldet.|Du hast :count Vorfälle gemeldet.', 'incident-create-template' => 'Vorlage erstellen', 'incident-templates' => 'Vorfall Vorlagen', + 'updates' => '{0} Zero aktualizacji|Jedna aktualizacja|:count aktualizacji', 'add' => [ 'title' => 'Vorfall hinzufügen', 'success' => 'Dodano zdarzenie.', @@ -34,6 +36,10 @@ 'success' => 'Wydarzenie zostało usunięte i nie będzie widoczne na stronie statusu.', 'failure' => 'Wydarzenie nie mogło zostać usunięte, proszę spróbować ponownie.', ], + 'update' => [ + 'title' => 'Utwórz nową aktualizację zdarzenia', + 'subtitle' => 'Dodaj aktualizację do :incident', + ], // Incident templates 'templates' => [ @@ -105,12 +111,12 @@ 'add' => [ 'title' => 'Eine Komponentengruppe hinzufügen', 'success' => 'Dodano grupę komponentów.', - 'failure' => 'Coś poszło nie tak z grupą komponentów, proszę spróbować ponownie.', + 'failure' => 'Coś poszło nie tak z komponentem, proszę spróbować ponownie.', ], 'edit' => [ 'title' => 'Komponentengruppe bearbeiten', 'success' => 'Zaktualizowano grupę komponentów.', - 'failure' => 'Coś poszło nie tak z grupą komponentów, proszę spróbować ponownie.', + 'failure' => 'Coś poszło nie tak z komponentem, proszę spróbować ponownie.', ], 'delete' => [ 'success' => 'Grupa komponentów została usunięta!', @@ -164,7 +170,7 @@ 'team' => 'Team', 'member' => 'Mitglied', 'profile' => 'Profil', - 'description' => 'Teammitglieder werden die Möglichkeit haben, Komponente sowie Vorfälle hinzuzufügen und zu verändern.', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', 'add' => [ 'title' => 'Neues Teammitglied hinzufügen', 'success' => 'Dodano członka zespołu.', @@ -197,6 +203,9 @@ 'analytics' => [ 'analytics' => 'Analytics', ], + 'log' => [ + 'log' => 'Logi', + ], 'localization' => [ 'localization' => 'Localization', ], @@ -205,6 +214,14 @@ 'header' => 'Niestandardowy nagłówek HTML', 'footer' => 'Niestandardowa stopka HTML', ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], 'security' => [ 'security' => 'Sicherheit', 'two-factor' => 'Nutzer ohne Zwei-Faktor-Authentifizierung', @@ -220,12 +237,12 @@ 'failure' => 'Einstellungen konnten nicht gespeichert werden.', ], 'credits' => [ - 'credits' => 'Credits', - 'contributors' => 'Contributors', - 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', - 'backers-title' => 'Backers & Sponsors', - 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', - 'thank-you' => 'Thank you to each and every one of the :count contributors.', + 'credits' => 'Autorzy', + 'contributors' => 'Współtwórcy', + 'license' => 'Catchet jest otwartym źródłem z licencją BSD utworzonym przez Alt Three Services Limited.', + 'backers-title' => 'Patronaci i sponsorzy', + 'backers' => 'Jeśli chciałbyś wspomóc przyszły rozwój sprawdź kampanię Cachet Patreon.', + 'thank-you' => 'Dziękujemy każdemu :count współtwórcy.', ], ], @@ -251,10 +268,10 @@ // Widgets 'widgets' => [ - 'support' => 'Support Cachet', - 'support_subtitle' => 'Check out our Patreon page!', - 'news' => 'Latest News', - 'news_subtitle' => 'Get the latest updates', + 'support' => 'Wspomóż Cachet', + 'support_subtitle' => 'Sprawdź również naszą stronę na Patreon!', + 'news' => 'Aktualności', + 'news_subtitle' => 'Pobierz najnowszą aktualizację', ], // Welcome modal diff --git a/resources/lang/pl/forms.php b/resources/lang/pl/forms.php index 5b8a8593005..e76f161cb89 100644 --- a/resources/lang/pl/forms.php +++ b/resources/lang/pl/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Name', 'template' => 'Vorlage', - 'twig' => 'Szablony wydarzeń mogą korzystać z języka szablonów Twig.', + 'twig' => 'Szablony wydarzeń mogą korzystać z języka szablonów Twig.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s Seiten-ID', ], 'localization' => [ - 'site-timezone' => 'Zeitzone ihrer Seite', - 'site-locale' => 'Sprache ihrer Seite', - 'date-format' => 'Datumsformat', - 'incident-date-format' => 'Vorfall Zeitstempel-Format', + 'site-timezone' => 'Zeitzone ihrer Seite', + 'site-locale' => 'Sprache ihrer Seite', + 'date-format' => 'Datumsformat', + 'incident-date-format' => 'Vorfall Zeitstempel-Format', ], 'security' => [ 'allowed-domains' => 'Erlaubte Domains', diff --git a/resources/lang/pt-BR/cachet.php b/resources/lang/pt-BR/cachet.php index e8ba2bd8969..b43dc750b4e 100644 --- a/resources/lang/pt-BR/cachet.php +++ b/resources/lang/pt-BR/cachet.php @@ -14,6 +14,7 @@ 'components' => [ 'last_updated' => 'Última atualização :timestamp', 'status' => [ + 0 => 'Desconhecido', 1 => 'Operacional', 2 => 'Problemas de performance', 3 => 'Indisponibilidade parcial', @@ -22,18 +23,20 @@ 'group' => [ 'other' => 'Outros componentes', ], + 'select_all' => 'Marcar todos', + 'deselect_all' => 'Desmarcar todos', ], // Incidents 'incidents' => [ - 'none' => 'Nenhum incidente reportado', - 'past' => 'Incidentes anteriores', - 'previous_week' => 'Semana anterior', - 'next_week' => 'Próxima semana', - 'scheduled' => 'Manutenção Agendada', - 'scheduled_at' => ', agendada :timestamp', - 'status' => [ - 0 => 'Agendado', // TODO: Hopefully remove this. + 'none' => 'Nenhum incidente reportado', + 'past' => 'Incidentes anteriores', + 'stickied' => 'Incidentes Fixados', + 'scheduled' => 'Manutenção', + 'scheduled_at' => ', agendada :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Postado em :timestamp', + 'status' => [ 1 => 'Investigando', 2 => 'Identificado', 3 => 'Observando', @@ -41,11 +44,20 @@ ], ], + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Em breve', + 1 => 'Em Progresso', + 2 => 'Concluído', + ], + ], + // Service Status 'service' => [ - 'good' => '[0,1] Sistema operacional|[2,Inf] Todos os sistemas estão operacionais', - 'bad' => '[0,1] O sistema encontra-se com alguns problemas|[2,Inf] Alguns sistemas estão com problemas', - 'major' => '[0,1] O serviço encontra-se com uma falha geral.|[2,Inf] Alguns sistemas encontram-se com falhas gerais', + 'good' => '[0,1] Sistema operacional | [2, *] Todos os sistemas estão operacionais', + 'bad' => '[0,1] O sistema apresenta falhas|[2,*] Alguns sistemas apresentam falhas', + 'major' => '[0,1] O sistema apresenta falhas críticas|[2,Inf] Alguns sistemas apresentam falhas críticas', ], 'api' => [ @@ -65,47 +77,29 @@ // Subscriber 'subscriber' => [ - 'subscribe' => 'Inscreva-se para obter as atualizações mais recentes', - 'button' => 'Inscreva-se', - 'manage' => [ - 'no_subscriptions' => 'Você está atualmente inscrito a todas as atualizações.', - 'my_subscriptions' => 'Você está atualmente inscrito para as seguintes atualizações.', + 'subscribe' => 'Inscreva-se para mudanças de status e atualizações de incidentes', + 'unsubscribe' => 'Cancelar inscrição', + 'button' => 'Inscreva-se', + 'manage_subscription' => 'Gerenciar inscrição', + 'manage' => [ + 'notifications' => 'Notificações', + 'notifications_for' => 'Gerenciar notificações', + 'no_subscriptions' => 'Você está atualmente inscrito a todas as atualizações.', + 'update_subscription' => 'Atualizar inscrição', + 'my_subscriptions' => 'Você está atualmente inscrito para as seguintes atualizações.', + 'manage_at_link' => 'Gerencie suas inscrições aqui :link', ], 'email' => [ - 'subscribe' => 'Inscreva-se para atualizações via e-mail.', - 'subscribed' => 'Inscrição realizada com sucesso! Por favor verifique o e-mail que enviamos à você para confirmar sua inscrição.', - 'verified' => 'Sua inscrição foi confirmada! Obrigado!', - 'manage' => 'Gerencie sua assinatura', - 'unsubscribe' => 'Não desejo mais receber notificações via e-mail.', - 'unsubscribed' => 'Sua inscrição foi cancelada.', - 'failure' => 'Ocorreu um problema na sua inscrição.', - 'already-subscribed' => 'Impossível inscrever :email pois já se encontra inscrito.', - 'verify' => [ - 'text' => "Por favor, confirme sua assinatura de e-mail para receber atualizações de status de :app_name. \n:link", - 'html' => '

Por favor, confirme sua assinatura de e-mail para receber atualizações de status de :app_name.

', - 'button' => 'Confirmar inscrição', - ], - 'maintenance' => [ - 'subject' => '[Manutenção Programada] :name', - ], - 'incident' => [ - 'subject' => '[Novo incidente] :status: :name', - ], - 'component' => [ - 'subject' => 'Atualização do Estado do Componente', - 'text' => 'O componente :component_name teve uma mudança de estado. O componente está agora em :component_human_status.\nObrigado, :app_name', - 'html' => '

O componente :component_name teve uma mudança de estado. O componente está agora em :component_human_status.

Obrigado, :app_name

', - 'tooltip-title' => 'Inscrever-se as notificações de :component_name.', - ], - ], - ], - - 'users' => [ - 'email' => [ - 'invite' => [ - 'text' => "Você foi convidado para a página de status da equipe :app_name, para se inscrever siga o próximo link.\n:link\nObrigado,: app_name", - 'html' => '

Você foi convidado para a página de status da equipe :app_name, para se inscrever siga o seguinte link.

:link

Obrigado, :app_name

', - ], + 'manage_subscription' => 'Enviamos um e-mail para você, por favor clique no link para gerenciar sua assinatura', + 'subscribe' => 'Inscreva-se para atualizações via e-mail.', + 'subscribed' => 'Inscrição realizada com sucesso! Por favor verifique o e-mail que enviamos à você para confirmar sua inscrição.', + 'updated-subscribe' => 'Suas assinaturas foram atualizadas com sucesso.', + 'verified' => 'Sua inscrição foi confirmada! Obrigado!', + 'manage' => 'Gerencie sua assinatura', + 'unsubscribe' => 'Não desejo mais receber notificações via e-mail.', + 'unsubscribed' => 'Sua inscrição foi cancelada.', + 'failure' => 'Ocorreu um problema na sua inscrição.', + 'already-subscribed' => 'Impossível inscrever :email pois já se encontra inscrito.', ], ], @@ -132,10 +126,20 @@ ], ], + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Detalhes e atualizações sobre o ​​incidente :name ocorrido em :date', + 'schedule' => 'Detalhes sobre o período de manutenção agendada :name que começa em :startDate', + 'subscribe' => 'Inscreva-se para o :app e receba atualizações de incidentes e períodos de manutenção agendada', + 'overview' => 'Mantenha-se atualizado com as últimas atualizações de serviço de: app.', + ], + ], + // Other 'home' => 'Início', - 'description' => 'Mantenha-se atualizado com as últimas atualizações de serviço de: app.', 'powered_by' => 'Desenvolvido por Cachet.', + 'timezone' => 'Horários são exibidos em :timezone.', 'about_this_site' => 'Sobre este Site', 'rss-feed' => 'RSS', 'atom-feed' => 'Atom', diff --git a/resources/lang/pt-BR/dashboard.php b/resources/lang/pt-BR/dashboard.php index 833694603d2..2a8796aa88f 100644 --- a/resources/lang/pt-BR/dashboard.php +++ b/resources/lang/pt-BR/dashboard.php @@ -11,15 +11,31 @@ return [ - 'dashboard' => 'Dashboard', + 'dashboard' => 'Dashboard', + 'writeable_settings' => 'O diretório de configurações do Cachet não é gravável. Certifique-se de que ./bootstrap/cachet é gravável pelo servidor web.', // Incidents 'incidents' => [ - 'title' => 'Incidentes & Agenda', + 'title' => 'Incidentes & Agendamentos', 'incidents' => 'Incidentes', - 'logged' => '{0} Não existem incidentes, bom trabalho.|Você registrou um incidente.|Você reportou :count incidentes.', + 'logged' => '{0}Não existem incidentes, bom trabalho.|[1]Você adicionou um incidente.|[2,*]Você reportou :count incidentes.', 'incident-create-template' => 'Criar template', 'incident-templates' => 'Template de incidentes', + 'updates' => [ + 'title' => 'Atualizações para o incidente :incident', + 'count' => '{0}Nenhuma atualização|[1]Uma atualização|[2]Duas atualizações|[3,*]Várias atualizações', + 'add' => [ + 'title' => 'Crie uma nova atualização de incidente', + 'success' => 'Sua atualização de incidente foi criada.', + 'failure' => 'Algo deu errado com a atualização do incidente.', + ], + 'edit' => [ + 'title' => 'Editar atualização do incidente', + 'success' => 'Sua atualização de incidente foi atualizada.', + 'failure' => 'Algo deu errado ao atualizar as informações do incidente', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', 'add' => [ 'title' => 'Relatar um incidente', 'success' => 'Incidente adicionado.', @@ -40,7 +56,7 @@ 'title' => 'Template de incidentes', 'add' => [ 'title' => 'Criar um modelo de incidente', - 'message' => 'Você deve adicionar um modelo de incidente.', + 'message' => 'Crie seu primeiro template de incidente.', 'success' => 'Seu novo modelo de incidente foi criado.', 'failure' => 'Algo deu errado com o modelo de incidente.', ], @@ -58,22 +74,22 @@ // Incident Maintenance 'schedule' => [ - 'schedule' => 'Manutenção Agendada', - 'logged' => '{0} Não existem agendamentos, bom trabalho.|Você introduziu um agendamento.|Você reportou :count agendamentos.', + 'schedule' => 'Manutenção', + 'logged' => '{0}Ainda não ocorreu nenhuma manuteção, bom trabalho. |[1]Você agendou uma manuteção. | [2, *] Você adicionou : manutenções.', 'scheduled_at' => 'Agendada em :timestamp', 'add' => [ - 'title' => 'Adicionar manutenção programada', - 'success' => 'Programação adicionada.', - 'failure' => 'Ocorreu um problema ao adicionar a programação, por favor tente novamente.', + 'title' => 'Adicionar manutenção agendada', + 'success' => 'Manutenção adicionada.', + 'failure' => 'Algo deu errado ao adicionar a Manutenção, por favor tente novamente.', ], 'edit' => [ - 'title' => 'Edite a manutenção agendada', - 'success' => 'A programação foi atualizada!', - 'failure' => 'Ocorreu um problema ao editar a programação, por favor tente novamente.', + 'title' => 'Editar Manutenção', + 'success' => 'Manutenção atualizada!', + 'failure' => 'Algo deu errado ao editar a Manutenção, por favor tente novamente.', ], 'delete' => [ 'success' => 'A manutenção programada foi excluída e não aparecerá na sua página de status.', - 'failure' => 'A manutenção programada não pode ser excluída, por favor tente novamente.', + 'failure' => 'A Manutenção não pôde ser excluída, por favor tente novamente.', ], ], @@ -105,12 +121,12 @@ 'add' => [ 'title' => 'Adicionar um grupo de componentes', 'success' => 'Grupo de componentes adicionado.', - 'failure' => 'Algo deu errado com o grupo de componentes, por favor tente novamente.', + 'failure' => 'Algo deu errado com o componente, por favor tente novamente.', ], 'edit' => [ 'title' => 'Editar um grupo de componentes', 'success' => 'Grupo de componentes atualizado.', - 'failure' => 'Algo deu errado com o grupo de componentes, por favor tente novamente.', + 'failure' => 'Algo deu errado com o componente, por favor tente novamente.', ], 'delete' => [ 'success' => 'O grupo de componentes foi excluído!', @@ -140,13 +156,15 @@ ], // Subscribers 'subscribers' => [ - 'subscribers' => 'Assinantes', - 'description' => 'Assinantes vão receber atualizações de e-mail quando incidentes criados ou componentes atualizados.', - 'verified' => 'Verificado', - 'not_verified' => 'Não verificado', - 'subscriber' => ':email, inscreveu-se em :date', - 'no_subscriptions' => 'Inscrito em todas as atualizações', - 'add' => [ + 'subscribers' => 'Assinantes', + 'description' => 'Assinantes vão receber atualizações de e-mail quando incidentes criados ou componentes atualizados.', + 'description_disabled' => 'Para utilizar esse recurso, você precisa permitir que as pessoas se cadastrem para notificações.', + 'verified' => 'Verificado', + 'not_verified' => 'Não verificado', + 'subscriber' => ':email, inscreveu-se em :date', + 'no_subscriptions' => 'Inscrito em todas as atualizações', + 'global' => 'Inscrito globalmente', + 'add' => [ 'title' => 'Adicionar um novo assinante', 'success' => 'Inscrito adicionado.', 'failure' => 'Algo deu errado adicionando o assinante, por favor tente novamente.', @@ -197,6 +215,9 @@ 'analytics' => [ 'analytics' => 'Estatísticas', ], + 'log' => [ + 'log' => 'Log', + ], 'localization' => [ 'localization' => 'Idioma', ], @@ -205,6 +226,14 @@ 'header' => 'HTML de cabeçalho personalizado', 'footer' => 'HTML de rodapé personalizado', ], + 'mail' => [ + 'mail' => 'E-Mail', + 'test' => 'Teste', + 'email' => [ + 'subject' => 'Notificação de teste do Cachet', + 'body' => 'Esta é uma notificação de teste do Cachet.', + ], + ], 'security' => [ 'security' => 'Segurança', 'two-factor' => 'Usuários sem autenticação de dois fatores', diff --git a/resources/lang/pt-BR/forms.php b/resources/lang/pt-BR/forms.php index 8a7f79a56f5..bc56f515f4e 100644 --- a/resources/lang/pt-BR/forms.php +++ b/resources/lang/pt-BR/forms.php @@ -22,7 +22,13 @@ 'site_locale' => 'Selecione seu idioma', 'enable_google2fa' => 'Habilitar a autenticação de dois fatores do Google', 'cache_driver' => 'Driver de Cache', + 'queue_driver' => 'Driver na fila', 'session_driver' => 'Driver de Sessão', + 'mail_driver' => 'Driver de correio', + 'mail_host' => 'Host de correio', + 'mail_address' => 'Correio do endereço', + 'mail_username' => 'Nome de usuário de email', + 'mail_password' => 'Senha de email', ], // Login form fields @@ -35,6 +41,7 @@ 'invalid-token' => 'Token inválido', 'cookies' => 'Você deve habilitar os cookies do navegador para logar.', 'rate-limit' => 'Limite de acesso excedido.', + 'remember_me' => 'Lembrar-me', ], // Incidents form fields @@ -42,18 +49,36 @@ 'name' => 'Nome', 'status' => 'Status', 'component' => 'Componente', + 'component_status' => 'Status do componente', 'message' => 'Mensagem', 'message-help' => 'Você também pode usar o Markdown.', - 'scheduled_at' => 'Agendar a manutenção para quando?', - 'incident_time' => 'Quando esse incidente ocorreu?', + 'occurred_at' => 'Quando este incidente ocorreu?', 'notify_subscribers' => 'Notificar os assinantes?', + 'notify_disabled' => 'Devido a manutenção programada, notificações sobre este incidente ou seus componentes não serão feitas.', 'visibility' => 'Visibilidade do incidente', + 'stick_status' => 'Incidente fixado', + 'stickied' => 'Fixado', + 'not_stickied' => 'Não Fixado', 'public' => 'Visível para todos', 'logged_in_only' => 'Visível somente para usuários logados', 'templates' => [ 'name' => 'Nome', 'template' => 'Template', - 'twig' => 'Esboços de incidentes podem fazer uso da linguagem de template Twig.', + 'twig' => 'Esboços de incidentes podem fazer uso da linguagem de template Twig.', + ], + ], + + 'schedules' => [ + 'name' => 'Nome', + 'status' => 'Status', + 'message' => 'Mensagem', + 'message-help' => 'Você também pode usar o Markdown.', + 'scheduled_at' => 'Esta manutenção foi programada para quando?', + 'completed_at' => 'Quando esta manutenção foi concluída?', + 'templates' => [ + 'name' => 'Nome', + 'template' => 'Template', + 'twig' => 'Esboços de incidentes podem fazer uso da linguagem de template Twig.', ], ], @@ -69,28 +94,50 @@ 'enabled' => 'Componente activado?', 'groups' => [ - 'name' => 'Nome', - 'collapsing' => 'Escolha a visibilidade do grupo', - 'visible' => 'Sempre expandido', - 'collapsed' => 'Colapsar o grupo por padrão', - 'collapsed_incident' => 'Colapsar o grupo, mas expandir se ocorrer algum problema', + 'name' => 'Nome', + 'collapsing' => 'Expandir/recolher opções', + 'visible' => 'Sempre expandido', + 'collapsed' => 'Colapsar o grupo por padrão', + 'collapsed_incident' => 'Colapsar o grupo, mas expandir se ocorrer algum problema', + 'visibility' => 'Visibilidade', + 'visibility_public' => 'Visível ao Público', + 'visibility_authenticated' => 'Visível apenas para usuários autenticados', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Nome', + 'description' => 'Descrição', + 'start_at' => 'Agendar horário de início', + 'timezone' => 'Fuso horário', + 'schedule_frequency' => 'Agendar frequência (em segundos)', + 'completion_latency' => 'Latência de conclusão (em segundos)', + 'group' => 'Grupo', + 'active' => 'Ativado?', + 'groups' => [ + 'name' => 'Nome do Grupo', ], ], // Metric form fields 'metrics' => [ - 'name' => 'Nome', - 'suffix' => 'Sufixo', - 'description' => 'Descrição', - 'description-help' => 'Você também pode usar Markdown.', - 'display-chart' => 'Exibir o gráfico na página de status?', - 'default-value' => 'Valor padrão', - 'calc_type' => 'Cálculo de métricas', - 'type_sum' => 'Soma', - 'type_avg' => 'Média', - 'places' => 'Casas decimais', - 'default_view' => 'Visualização padrão', - 'threshold' => 'Quantos minutos de limite entre os pontos das métricas?', + 'name' => 'Nome', + 'suffix' => 'Sufixo', + 'description' => 'Descrição', + 'description-help' => 'Você também pode usar o Markdown.', + 'display-chart' => 'Exibir o gráfico na página de status?', + 'default-value' => 'Valor padrão', + 'calc_type' => 'Cálculo de métricas', + 'type_sum' => 'Soma', + 'type_avg' => 'Média', + 'places' => 'Casas decimais', + 'default_view' => 'Visualização padrão', + 'threshold' => 'Quantos minutos de limite entre os pontos das métricas?', + 'visibility' => 'Visibilidade', + 'visibility_authenticated' => 'Visível para usuários autenticados', + 'visibility_public' => 'Visível para todos', + 'visibility_hidden' => 'Sempre oculto', 'points' => [ 'value' => 'Valor', @@ -99,33 +146,42 @@ // Settings 'settings' => [ - /// Application setup + // Application setup 'app-setup' => [ - 'site-name' => 'Nome do site', - 'site-url' => 'URL do site', - 'display-graphs' => 'Exibir gráficos na página de status?', - 'about-this-page' => 'Sobre esta página', - 'days-of-incidents' => 'Quantos dias de incidentes para mostrar?', - 'banner' => 'Imagem do banner', - 'banner-help' => 'É recomendável que você faça upload de arquivos menores que 930px .', - 'subscribers' => 'Permitir que outras pessoas se cadastrem para notificações via e-mail?', - 'automatic_localization' => 'Localizar sua página de status de acordo com o idioma do visitante automaticamente?', + 'site-name' => 'Nome do site', + 'site-url' => 'URL do site', + 'display-graphs' => 'Exibir gráficos na página de status?', + 'about-this-page' => 'Sobre esta página', + 'days-of-incidents' => 'Quantos dias de incidentes para mostrar?', + 'time_before_refresh' => 'Frequência de atualização da página de status (em segundos)', + 'major_outage_rate' => 'Limite de indisponibilidade (em %)', + 'banner' => 'Imagem do banner', + 'banner-help' => 'Recomenda-se que você envie arquivos com até 930 pixels de largura', + 'subscribers' => 'Permitir que outras pessoas se cadastrem para notificações via e-mail?', + 'suppress_notifications_in_maintenance' => 'Não enviar notificações quando o incidente ocorrer durante o período de manutenção?', + 'skip_subscriber_verification' => 'Ignorar verificação de usuários? (Cuidado, você pode sofrer com spam)', + 'automatic_localization' => 'Localizar sua página de status de acordo com o idioma do visitante automaticamente?', + 'enable_external_dependencies' => 'Ativar dependências de terceiros (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Mostrar o fuso horário no qual a página de status está sendo executada', + 'only_disrupted_days' => 'Mostrar apenas os dias que contenham incidentes na linha do tempo?', ], 'analytics' => [ 'analytics_google' => 'Código do Google Analytics', 'analytics_gosquared' => 'Código do GoSquared Analytics', - 'analytics_piwik_url' => 'URL para a instância do Piwik (sem o http(s)://)', + 'analytics_piwik_url' => 'URL da sua instância Piwik', 'analytics_piwik_siteid' => 'Id do site no Piwik', ], 'localization' => [ - 'site-timezone' => 'Fuso horário do site', - 'site-locale' => 'Idioma do site', - 'date-format' => 'Formato da data', - 'incident-date-format' => 'Formato de Hora do Incidente', + 'site-timezone' => 'Fuso horário do site', + 'site-locale' => 'Idioma do site', + 'date-format' => 'Formato da data', + 'incident-date-format' => 'Formato de Hora do Incidente', ], 'security' => [ - 'allowed-domains' => 'Domínios permitidos', - 'allowed-domains-help' => 'Separados por vírgula. O domínio definido acima é permitido automaticamente por padrão.', + 'allowed-domains' => 'Domínios permitidos', + 'allowed-domains-help' => 'Separados por vírgula. O domínio definido acima é permitido automaticamente por padrão.', + 'always-authenticate' => 'Autenticar sempre', + 'always-authenticate-help' => 'Exigir login para ver qualquer página do sistema', ], 'stylesheet' => [ 'custom-css' => 'Folha de estilos personalizada', @@ -135,7 +191,7 @@ 'background-fills' => 'Preenchimento de Fundo (Componentes, Incidentes, Rodapé)', 'banner-background-color' => 'Cor de Fundo do banner', 'banner-padding' => 'Margem interna', - 'fullwidth-banner' => 'Habilitar largura completa do banner?', + 'fullwidth-banner' => 'Habilitar banner com largura total?', 'text-color' => 'Cor do Texto', 'dashboard-login' => 'Mostrar botão para painel no rodapé?', 'reds' => 'Vermelho (Usado para erros)', @@ -165,22 +221,32 @@ ], 'team' => [ 'description' => 'Convide membros da sua equipe através do endereço de e-mail aqui.', - 'email' => 'Email #:id', + 'email' => 'Endereço de e-mail dos membros da sua equipe', ], ], + 'general' => [ + 'timezone' => 'Selecione o fuso horário', + ], + + 'seo' => [ + 'title' => 'Título para SEO', + 'description' => 'Descrição para SEO', + ], + // Buttons - 'add' => 'Adicionar', - 'save' => 'Salvar', - 'update' => 'Atualizar', - 'create' => 'Criar', - 'edit' => 'Editar', - 'delete' => 'Apagar', - 'submit' => 'Enviar', - 'cancel' => 'Cancelar', - 'remove' => 'Remover', - 'invite' => 'Convite', - 'signup' => 'Cadastrar-se', + 'add' => 'Adicionar', + 'save' => 'Salvar', + 'update' => 'Atualizar', + 'create' => 'Criar', + 'edit' => 'Editar', + 'delete' => 'Apagar', + 'submit' => 'Enviar', + 'cancel' => 'Cancelar', + 'remove' => 'Remover', + 'invite' => 'Convite', + 'signup' => 'Cadastrar-se', + 'manage_updates' => 'Gerenciar atualizações', // Other 'optional' => '* Opcional', diff --git a/resources/lang/pt-BR/notifications.php b/resources/lang/pt-BR/notifications.php new file mode 100644 index 00000000000..a4fb209890f --- /dev/null +++ b/resources/lang/pt-BR/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Status do Componente Atualizado', + 'greeting' => 'O status de um componente foi atualizado!', + 'content' => 'O status de :name mudou de :old_status para :new_status.', + 'action' => 'Visualizar', + ], + 'slack' => [ + 'title' => 'Status do Componente Atualizado', + 'content' => 'O status de :name mudou de :old_status para :new_status.', + ], + 'sms' => [ + 'content' => 'O status de :name mudou de :old_status para :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Novo incidente reportado', + 'greeting' => 'Um novo incidente foi reportado em :app_name.', + 'content' => 'O Incidente :name foi reportado', + 'action' => 'Visualizar', + ], + 'slack' => [ + 'title' => 'Incidente :name reportado', + 'content' => 'Um novo incidente foi relatado em :app_name', + ], + 'sms' => [ + 'content' => 'Um novo incidente foi reportado em :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incidente Atualizado', + 'content' => ':name foi atualizado', + 'title' => ':name foi atualizado para :new_status', + 'action' => 'Visualizar', + ], + 'slack' => [ + 'title' => ':name atualizado', + 'content' => ':name foi atualizado para :new_status', + ], + 'sms' => [ + 'content' => 'Incidente :name foi atualizado', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'Novo Agendamento Criado', + 'content' => ':name foi agendado para :date', + 'title' => 'Uma nova manutenção agendada foi criada.', + 'action' => 'Visualizar', + ], + 'slack' => [ + 'title' => 'Novo Agendamento Criado!', + 'content' => ':name foi agendado para :date', + ], + 'sms' => [ + 'content' => ':name foi agendado para :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verifique a sua inscrição', + 'content' => 'Clique para verificar sua inscrição na página de status :app_name.', + 'title' => 'Verifique sua inscrição na página de status de :app_name.', + 'action' => 'Verifique', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Gerenciar inscrição', + 'content' => 'Clique para gerenciar sua inscrição na página de status de :app_name.', + 'title' => 'Clique para gerenciar sua inscrição na página de status de :app_name.', + 'action' => 'Gerenciar inscrição', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping do Cachet!', + 'content' => 'Esta é uma notificação de teste do Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Seu convite está aqui dentro...', + 'content' => 'Você foi convidado para fazer parte da página de status :app_name.', + 'title' => 'Você foi convidado para fazer parte da página de status :app_name.', + 'action' => 'Aceitar', + ], + ], + ], +]; diff --git a/resources/lang/pt-BR/pagination.php b/resources/lang/pt-BR/pagination.php index 5599d696218..2eccd92284f 100644 --- a/resources/lang/pt-BR/pagination.php +++ b/resources/lang/pt-BR/pagination.php @@ -22,7 +22,7 @@ | */ - 'previous' => '« Anterior', - 'next' => 'Próximo »', + 'previous' => 'Anterior', + 'next' => 'Próxima', ]; diff --git a/resources/lang/pt-BR/validation.php b/resources/lang/pt-BR/validation.php index 4029fd21797..37dfb385d9e 100644 --- a/resources/lang/pt-BR/validation.php +++ b/resources/lang/pt-BR/validation.php @@ -23,7 +23,7 @@ */ 'accepted' => 'O campo :attribute deve ser aceito.', - 'active_url' => 'O campo :attribute não é uma URL válida.', + 'active_url' => 'O campo :attribute não contém uma URL válida.', 'after' => 'O campo :attribute deverá conter uma data posterior a :date.', 'alpha' => 'O campo :attribute deverá conter apenas letras.', 'alpha_dash' => 'O campo :attribute só pode conter letras, números, e hifens.', @@ -31,60 +31,60 @@ 'array' => 'O campo :attribute deve ser um vetor.', 'before' => 'O campo :attribute deverá conter uma data anterior a :date.', 'between' => [ - 'numeric' => 'O campo :attribute deverá conter uma data anterior a :date.', - 'file' => 'O campo :attribute deverá ter um valor entre :min - :max.', - 'string' => 'O campo :attribute deverá ter um tamanho entre :min - :max kilobytes.', + 'numeric' => 'O campo :attribute deverá ter um valor entre :min - :max.', + 'file' => 'O campo :attribute deve estar entre :min e :max kilobytes.', + 'string' => 'O campo :attribute deve ter entre :min e :max caracteres.', 'array' => 'O campo :attribute deve ter entre :min e :max itens.', ], - 'boolean' => 'O campo :attribute deve ter entre :min e :max itens.', - 'confirmed' => 'O campo :attribute deve ser verdadeiro ou falso.', - 'date' => 'A confirmação do :attribute é inválida ou não correspondente.', - 'date_format' => 'O campo :attribute não contém uma data válida.', - 'different' => 'A data indicada para o campo :attribute não respeita o formato :format.', - 'digits' => 'Os campos :attribute e :other devem conter valores diferentes.', - 'digits_between' => 'O campo :attribute deve conter :digits dígitos.', - 'email' => 'O campo :attribute deve conter entre :min a :max dígitos.', - 'exists' => 'O campo :attribute tem que ser um e-mail válido.', + 'boolean' => 'O campo :attribute deve ser verdadeiro ou falso.', + 'confirmed' => 'A confirmação do campo :attribute não corresponde.', + 'date' => 'O campo :attribute não é uma data válida.', + 'date_format' => 'O campo :attribute não corresponde ao formato :format.', + 'different' => 'O campo :attribute e :other devem ser diferentes.', + 'digits' => 'O campo :attribute deve ter :digits dígitos.', + 'digits_between' => 'O campo :attribute deve ter entre :min e :max dígitos.', + 'email' => 'O campo :attribute deve ser um endereço de email válido.', + 'exists' => 'O campo :attribute é inválido.', 'distinct' => 'O campo :attribute tem um valor duplicado.', - 'filled' => 'O formato de :attribute é inválido.', + 'filled' => 'O campo :attribute é obrigatório.', 'image' => 'O :attribute deve ser uma imagem.', - 'in' => 'O :attribute deve ser uma imagem.', + 'in' => 'O campo :attribute é inválido.', 'in_array' => 'O campo :attribute não existe em :other.', - 'integer' => 'O valor selecionado para o campo :attribute é inválido.', - 'ip' => 'O campo :attribute deve ser um número inteiro.', + 'integer' => 'O campo :attribute deve ser um número inteiro.', + 'ip' => 'O campo :attribute deve ser um endereço de IP válido.', 'json' => 'O :attribute tem que ser uma string JSON válida.', 'max' => [ - 'numeric' => 'O campo :attribute deve ser um IP válido.', - 'file' => 'O campo :attribute não pode ser maior do que :max.', - 'string' => 'O campo :attribute não deverá ter um tamanho superior a :max kilobytes.', + 'numeric' => 'O campo :attribute não deve ser maior que :max.', + 'file' => 'O campo :attribute não deve ser maior que :max kilobytes.', + 'string' => 'O campo :attribute não deve ser maior que :max caracteres.', 'array' => 'A: atributo não pode ter mais de que :max itens.', ], - 'mimes' => 'A: atributo não pode ter mais de que :max itens.', + 'mimes' => 'O campo :attribute deve ser um arquivo do tipo: :values.', 'min' => [ - 'numeric' => 'O campo :attribute deverá conter um arquivo do tipo: :values.', + 'numeric' => 'O campo :attribute deve ter no mínimo :min.', 'file' => 'O :attribute deve ter pelo menos :min kilobytes.', - 'string' => 'O :attribute deve ter pelo menos :min kilobytes.', - 'array' => 'O campo :attribute deverá conter no mínimo :min caracteres.', + 'string' => 'O campo :attribute deve ter no mínimo :min caracteres.', + 'array' => 'O campo :attribute deve ter no mínimo :min itens.', ], - 'not_in' => 'O campo :attribute deve ter pelo menos :min itens.', - 'numeric' => 'O valor selecionado para o campo :attribute é inválido.', + 'not_in' => 'O campo :attribute é inválido.', + 'numeric' => 'O campo :attribute deve ser um número.', 'present' => 'O campo :attribute deve estar presente.', - 'regex' => 'O campo :attribute deve ser um número.', - 'required' => 'O formato de :attribute é inválido.', - 'required_if' => 'O campo :attribute é obrigatório.', - 'required_unless' => 'O campo :attribute é obrigatório a não ser que :other estiver em :values.', - 'required_with' => 'O campo :attribute é obrigatório quando :other é :value.', + 'regex' => 'O formato de :attribute é inválido.', + 'required' => 'O campo :attribute é obrigatório.', + 'required_if' => 'O campo :attribute é obrigatório quando :other é :value.', + 'required_unless' => 'O campo :attribute é obrigatório a não ser que :other esteja entre :values.', + 'required_with' => 'O campo :attribute é obrigatório quando :values está presente.', 'required_with_all' => 'O campo :attribute é obrigatório quando :values está presente.', - 'required_without' => 'O campo :attribute é obrigatório quando :values está presente.', - 'required_without_all' => 'O campo :attribute é obrigatório quando :values não está presente.', - 'same' => 'O campo :attribute é necessário quando não há :values presentes.', + 'required_without' => 'O campo :attribute é obrigatório quando :values não está presente.', + 'required_without_all' => 'O campo :attribute é obrigatório quando nenhum dos :values está presente.', + 'same' => 'O campo :attribute e :other devem ser iguais.', 'size' => [ - 'numeric' => 'Os campos :attribute e :other devem ser iguais.', + 'numeric' => 'O campo :attribute deve ter :size caracteres.', 'file' => 'O :attribute deve ter :size kilobytes.', 'string' => 'O :attribute deve ter :size caracteres.', - 'array' => 'O :attribute deve ter :size caracteres.', + 'array' => 'O campo :attribute deve ter :size itens.', ], - 'string' => 'O campo :attribute deve ter :size itens.', + 'string' => 'O campo :attribute deve ser uma string.', 'timezone' => 'O :attribute deve ser uma zona válida.', 'unique' => 'O :attribute já existe.', 'url' => 'O formato de :attribute é inválido.', diff --git a/resources/lang/pt-PT/cachet.php b/resources/lang/pt-PT/cachet.php index d9f3c2bddd2..8c50a99d1e4 100644 --- a/resources/lang/pt-PT/cachet.php +++ b/resources/lang/pt-PT/cachet.php @@ -14,6 +14,7 @@ 'components' => [ 'last_updated' => 'Last updated :timestamp', 'status' => [ + 0 => 'Unknown', 1 => 'Operacional', 2 => 'Problemas de performance', 3 => 'Indisponibilidade parcial', @@ -22,18 +23,20 @@ 'group' => [ 'other' => 'Other Components', ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', ], // Incidents 'incidents' => [ - 'none' => 'Nenhum incidente reportado', - 'past' => 'Incidentes anteriores', - 'previous_week' => 'Semana anterior', - 'next_week' => 'Próxima semana', - 'scheduled' => 'Manutenção Agendada', - 'scheduled_at' => ', agendada :timestamp', - 'status' => [ - 0 => 'Agendada', // TODO: Hopefully remove this. + 'none' => 'Nenhum incidente reportado', + 'past' => 'Incidentes anteriores', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', agendada :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ 1 => 'Investigando', 2 => 'Identificado', 3 => 'Observando', @@ -41,11 +44,20 @@ ], ], + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + // Service Status 'service' => [ - 'good' => '[0,1] Sistema operacional|[2,Inf] Todos os sistemas estão operacionais', - 'bad' => '[0,1] O sistema encontra-se com alguns problemas|[2,Inf] Alguns sistemas estão com problemas', - 'major' => '[0,1] O serviço encontra-se com uma falha geral.|[2,Inf] Alguns sistemas encontram-se com falhas gerais', + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', ], 'api' => [ @@ -65,47 +77,29 @@ // Subscriber 'subscriber' => [ - 'subscribe' => 'Inscreva-se para obter as atualizações mais recentes', - 'button' => 'Subscrever', - 'manage' => [ - 'no_subscriptions' => 'You\'re currently subscribed to all updates.', - 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscrever', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notificações', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', ], 'email' => [ - 'subscribe' => 'Subscrever actualizações via email.', - 'subscribed' => 'Subscreveu as notificações por e-mail, por favor verifique o seu e-mail para confirmar a subscrição.', - 'verified' => 'A sua subscrição por e-mail foi confirmada. Obrigado!', - 'manage' => 'Manage your subscription', - 'unsubscribe' => 'Remover subscrição de e-mail.', - 'unsubscribed' => 'A sua subscrição de e-mail foi cancelada.', - 'failure' => 'Algo correu mal com a sua subscrição.', - 'already-subscribed' => 'Não posso subscrever :email pois já se encontra subscrito.', - 'verify' => [ - 'text' => "Please confirm your email subscription to :app_name status updates.\n:link", - 'html' => '

Please confirm your email subscription to :app_name status updates.

', - 'button' => 'Confirm Subscription', - ], - 'maintenance' => [ - 'subject' => '[Maintenance Scheduled] :name', - ], - 'incident' => [ - 'subject' => '[New Incident] :status: :name', - ], - 'component' => [ - 'subject' => 'Atualização do Estado do Componente', - 'text' => 'O componente :component_name teve uma mudança de estado. O componente está agora em :component_human_status.\nObrigado, :app_name', - 'html' => '

O componente :component_name teve uma mudança de estado. O componente está agora em :component_human_status.

Obrigado, :app_name

', - 'tooltip-title' => 'Subscrever a notificações de :component_name.', - ], - ], - ], - - 'users' => [ - 'email' => [ - 'invite' => [ - 'text' => "Você foi convidado para a equipa :app_name página de status, para se inscrever siga o próximo link.\n:link\nObrigado, :app_name", - 'html' => '

Foi convidado para a equipa :app_name página de status, para se inscrever siga o seguinte link.

:link

Obrigado, :app_name

', - ], + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscrever actualizações via email.', + 'subscribed' => 'Subscreveu as notificações por e-mail, por favor verifique o seu e-mail para confirmar a subscrição.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'A sua subscrição por e-mail foi confirmada. Obrigado!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Remover subscrição de e-mail.', + 'unsubscribed' => 'A sua subscrição de e-mail foi cancelada.', + 'failure' => 'Algo correu mal com a sua subscrição.', + 'already-subscribed' => 'Não posso subscrever :email pois já se encontra subscrito.', ], ], @@ -132,10 +126,20 @@ ], ], + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + // Other 'home' => 'Home', - 'description' => 'Stay up to date with the latest service updates from :app.', 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', 'about_this_site' => 'Sobre este Site', 'rss-feed' => 'RSS', 'atom-feed' => 'Atom', diff --git a/resources/lang/pt-PT/dashboard.php b/resources/lang/pt-PT/dashboard.php index 3f54feb36e0..353828fcb1a 100644 --- a/resources/lang/pt-PT/dashboard.php +++ b/resources/lang/pt-PT/dashboard.php @@ -11,15 +11,31 @@ return [ - 'dashboard' => 'Dashboard', + 'dashboard' => 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', // Incidents 'incidents' => [ - 'title' => 'Incidentes & Agendamentos', + 'title' => 'Incidents & Maintenance', 'incidents' => 'Ocorrências', - 'logged' => '{0} Não existem incidentes, bom trabalho.|Você registrou um incidente.|Você reportou :count incidentes.', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', 'incident-create-template' => 'Criar template', 'incident-templates' => 'Template de incidentes', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', 'add' => [ 'title' => 'Adicionar um incidente', 'success' => 'Incident added.', @@ -40,7 +56,7 @@ 'title' => 'Template de incidentes', 'add' => [ 'title' => 'Criar um modelo de incidente', - 'message' => 'Adicione um esboço de incidente.', + 'message' => 'Create your first incident template.', 'success' => 'Your new incident template has been created.', 'failure' => 'Something went wrong with the incident template.', ], @@ -58,22 +74,22 @@ // Incident Maintenance 'schedule' => [ - 'schedule' => 'Manutenção Agendada', - 'logged' => '{0} Não existem agendamentos, bom trabalho.|Você introduziu um agendamento.|Você reportou :count agendamentos.', + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', 'scheduled_at' => 'Agendada em :timestamp', 'add' => [ - 'title' => 'Add Scheduled Maintenance', - 'success' => 'Schedule added.', - 'failure' => 'Something went wrong adding the schedule, please try again.', + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', ], 'edit' => [ - 'title' => 'Edit Scheduled Maintenance', - 'success' => 'Schedule has been updated!', - 'failure' => 'Something went wrong editing the schedule, please try again.', + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', ], 'delete' => [ - 'success' => 'The scheduled maintenance has been deleted and will not show on your status page.', - 'failure' => 'The scheduled maintenance could not be deleted, please try again.', + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', ], ], @@ -86,12 +102,12 @@ 'title' => 'Adicionar um Componente', 'message' => 'Você deve adicionar um componente.', 'success' => 'Component created.', - 'failure' => 'Something went wrong with the component, please try again.', + 'failure' => 'Something went wrong with the component group, please try again.', ], 'edit' => [ 'title' => 'Editar um Componente', 'success' => 'Component updated.', - 'failure' => 'Something went wrong with the component, please try again.', + 'failure' => 'Something went wrong with the component group, please try again.', ], 'delete' => [ 'success' => 'O componente foi apagado!', @@ -140,13 +156,15 @@ ], // Subscribers 'subscribers' => [ - 'subscribers' => 'Assinantes', - 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', - 'verified' => 'Verificado', - 'not_verified' => 'Não Verificado', - 'subscriber' => ':email, subscribed :date', - 'no_subscriptions' => 'Subscribed to all updates', - 'add' => [ + 'subscribers' => 'Assinantes', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verificado', + 'not_verified' => 'Não Verificado', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ 'title' => 'Adicionar um novo assinante', 'success' => 'Assinante adicionado.', 'failure' => 'Something went wrong adding the subscriber, please try again.', @@ -197,6 +215,9 @@ 'analytics' => [ 'analytics' => 'Analítica', ], + 'log' => [ + 'log' => 'Log', + ], 'localization' => [ 'localization' => 'Localização', ], @@ -205,6 +226,14 @@ 'header' => 'Custom Header HTML', 'footer' => 'Custom Footer HTML', ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], 'security' => [ 'security' => 'Segurança', 'two-factor' => 'Utilizados sem factor de dupla autenticação', @@ -254,14 +283,14 @@ 'support' => 'Support Cachet', 'support_subtitle' => 'Check out our Patreon page!', 'news' => 'Latest News', - 'news_subtitle' => 'Get the latest updates', + 'news_subtitle' => 'Get the latest update', ], // Welcome modal 'welcome' => [ 'welcome' => 'Bem vindo à sua página de estado!', 'message' => 'Sua página de status está quase pronta! Tavez vocë queira checar essas configurações extras', - 'close' => 'Take me straight to my dashboard', + 'close' => 'I\'m good thanks!', 'steps' => [ 'component' => 'Criar componentes', 'incident' => 'Criar incidentes', diff --git a/resources/lang/pt-PT/forms.php b/resources/lang/pt-PT/forms.php index ddecf9a3fc0..c2ebe455664 100644 --- a/resources/lang/pt-PT/forms.php +++ b/resources/lang/pt-PT/forms.php @@ -22,19 +22,26 @@ 'site_locale' => 'Selecione seu idioma', 'enable_google2fa' => 'Habilitar a autenticação de dois fatores do Google', 'cache_driver' => 'Driver de Cache', + 'queue_driver' => 'Queue Driver', 'session_driver' => 'Driver de Sessão', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', ], // Login form fields 'login' => [ 'login' => 'Nome de utilizador ou E-mail', - 'email' => 'Endereço de Correio', + 'email' => 'E-mail', 'password' => 'Senha', '2fauth' => 'Código de autenticação', 'invalid' => 'Nome de utilizador ou palavra-passe inválidos', 'invalid-token' => 'Token inválido', 'cookies' => 'Deverá activar cookies para efectuar autenticação.', 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', ], // Incidents form fields @@ -42,18 +49,36 @@ 'name' => 'Nome', 'status' => 'Estado', 'component' => 'Componente', + 'component_status' => 'Component Status', 'message' => 'Mensagem', 'message-help' => 'Você também pode usar o Markdown.', - 'scheduled_at' => 'Para quando pretende agendar a manutenção?', - 'incident_time' => 'Quando é que este incidente ocorreu?', + 'occurred_at' => 'When did this incident occur?', 'notify_subscribers' => 'Notificar subscritores?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', 'public' => 'Visível ao Publico', 'logged_in_only' => 'Apenas visível para users autenticados', 'templates' => [ 'name' => 'Nome', 'template' => 'Template', - 'twig' => 'Esboços de incidentes podem fazer uso da linguagem de template Twig.', + 'twig' => 'Esboços de incidentes podem fazer uso da linguagem de template Twig.', + ], + ], + + 'schedules' => [ + 'name' => 'Nome', + 'status' => 'Estado', + 'message' => 'Mensagem', + 'message-help' => 'Você também pode usar o Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Nome', + 'template' => 'Template', + 'twig' => 'Esboços de incidentes podem fazer uso da linguagem de template Twig.', ], ], @@ -69,28 +94,50 @@ 'enabled' => 'Componente activado?', 'groups' => [ - 'name' => 'Nome', - 'collapsing' => 'Choose visibility of the group', - 'visible' => 'Always expanded', - 'collapsed' => 'Collapse the group by default', - 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'name' => 'Nome', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Nome', + 'description' => 'Descrição', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Grupo', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', ], ], // Metric form fields 'metrics' => [ - 'name' => 'Nome', - 'suffix' => 'Sufixo', - 'description' => 'Descrição', - 'description-help' => 'Poderá também usar Markdown.', - 'display-chart' => 'Mostrar gráfico na página de estado?', - 'default-value' => 'Valor Padrão', - 'calc_type' => 'Cálculo de Métricas', - 'type_sum' => 'Soma', - 'type_avg' => 'Média', - 'places' => 'Casas Decimais', - 'default_view' => 'Vista por defeito', - 'threshold' => 'How many minutes of threshold between metric points?', + 'name' => 'Nome', + 'suffix' => 'Sufixo', + 'description' => 'Descrição', + 'description-help' => 'Você também pode usar o Markdown.', + 'display-chart' => 'Mostrar gráfico na página de estado?', + 'default-value' => 'Valor Padrão', + 'calc_type' => 'Cálculo de Métricas', + 'type_sum' => 'Soma', + 'type_avg' => 'Média', + 'places' => 'Casas Decimais', + 'default_view' => 'Vista por defeito', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', 'points' => [ 'value' => 'Valor', @@ -99,44 +146,53 @@ // Settings 'settings' => [ - /// Application setup + // Application setup 'app-setup' => [ - 'site-name' => 'Nome do site', - 'site-url' => 'URL do site', - 'display-graphs' => 'Mostrar gráficos na página de estado?', - 'about-this-page' => 'Sobre esta página', - 'days-of-incidents' => 'Quantos dias de incidentes para mostrar?', - 'banner' => 'Banner Image', - 'banner-help' => 'É recomendável que você faça upload de arquivos menores que 930px .', - 'subscribers' => 'Permitir que as pessoas subscrevam as notificações?', - 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'site-name' => 'Nome do site', + 'site-url' => 'URL do site', + 'display-graphs' => 'Mostrar gráficos na página de estado?', + 'about-this-page' => 'Sobre esta página', + 'days-of-incidents' => 'Quantos dias de incidentes para mostrar?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Permitir que as pessoas subscrevam as notificações?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', ], 'analytics' => [ 'analytics_google' => 'Código do Google Analytics', 'analytics_gosquared' => 'Código do GoSquared Analytics', - 'analytics_piwik_url' => 'URL da instância do Piwik (sem http(s)://)', + 'analytics_piwik_url' => 'URL of your Piwik instance', 'analytics_piwik_siteid' => 'ID do site Piwik', ], 'localization' => [ - 'site-timezone' => 'Fuso horário do site', - 'site-locale' => 'Idioma do site', - 'date-format' => 'Formato da Data', - 'incident-date-format' => 'Formato da Hora do Incidente', + 'site-timezone' => 'Fuso horário do site', + 'site-locale' => 'Idioma do site', + 'date-format' => 'Formato da Data', + 'incident-date-format' => 'Formato da Hora do Incidente', ], 'security' => [ - 'allowed-domains' => 'Domínios permitidos', - 'allowed-domains-help' => 'Separados por vírgula. O domínio definido acima é permitido automaticamente por padrão.', + 'allowed-domains' => 'Domínios permitidos', + 'allowed-domains-help' => 'Separados por vírgula. O domínio definido acima é permitido automaticamente por padrão.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', ], 'stylesheet' => [ 'custom-css' => 'Custom Stylesheet', ], 'theme' => [ - 'background-color' => 'Background Color', + 'background-color' => 'Background color', 'background-fills' => 'Preenchimento de Fundo (Componentes, Incidentes, Rodapé)', 'banner-background-color' => 'Cor de Fundo do banner', 'banner-padding' => 'Espaçamento do Banner', - 'fullwidth-banner' => 'Habilitar largura completa do banner?', - 'text-color' => 'Text Color', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', 'dashboard-login' => 'Mostrar botão para painel no rodapé?', 'reds' => 'Vermelho (Usado para erros)', 'blues' => 'Azul (usado para informações)', @@ -165,22 +221,32 @@ ], 'team' => [ 'description' => 'Convide membros da sua equipa através do endereço de e-mail aqui.', - 'email' => 'Email', + 'email' => 'Your Team Members Email Address', ], ], + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + // Buttons - 'add' => 'Adicionar', - 'save' => 'Salvar', - 'update' => 'Atualizar', - 'create' => 'Criar', - 'edit' => 'Editar', - 'delete' => 'Apagar', - 'submit' => 'Enviar', - 'cancel' => 'Cancelar', - 'remove' => 'Remover', - 'invite' => 'Convite', - 'signup' => 'Registrar', + 'add' => 'Adicionar', + 'save' => 'Salvar', + 'update' => 'Atualizar', + 'create' => 'Criar', + 'edit' => 'Editar', + 'delete' => 'Apagar', + 'submit' => 'Enviar', + 'cancel' => 'Cancelar', + 'remove' => 'Remover', + 'invite' => 'Convite', + 'signup' => 'Registrar', + 'manage_updates' => 'Manage Updates', // Other 'optional' => '* Opcional', diff --git a/resources/lang/pt-PT/notifications.php b/resources/lang/pt-PT/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/pt-PT/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/pt-PT/pagination.php b/resources/lang/pt-PT/pagination.php index 5599d696218..0ee724cf086 100644 --- a/resources/lang/pt-PT/pagination.php +++ b/resources/lang/pt-PT/pagination.php @@ -22,7 +22,7 @@ | */ - 'previous' => '« Anterior', - 'next' => 'Próximo »', + 'previous' => 'Previous', + 'next' => 'Next', ]; diff --git a/resources/lang/pt-PT/validation.php b/resources/lang/pt-PT/validation.php index 9527edde261..c6f650c7b98 100644 --- a/resources/lang/pt-PT/validation.php +++ b/resources/lang/pt-PT/validation.php @@ -31,60 +31,60 @@ 'array' => 'O campo :attribute deve ser um vetor.', 'before' => 'O campo :attribute deverá conter uma data anterior a :date.', 'between' => [ - 'numeric' => 'O campo :attribute deverá conter uma data anterior a :date.', - 'file' => 'The :attribute must be between :min and :max.', - 'string' => 'The :attribute must be between :min and :max kilobytes.', + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', 'array' => 'O campo :attribute deve ter entre :min e :max itens.', ], - 'boolean' => 'O campo :attribute deve ter entre :min e :max itens.', - 'confirmed' => 'The :attribute field must be true or false.', - 'date' => 'The :attribute confirmation does not match.', - 'date_format' => 'The :attribute is not a valid date.', - 'different' => 'The :attribute does not match the format :format.', - 'digits' => 'The :attribute and :other must be different.', - 'digits_between' => 'The :attribute must be :digits digits.', - 'email' => 'The :attribute must be between :min and :max digits.', - 'exists' => 'The :attribute must be a valid email address.', + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', 'distinct' => 'The :attribute field has a duplicate value.', - 'filled' => 'O formato de :attribute é inválido.', + 'filled' => 'The :attribute field is required.', 'image' => 'O :attribute deve ser uma imagem.', - 'in' => 'O :attribute deve ser uma imagem.', + 'in' => 'The selected :attribute is invalid.', 'in_array' => 'The :attribute field does not exist in :other.', - 'integer' => 'The selected :attribute is invalid.', - 'ip' => 'The :attribute must be an integer.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', 'json' => 'O :attribute tem que ser uma string JSON válida.', 'max' => [ - 'numeric' => 'The :attribute must be a valid IP address.', - 'file' => 'The :attribute may not be greater than :max.', - 'string' => 'The :attribute may not be greater than :max kilobytes.', + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', 'array' => 'A: atributo não pode ter mais de que :max itens.', ], - 'mimes' => 'A: atributo não pode ter mais de que :max itens.', + 'mimes' => 'The :attribute must be a file of type: :values.', 'min' => [ - 'numeric' => 'The :attribute must be a file of type: :values.', + 'numeric' => 'The :attribute must be at least :min.', 'file' => 'O :attribute deve ter pelo menos :min kilobytes.', - 'string' => 'O :attribute deve ter pelo menos :min kilobytes.', - 'array' => 'The :attribute must be at least :min characters.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', ], - 'not_in' => 'The :attribute must have at least :min items.', - 'numeric' => 'The selected :attribute is invalid.', + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', 'present' => 'The :attribute field must be present.', - 'regex' => 'The :attribute must be a number.', - 'required' => 'O formato de :attribute é inválido.', - 'required_if' => 'The :attribute field is required.', + 'regex' => 'O formato de :attribute é inválido.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', 'required_unless' => 'O campo :attribute é obrigatório a não ser que :other estiver em :values.', - 'required_with' => 'The :attribute field is required when :other is :value.', + 'required_with' => 'O campo :attribute é obrigatório quando :values está presente.', 'required_with_all' => 'O campo :attribute é obrigatório quando :values está presente.', - 'required_without' => 'O campo :attribute é obrigatório quando :values está presente.', - 'required_without_all' => 'The :attribute field is required when :values is not present.', - 'same' => 'The :attribute field is required when none of :values are present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', 'size' => [ - 'numeric' => 'The :attribute and :other must match.', + 'numeric' => 'The :attribute must be :size.', 'file' => 'O :attribute deve ter :size kilobytes.', 'string' => 'O :attribute deve ter :size caracteres.', - 'array' => 'O :attribute deve ter :size caracteres.', + 'array' => 'The :attribute must contain :size items.', ], - 'string' => 'The :attribute must contain :size items.', + 'string' => 'The :attribute must be a string.', 'timezone' => 'O :attribute deve ser uma zona válida.', 'unique' => 'O :attribute já existe.', 'url' => 'O formato de :attribute é inválido.', diff --git a/resources/lang/ro-RO/cachet.php b/resources/lang/ro-RO/cachet.php new file mode 100644 index 00000000000..52c20a09860 --- /dev/null +++ b/resources/lang/ro-RO/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Ultima actualizare :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operaţional', + 2 => 'Probleme de performanţă', + 3 => 'Ȋntrerupere parțială', + 4 => 'Ȋntrerupere gravă', + ], + 'group' => [ + 'other' => 'Alte Componente', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Nici un incident raportat', + 'past' => 'Incidente anterioare', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', programată: timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Sub investigație', + 2 => 'Identificat', + 3 => 'Sub observație', + 4 => 'Remediat', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerează cheia API', + 'revoke' => 'Revocă cheia API', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Ultima Oră', + 'hourly' => 'Ultimele 12 ore', + 'weekly' => 'Săptămână', + 'monthly' => 'Lună', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Abonează-te', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notificări', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'Acum eşti abonat la toate actualizările.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'Acum eşti abonat la următoarele actualizări.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Abonează-te la actualizări prin email.', + 'subscribed' => 'Te-ai abonat la actualizări prin email, te rugăm să îți verifici adresa email și să confirmi abonarea.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Abonarea prin email a fost confirmată. Mulțumim!', + 'manage' => 'Gestionează-ţi abonările', + 'unsubscribe' => 'Dezabonare de la actualizări prin email.', + 'unsubscribed' => 'Actualizările prin email au fost anulate.', + 'failure' => 'Ceva nu a funcționat în legătură cu abonarea.', + 'already-subscribed' => 'Adresa :email nu poate fi folosită deoarece este deja abonată.', + ], + ], + + 'signup' => [ + 'title' => 'Înregistrează-te', + 'username' => 'Utilizator', + 'email' => 'Email', + 'password' => 'Parolă', + 'success' => 'Contul tău a fost creat.', + 'failure' => 'Ceva a mers greșit cu procesul de înregistrare.', + ], + + 'system' => [ + 'update' => 'O nouă versiune a Cachet este disponibilă. Află cum să o actualizezi aici!', + ], + + // Modal + 'modal' => [ + 'close' => 'Închide', + 'subscribe' => [ + 'title' => 'Abonează-te la actualizările componentei', + 'body' => 'Introdu adresa ta de email pentru a te abona la actualizări pentru această componentă. Dacă ești deja abonat, vei primi deja emailuri pentru această componentă.', + 'button' => 'Abonează-te', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Fii la curent cu cele mai recente actualizări ale serviciilor pentru :app.', + ], + ], + + // Other + 'home' => 'Acasă', + 'powered_by' => 'Cu sprijinul Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'Despre acest Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Feed Stare', + +]; diff --git a/resources/lang/ro-RO/dashboard.php b/resources/lang/ro-RO/dashboard.php new file mode 100644 index 00000000000..d5506b97504 --- /dev/null +++ b/resources/lang/ro-RO/dashboard.php @@ -0,0 +1,304 @@ + 'Panou de control', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidente', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Crează şablon', + 'incident-templates' => 'Şabloane incident', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Raportează un incident', + 'success' => 'Incidentul a fost adăugat.', + 'failure' => 'A avut loc o eroare la adăugarea incidentului, vă rugăm să încercaţi din nou.', + ], + 'edit' => [ + 'title' => 'Editează un incident', + 'success' => 'Incidentul a fost actualizat.', + 'failure' => 'A avut loc o eroare la actualizarea incidentului, vă rugăm să încercaţi din nou.', + ], + 'delete' => [ + 'success' => 'Incidentul a fost şters şi nu va mai apărea pe pagina de status.', + 'failure' => 'Incidentul nu a putut fi şters, vă rugăm încercaţi din nou.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Şabloane incident', + 'add' => [ + 'title' => 'Adaugă un nou şablon pentru incident', + 'message' => 'Create your first incident template.', + 'success' => 'Noul şablon pentru incident a fost creat.', + 'failure' => 'Ceva nu a funcționat legat de șablonul incidentului.', + ], + 'edit' => [ + 'title' => 'Editare Şablon', + 'success' => 'Şablonul incidentului a fost actualizat.', + 'failure' => 'Ceva nu a funcționat legat de actualizarea șablonului incidentului', + ], + 'delete' => [ + 'success' => 'Şablonul incidentului a fost şters.', + 'failure' => 'Şablonul incidentului nu a putut fi şters, vă rugăm încercaţi din nou.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Programat la :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Componente', + 'component_statuses' => 'Stările Componentei', + 'listed_group' => 'Grupat ca :name', + 'add' => [ + 'title' => 'Adăugați o componentă', + 'message' => 'Ar trebui să adăugați o componentă.', + 'success' => 'Componenta a fost creată.', + 'failure' => 'Ceva nu a funcționat legat de grupul de componente, vă rugăm încercați din nou.', + ], + 'edit' => [ + 'title' => 'Modificați o componentă', + 'success' => 'Componenta a fost actualizată.', + 'failure' => 'Ceva nu a funcționat legat de grupul de componente, vă rugăm încercați din nou.', + ], + 'delete' => [ + 'success' => 'Componenta a fost ștearsă!', + 'failure' => 'Component nu a putut fi ștearsă, vă rugăm încercați din nou.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Group de componente|Grupuri de componente', + 'no_components' => 'Ar trebui să adăugați un grup de componente.', + 'add' => [ + 'title' => 'Adăugați un grup de componente', + 'success' => 'Grupul de componente a fost adăugat.', + 'failure' => 'Ceva nu a funcționat legat de grupul de componente, vă rugăm încercați din nou.', + ], + 'edit' => [ + 'title' => 'Modificați un grup de componente', + 'success' => 'Grupul de componente a fost actualizat.', + 'failure' => 'Ceva nu a funcționat legat de grupul de componente, vă rugăm încercați din nou.', + ], + 'delete' => [ + 'success' => 'Grupul de componente a fost șters!', + 'failure' => 'Grupul de componente nu a putut fi șters, vă rugăm încercați din nou.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Măsurători', + 'add' => [ + 'title' => 'Adaugă o măsurătoare', + 'message' => 'Ar trebui să adaugi o măsurătoare.', + 'success' => 'Măsurătoarea a fost creată.', + 'failure' => 'Ceva nu a funcționat legat de măsurătoare, vă rugăm încercați din nou.', + ], + 'edit' => [ + 'title' => 'Modificați o măsurătoare', + 'success' => 'Măsurătoarea a fost actualizată.', + 'failure' => 'Ceva nu a funcționat legat de măsurătoare, vă rugăm încercați din nou.', + ], + 'delete' => [ + 'success' => 'Măsurătoarea a fost ștearsă și nu va mai apărea pe pagina dvs. de stare.', + 'failure' => 'Măsurătoarea nu a putut fi ștearsă, vă rugăm încercați din nou.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Abonați', + 'description' => 'Abonații vor primi actualizări prin email când incidente noi sunt adăugate sau componentele sunt actualizate.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verificat', + 'not_verified' => 'Neverificat', + 'subscriber' => ':email, abonat la :date', + 'no_subscriptions' => 'Ați fost abonat la toate actualizările', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Adaugă un nou abonat', + 'success' => 'Abonatul a fost adăugat!', + 'failure' => 'Ceva nu a funcționat legat de adăugarea abonatului, vă rugăm încercați din nou.', + 'help' => 'Introduceți fiecare abonat pe o nouă linie.', + ], + 'edit' => [ + 'title' => 'Actualizează abonatul', + 'success' => 'Abonatul a fost actualizat!', + 'failure' => 'Ceva nu a funcționat legat de modificarea abonatului, vă rugăm încercați din nou.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Echipa', + 'member' => 'Membru', + 'profile' => 'Profil', + 'description' => 'Membrii echipei vor avea posibilitatea să adauge, modifice & actualiza componentele și incidentele.', + 'add' => [ + 'title' => 'Adaugă un nou membru la echipă', + 'success' => 'Un nou membru a fost adăugat la echipă.', + 'failure' => 'Un nou membru nu a putut fi adăugat la echipă, vă rugăm încercați din nou.', + ], + 'edit' => [ + 'title' => 'Actualizați profilul', + 'success' => 'Profilul a fost actualizat.', + 'failure' => 'Ceva nu a funcționat legat de actualizarea profilului, vă rugăm încercați din nou.', + ], + 'delete' => [ + 'success' => 'Membrul echipei a fost șters și nu va mai avea acces la panoul de control!', + 'failure' => 'Un nou membru nu a putut fi adăugat la echipă, vă rugăm încercați din nou.', + ], + 'invite' => [ + 'title' => 'Invită un nou membru în echipă', + 'success' => 'Invitația a fost trimisă', + 'failure' => 'Invitația nu a putut fi trimisă, vă rugăm încercați din nou.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Setări', + 'app-setup' => [ + 'app-setup' => 'Instalarea Aplicației', + 'images-only' => 'Puteți urca doar imagini.', + 'too-big' => 'Fișierul urcat este prea mare. Urcați o imagine mai mică de :size', + ], + 'analytics' => [ + 'analytics' => 'Analize', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localizare', + ], + 'customization' => [ + 'customization' => 'Personalizare', + 'header' => 'Header HTML Personalizat', + 'footer' => 'Footer HTML Personalizat', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Securitate', + 'two-factor' => 'Utilizatori care nu folosesc autentificare two-factor', + ], + 'stylesheet' => [ + 'stylesheet' => 'Listă de stiluri', + ], + 'theme' => [ + 'theme' => 'Tema', + ], + 'edit' => [ + 'success' => 'Setările au fost salvate.', + 'failure' => 'Setările nu au putut fi salvate.', + ], + 'credits' => [ + 'credits' => 'Autori', + 'contributors' => 'Contribuitori', + 'license' => 'Cachet este un proiect open source cu licență BSD-3, realizat de Alt Three Services Limited.', + 'backers-title' => 'Susținători & Sponsori', + 'backers' => 'Dacă vreți să susțineți dezvoltarea proiectului, vizitați pagina de campanie Cachet Patreon.', + 'thank-you' => 'Mulțumim tuturor celor :count contribuitori.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Autentificare', + 'logged_in' => 'Ești autentificat.', + 'welcome' => 'Bine ai revenit!', + 'two-factor' => 'Te rog introdu token-ul tău.', + ], + + // Sidebar footer + 'help' => 'Ajutor', + 'status_page' => 'Pagina de Stare', + 'logout' => 'Deconectează-te', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notificări', + 'awesome' => 'Minunat.', + 'whoops' => 'Hopa.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Susțineți Cachet', + 'support_subtitle' => 'Vizitați pagina noastră pe Patreon!', + 'news' => 'Ultimele Știri', + 'news_subtitle' => 'Obţineţi cea mai recentă actualizare', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Bun venit pe noua pagină de Stare!', + 'message' => 'Pagina de stare este aproape gata! S-ar putea să doriți să configurați aceste setări suplimentare', + 'close' => 'Du-mă direct la panoul de control', + 'steps' => [ + 'component' => 'Creează componente', + 'incident' => 'Creează incidente', + 'customize' => 'Personalizează', + 'team' => 'Adaugă utilizatori', + 'api' => 'Generează un token pentru API', + 'two-factor' => 'Autentificare Two Factor', + ], + ], + +]; diff --git a/resources/lang/ro-RO/forms.php b/resources/lang/ro-RO/forms.php new file mode 100644 index 00000000000..5f167eee6ba --- /dev/null +++ b/resources/lang/ro-RO/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Utilizator', + 'password' => 'Parolă', + 'site_name' => 'Numele site-ului', + 'site_domain' => 'Domeniu Site', + 'site_timezone' => 'Selectaţi fusul orar', + 'site_locale' => 'Selectaţi limba dumneavoastră', + 'enable_google2fa' => 'Activaţi Google Two Factor Authentication', + 'cache_driver' => 'Driver Cache', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Driver Sesiune', + 'mail_driver' => 'Driver Mail', + 'mail_host' => 'Gazdă Mail', + 'mail_address' => 'Adresa Email Expeditor', + 'mail_username' => 'Utilizator Mail', + 'mail_password' => 'Parolă Mail', + ], + + // Login form fields + 'login' => [ + 'login' => 'Utilizator sau Email', + 'email' => 'Email', + 'password' => 'Parolă', + '2fauth' => 'Cod de Autentificare', + 'invalid' => 'Utilizator sau parolă incorecte', + 'invalid-token' => 'Token incorect', + 'cookies' => 'Trebuie să activaţi cookies pentru a vă putea autentifica.', + 'rate-limit' => 'Limita de folosire a fost depăşită.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Nume', + 'status' => 'Stare', + 'component' => 'Componentă', + 'component_status' => 'Component Status', + 'message' => 'Mesaj', + 'message-help' => 'Puteţi utiliza şi Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notificaţi abonaţii?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Vizibilitatea Incidentului', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Vizibilă public', + 'logged_in_only' => 'Vizibilă numai pentru utilizatorii autentificaţi', + 'templates' => [ + 'name' => 'Nume', + 'template' => 'Șablon', + 'twig' => 'Şabloanele pentru incidente pot folosi limbajul Twig.', + ], + ], + + 'schedules' => [ + 'name' => 'Nume', + 'status' => 'Stare', + 'message' => 'Mesaj', + 'message-help' => 'Puteţi utiliza şi Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Nume', + 'template' => 'Șablon', + 'twig' => 'Şabloanele pentru incidente pot folosi limbajul Twig.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Nume', + 'status' => 'Stare', + 'group' => 'Grup', + 'description' => 'Descriere', + 'link' => 'Legătură', + 'tags' => 'Etichete', + 'tags-help' => 'Separate prin virgulă.', + 'enabled' => 'Componentă activată?', + + 'groups' => [ + 'name' => 'Nume', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Întotdeauna extins', + 'collapsed' => 'Restrânge grupul implicit', + 'collapsed_incident' => 'Restrânge grupul, dar extinde în cazul în care sunt probleme', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Nume', + 'description' => 'Descriere', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Grup', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Nume', + 'suffix' => 'Sufix', + 'description' => 'Descriere', + 'description-help' => 'Puteţi utiliza şi Markdown.', + 'display-chart' => 'Afişaţi graficul pe pagina de stare?', + 'default-value' => 'Valoare implicită', + 'calc_type' => 'Calculul măsurătorilor', + 'type_sum' => 'Sumă', + 'type_avg' => 'Medie', + 'places' => 'Zecimale', + 'default_view' => 'Opţiunea implicită', + 'threshold' => 'Ce interval de timp(în minute) doriţi între măsurători?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Valoarea', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Numele site-ului', + 'site-url' => 'URL-ul site-ului', + 'display-graphs' => 'Afişaţi grafice pe pagina stare?', + 'about-this-page' => 'Despre această pagină', + 'days-of-incidents' => 'Câte zile de incidente vreţi să fie afişate?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Imagine Banner', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Permiteţi vizitatorilor să se aboneze la notificări prin email?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Schimbaţi automat limba pentru pagina de stare în funcţie de limba vizitatorului?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Cod Google Analytics', + 'analytics_gosquared' => 'Cod GoSquared Analytics', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Id site Piwik', + ], + 'localization' => [ + 'site-timezone' => 'Fusul orar al site-ului', + 'site-locale' => 'Limba site-ului', + 'date-format' => 'Formatul datei', + 'incident-date-format' => 'Formatul de timp al incidentului', + ], + 'security' => [ + 'allowed-domains' => 'Domenii permise', + 'allowed-domains-help' => 'Separate prin virgulă. Domeniul configurat mai sus este automat permis implicit.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Personalizează Stilurile', + ], + 'theme' => [ + 'background-color' => 'Culoarea de fundal', + 'background-fills' => 'Gradient Fundal (componente, incidente, subsol)', + 'banner-background-color' => 'Culoarea de fundal pentru banner', + 'banner-padding' => 'Spaţiere banner', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Culoare Text', + 'dashboard-login' => 'Arătaţi butonul Dashboard în subsol?', + 'reds' => 'Roşu (utilizat pentru mesaje de eroare)', + 'blues' => 'Albastru (utilizat pentru mesaje de informare)', + 'greens' => 'Verde (folosit pentru mesaje de succes)', + 'yellows' => 'Galben (folosit pentru alerte)', + 'oranges' => 'Orange (folosit pentru mesaje de notificare)', + 'metrics' => 'Măsurători de umplere', + 'links' => 'Legături', + ], + ], + + 'user' => [ + 'username' => 'Utilizator', + 'email' => 'Email', + 'password' => 'Parolă', + 'api-token' => 'Token API', + 'api-token-help' => 'Regenerarea token-ului API va împiedica aplicaţiile existente să acceseze Cachet.', + 'gravatar' => 'Schimbaţi poza de profil pe Gravatar.', + 'user_level' => 'Nivel utilizator', + 'levels' => [ + 'admin' => 'Administator', + 'user' => 'Utilizator', + ], + '2fa' => [ + 'help' => 'Activând autentificarea two factor securitatea contului dvs. este mult îmbunătăţită. Trebuie să descărcaţi Google Authenticator sau o aplicaţie similară pe telefonul dvs. Când vă autentificaţi, vi se va cere token-ul generat de aplicaţie.', + ], + 'team' => [ + 'description' => 'Invităţi membrii echipei introducând aici adresele lor de email.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Adaugă', + 'save' => 'Salvează', + 'update' => 'Actualizează', + 'create' => 'Creează', + 'edit' => 'Modifică', + 'delete' => 'Şterge', + 'submit' => 'Trimite', + 'cancel' => 'Renunță', + 'remove' => 'Elimină', + 'invite' => 'Invită', + 'signup' => 'Înregistrează-te', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Opţional', +]; diff --git a/resources/lang/ro-RO/notifications.php b/resources/lang/ro-RO/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/ro-RO/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/ro-RO/pagination.php b/resources/lang/ro-RO/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/ro-RO/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/ro-RO/setup.php b/resources/lang/ro-RO/setup.php new file mode 100644 index 00000000000..73337a74326 --- /dev/null +++ b/resources/lang/ro-RO/setup.php @@ -0,0 +1,23 @@ + 'Instalare', + 'title' => 'Instalare Cachet', + 'service_details' => 'Detalii Serviciu', + 'env_setup' => 'Instalare Mediu', + 'status_page_setup' => 'Instalare Pagină de Status', + 'show_support' => 'Vrei să contribui la proiectul Cachet?', + 'admin_account' => 'Cont Administrator', + 'complete_setup' => 'Completaţi Instalarea', + 'completed' => 'Cachet a fost configurat cu succes!', + 'finish_setup' => 'Mergi la panoul de comenzi', +]; diff --git a/resources/lang/ro-RO/validation.php b/resources/lang/ro-RO/validation.php new file mode 100644 index 00000000000..d5082e01b06 --- /dev/null +++ b/resources/lang/ro-RO/validation.php @@ -0,0 +1,122 @@ + ':attribute trebuie să fie acceptat.', + 'active_url' => ':attribute nu este un URL valid.', + 'after' => ':attribute trebuie să fie o dată după :date.', + 'alpha' => ':attribute poate să conțină numai litere.', + 'alpha_dash' => ':attribute poate să conțină numai litere, cifre şi semne de punctuație.', + 'alpha_num' => ':attribute poate să conțină numai litere şi cifre.', + 'array' => ':attribute trebuie să fie o matrice.', + 'before' => ':attribute trebuie să fie o dată înainte de :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => ':attribute trebuie să aibă între :min şi :max elemente.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => ':attribute are o valoare duplicată.', + 'filled' => 'The :attribute field is required.', + 'image' => ':attribute trebuie să fie o imagine.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'Câmpul :attribute nu există în :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => ':attribute trebuie să fie un şir JSON valid.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => ':attribute nu poate avea mai mult de :max elemente.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => ':attribute trebuie să aibă cel puţin :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'Câmpul :attribute trebuie să fie prezent.', + 'regex' => 'Formatul :attribute nu este valid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'Câmpul :attribute este necesar dacă :other nu există în :values.', + 'required_with' => 'Câmpul :attribute este obligatoriu atunci când :values este prezent.', + 'required_with_all' => 'Câmpul :attribute este obligatoriu atunci când :values este prezent.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => ':attribute trebuie să aibă :size kilobytes.', + 'string' => ':attribute trebuie să aibă :size caractere.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => ':attribute trebuie să fie o zonă validă.', + 'unique' => ':attribute este deja folosit.', + 'url' => 'Formatul :attribute nu este valid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'mesaj-personalizat', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/ro/cachet.php b/resources/lang/ro/cachet.php index e0e01642dff..3b60a085ab0 100644 --- a/resources/lang/ro/cachet.php +++ b/resources/lang/ro/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/ro/dashboard.php b/resources/lang/ro/dashboard.php index 16e33d77512..59e4e59100b 100644 --- a/resources/lang/ro/dashboard.php +++ b/resources/lang/ro/dashboard.php @@ -11,47 +11,53 @@ return [ - 'dashboard' => 'Dashboard', + 'dashboard' => 'Panou de control', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', // Incidents 'incidents' => [ 'title' => 'Incidents & Schedule', - 'incidents' => 'Incidents', - 'logged' => '{0} There are no incidents, good work.|You have logged one incident.|You have reported :count incidents.', - 'incident-create-template' => 'Create Template', - 'incident-templates' => 'Incident Templates', + 'incidents' => 'Incidente', + 'logged' => '{0} Nu sunt incidente, bravo! | Ai adăugat un incident. | Ai raportat :count incidente.', + 'incident-create-template' => 'Crează şablon', + 'incident-templates' => 'Şabloane incident', + 'updates' => '{0} Nicio actualizare|O actualizare|:count Actualizări', 'add' => [ - 'title' => 'Report an incident', - 'success' => 'Incident added.', - 'failure' => 'There was an error adding the incident, please try again.', + 'title' => 'Raportează un incident', + 'success' => 'Incidentul a fost adăugat.', + 'failure' => 'A avut loc o eroare la adăugarea incidentului, vă rugăm să încercaţi din nou.', ], 'edit' => [ - 'title' => 'Edit an incident', - 'success' => 'Incident updated.', - 'failure' => 'There was an error editing the incident, please try again.', + 'title' => 'Editează un incident', + 'success' => 'Incidentul a fost actualizat.', + 'failure' => 'A avut loc o eroare la actualizarea incidentului, vă rugăm să încercaţi din nou.', ], 'delete' => [ - 'success' => 'The incident has been deleted and will not show on your status page.', - 'failure' => 'The incident could not be deleted, please try again.', + 'success' => 'Incidentul a fost şters şi nu va mai apărea pe pagina de status.', + 'failure' => 'Incidentul nu a putut fi şters, vă rugăm încercaţi din nou.', + ], + 'update' => [ + 'title' => 'Adaugă o nouă actualizare a incidentului', + 'subtitle' => 'Adaugă o actualizare la :incident', ], // Incident templates 'templates' => [ - 'title' => 'Incident Templates', + 'title' => 'Şabloane incident', 'add' => [ - 'title' => 'Create an incident template', - 'message' => 'You should add an incident template.', - 'success' => 'Your new incident template has been created.', - 'failure' => 'Something went wrong with the incident template.', + 'title' => 'Adaugă un nou şablon pentru incident', + 'message' => 'Trebuie să adaugi un şablon pentru incident.', + 'success' => 'Noul şablon pentru incident a fost creat.', + 'failure' => 'Ceva nu a funcționat legat de șablonul incidentului.', ], 'edit' => [ - 'title' => 'Edit Template', - 'success' => 'The incident template has been updated.', - 'failure' => 'Something went wrong updating the incident template', + 'title' => 'Editare Şablon', + 'success' => 'Şablonul incidentului a fost actualizat.', + 'failure' => 'Ceva nu a funcționat legat de actualizarea șablonului incidentului', ], 'delete' => [ - 'success' => 'The incident template has been deleted.', - 'failure' => 'The incident template could not be deleted, please try again.', + 'success' => 'Şablonul incidentului a fost şters.', + 'failure' => 'Şablonul incidentului nu a putut fi şters, vă rugăm încercaţi din nou.', ], ], ], @@ -59,216 +65,227 @@ // Incident Maintenance 'schedule' => [ 'schedule' => 'Întreținere programată', - 'logged' => '{0} There are no schedules, good work.|You have logged one schedule.|You have reported :count schedules.', - 'scheduled_at' => 'Scheduled at :timestamp', + 'logged' => '{0} Nu există programări, bravo.|Ai o singură programare.|Ai :count programări.', + 'scheduled_at' => 'Programat la :timestamp', 'add' => [ - 'title' => 'Add Scheduled Maintenance', - 'success' => 'Schedule added.', - 'failure' => 'Something went wrong adding the schedule, please try again.', + 'title' => 'Adăugaţi Programare Mentenanţă', + 'success' => 'Programare adăugată.', + 'failure' => 'Ceva nu a funcționat legat de adăugarea unei programări, vă rugăm încercați din nou.', ], 'edit' => [ - 'title' => 'Edit Scheduled Maintenance', - 'success' => 'Schedule has been updated!', - 'failure' => 'Something went wrong editing the schedule, please try again.', + 'title' => 'Modificați Programarea Mentenanței', + 'success' => 'Programarea a fost actualizată!', + 'failure' => 'Ceva nu a funcționat legat de modificarea programării, vă rugăm încercați din nou.', ], 'delete' => [ - 'success' => 'The scheduled maintenance has been deleted and will not show on your status page.', - 'failure' => 'The scheduled maintenance could not be deleted, please try again.', + 'success' => 'Programarea mentenanței a fost ștearsă și nu va mai apărea pe pagina dvs. de stare.', + 'failure' => 'Programarea mentenanței nu a putut fi ștearsă, vă rugăm încercați din nou.', ], ], // Components 'components' => [ - 'components' => 'Components', - 'component_statuses' => 'Component Statuses', - 'listed_group' => 'Grouped under :name', + 'components' => 'Componente', + 'component_statuses' => 'Stările Componentei', + 'listed_group' => 'Grupat ca :name', 'add' => [ - 'title' => 'Add a component', - 'message' => 'You should add a component.', - 'success' => 'Component created.', - 'failure' => 'Something went wrong with the component, please try again.', + 'title' => 'Adăugați o componentă', + 'message' => 'Ar trebui să adăugați o componentă.', + 'success' => 'Componenta a fost creată.', + 'failure' => 'Ceva nu a funcționat legat de grupul de componente, vă rugăm încercați din nou.', ], 'edit' => [ - 'title' => 'Edit a component', - 'success' => 'Component updated.', - 'failure' => 'Something went wrong with the component, please try again.', + 'title' => 'Modificați o componentă', + 'success' => 'Componenta a fost actualizată.', + 'failure' => 'Ceva nu a funcționat legat de grupul de componente, vă rugăm încercați din nou.', ], 'delete' => [ - 'success' => 'The component has been deleted!', - 'failure' => 'The component could not be deleted, please try again.', + 'success' => 'Componenta a fost ștearsă!', + 'failure' => 'Component nu a putut fi ștearsă, vă rugăm încercați din nou.', ], // Component groups 'groups' => [ - 'groups' => 'Component group|Component groups', - 'no_components' => 'You should add a component group.', + 'groups' => 'Group de componente|Grupuri de componente', + 'no_components' => 'Ar trebui să adăugați un grup de componente.', 'add' => [ - 'title' => 'Add a component group', - 'success' => 'Component group added.', - 'failure' => 'Something went wrong with the component group, please try again.', + 'title' => 'Adăugați un grup de componente', + 'success' => 'Grupul de componente a fost adăugat.', + 'failure' => 'Ceva nu a funcționat legat de grupul de componente, vă rugăm încercați din nou.', ], 'edit' => [ - 'title' => 'Edit a component group', - 'success' => 'Component group updated.', - 'failure' => 'Something went wrong with the component group, please try again.', + 'title' => 'Modificați un grup de componente', + 'success' => 'Grupul de componente a fost actualizat.', + 'failure' => 'Ceva nu a funcționat legat de grupul de componente, vă rugăm încercați din nou.', ], 'delete' => [ - 'success' => 'Component group has been deleted!', - 'failure' => 'The component group could not be deleted, please try again.', + 'success' => 'Grupul de componente a fost șters!', + 'failure' => 'Grupul de componente nu a putut fi șters, vă rugăm încercați din nou.', ], ], ], // Metrics 'metrics' => [ - 'metrics' => 'Metrics', + 'metrics' => 'Măsurători', 'add' => [ - 'title' => 'Create a metric', - 'message' => 'You should add a metric.', - 'success' => 'Metric created.', - 'failure' => 'Something went wrong with the metric, please try again.', + 'title' => 'Adaugă o măsurătoare', + 'message' => 'Ar trebui să adaugi o măsurătoare.', + 'success' => 'Măsurătoarea a fost creată.', + 'failure' => 'Ceva nu a funcționat legat de măsurătoare, vă rugăm încercați din nou.', ], 'edit' => [ - 'title' => 'Edit a metric', - 'success' => 'Metric updated.', - 'failure' => 'Something went wrong with the metric, please try again.', + 'title' => 'Modificați o măsurătoare', + 'success' => 'Măsurătoarea a fost actualizată.', + 'failure' => 'Ceva nu a funcționat legat de măsurătoare, vă rugăm încercați din nou.', ], 'delete' => [ - 'success' => 'The metric has been deleted and will no longer display on your status page.', - 'failure' => 'The metric could not be deleted, please try again.', + 'success' => 'Măsurătoarea a fost ștearsă și nu va mai apărea pe pagina dvs. de stare.', + 'failure' => 'Măsurătoarea nu a putut fi ștearsă, vă rugăm încercați din nou.', ], ], // Subscribers 'subscribers' => [ - 'subscribers' => 'Subscribers', - 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', - 'verified' => 'Verified', - 'not_verified' => 'Not verified', - 'subscriber' => ':email, subscribed :date', - 'no_subscriptions' => 'Subscribed to all updates', + 'subscribers' => 'Abonați', + 'description' => 'Abonații vor primi actualizări prin email când incidente noi sunt adăugate sau componentele sunt actualizate.', + 'verified' => 'Verificat', + 'not_verified' => 'Neverificat', + 'subscriber' => ':email, abonat la :date', + 'no_subscriptions' => 'Ați fost abonat la toate actualizările', 'add' => [ - 'title' => 'Add a new subscriber', - 'success' => 'Subscriber has been added!', - 'failure' => 'Something went wrong adding the subscriber, please try again.', - 'help' => 'Enter each subscriber on a new line.', + 'title' => 'Adaugă un nou abonat', + 'success' => 'Abonatul a fost adăugat!', + 'failure' => 'Ceva nu a funcționat legat de adăugarea abonatului, vă rugăm încercați din nou.', + 'help' => 'Introduceți fiecare abonat pe o nouă linie.', ], 'edit' => [ - 'title' => 'Update subscriber', - 'success' => 'Subscriber has been updated!', - 'failure' => 'Something went wrong editing the subscriber, please try again.', + 'title' => 'Actualizează abonatul', + 'success' => 'Abonatul a fost actualizat!', + 'failure' => 'Ceva nu a funcționat legat de modificarea abonatului, vă rugăm încercați din nou.', ], ], // Team 'team' => [ - 'team' => 'Team', - 'member' => 'Member', - 'profile' => 'Profile', + 'team' => 'Echipa', + 'member' => 'Membru', + 'profile' => 'Profil', 'description' => 'Team Members will be able to add, modify & edit components and incidents.', 'add' => [ - 'title' => 'Add a new team member', - 'success' => 'Team member added.', - 'failure' => 'The team member could not be added, please try again.', + 'title' => 'Adaugă un nou membru la echipă', + 'success' => 'Un nou membru a fost adăugat la echipă.', + 'failure' => 'Un nou membru nu a putut fi adăugat la echipă, vă rugăm încercați din nou.', ], 'edit' => [ - 'title' => 'Update profile', - 'success' => 'Profile updated.', - 'failure' => 'Something went wrong updating the profile, please try again.', + 'title' => 'Actualizați profilul', + 'success' => 'Profilul a fost actualizat.', + 'failure' => 'Ceva nu a funcționat legat de actualizarea profilului, vă rugăm încercați din nou.', ], 'delete' => [ - 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', - 'failure' => 'The team member could not be added, please try again.', + 'success' => 'Membrul echipei a fost șters și nu va mai avea acces la panoul de control!', + 'failure' => 'Un nou membru nu a putut fi adăugat la echipă, vă rugăm încercați din nou.', ], 'invite' => [ - 'title' => 'Invite a new team member', - 'success' => 'An invite has been sent', - 'failure' => 'The invite could not be sent, please try again.', + 'title' => 'Invită un nou membru în echipă', + 'success' => 'Invitația a fost trimisă', + 'failure' => 'Invitația nu a putut fi trimisă, vă rugăm încercați din nou.', ], ], // Settings 'settings' => [ - 'settings' => 'Settings', + 'settings' => 'Setări', 'app-setup' => [ - 'app-setup' => 'Application Setup', - 'images-only' => 'Only images may be uploaded.', - 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + 'app-setup' => 'Instalarea Aplicației', + 'images-only' => 'Puteți urca doar imagini.', + 'too-big' => 'Fișierul urcat este prea mare. Urcați o imagine mai mică de :size', ], 'analytics' => [ - 'analytics' => 'Analytics', + 'analytics' => 'Analize', + ], + 'log' => [ + 'log' => 'Jurnal', ], 'localization' => [ - 'localization' => 'Localization', + 'localization' => 'Localizare', ], 'customization' => [ - 'customization' => 'Customization', - 'header' => 'Custom Header HTML', - 'footer' => 'Custom Footer HTML', + 'customization' => 'Personalizare', + 'header' => 'Header HTML Personalizat', + 'footer' => 'Footer HTML Personalizat', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], ], 'security' => [ - 'security' => 'Security', - 'two-factor' => 'Users without two-factor authentication', + 'security' => 'Securitate', + 'two-factor' => 'Utilizatori care nu folosesc autentificare two-factor', ], 'stylesheet' => [ - 'stylesheet' => 'Stylesheet', + 'stylesheet' => 'Listă de stiluri', ], 'theme' => [ - 'theme' => 'Theme', + 'theme' => 'Tema', ], 'edit' => [ - 'success' => 'Settings saved.', - 'failure' => 'Settings could not be saved.', + 'success' => 'Setările au fost salvate.', + 'failure' => 'Setările nu au putut fi salvate.', ], 'credits' => [ - 'credits' => 'Credits', - 'contributors' => 'Contributors', - 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', - 'backers-title' => 'Backers & Sponsors', - 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', - 'thank-you' => 'Thank you to each and every one of the :count contributors.', + 'credits' => 'Autori', + 'contributors' => 'Contribuitori', + 'license' => 'Cachet este un proiect open source cu licență BSD-3, realizat de Alt Three Services Limited.', + 'backers-title' => 'Susținători & Sponsori', + 'backers' => 'Dacă vreți să susțineți dezvoltarea proiectului, vizitați pagina de campanie Cachet Patreon.', + 'thank-you' => 'Mulțumim tuturor celor :count contribuitori.', ], ], // Login 'login' => [ - 'login' => 'Login', - 'logged_in' => 'You\'re logged in.', - 'welcome' => 'Welcome Back!', - 'two-factor' => 'Please enter your token.', + 'login' => 'Autentificare', + 'logged_in' => 'Ești autentificat.', + 'welcome' => 'Bine ai revenit!', + 'two-factor' => 'Te rog introdu token-ul tău.', ], // Sidebar footer - 'help' => 'Help', - 'status_page' => 'Status Page', - 'logout' => 'Logout', + 'help' => 'Ajutor', + 'status_page' => 'Pagina de Stare', + 'logout' => 'Deconectează-te', // Notifications 'notifications' => [ - 'notifications' => 'Notifications', - 'awesome' => 'Awesome.', - 'whoops' => 'Whoops.', + 'notifications' => 'Notificări', + 'awesome' => 'Minunat.', + 'whoops' => 'Hopa.', ], // Widgets 'widgets' => [ - 'support' => 'Support Cachet', - 'support_subtitle' => 'Check out our Patreon page!', - 'news' => 'Latest News', - 'news_subtitle' => 'Get the latest updates', + 'support' => 'Susțineți Cachet', + 'support_subtitle' => 'Vizitați pagina noastră pe Patreon!', + 'news' => 'Ultimele Știri', + 'news_subtitle' => 'Obţineţi cea mai recentă actualizare', ], // Welcome modal 'welcome' => [ - 'welcome' => 'Welcome to your new status page!', - 'message' => 'Your status page is almost ready! You might want to configure these extra settings', - 'close' => 'Take me straight to my dashboard', + 'welcome' => 'Bun venit pe noua pagină de Stare!', + 'message' => 'Pagina de stare este aproape gata! S-ar putea să doriți să configurați aceste setări suplimentare', + 'close' => 'Du-mă direct la panoul de control', 'steps' => [ - 'component' => 'Create components', - 'incident' => 'Create incidents', - 'customize' => 'Customize', - 'team' => 'Add users', - 'api' => 'Generate API token', - 'two-factor' => 'Two Factor Authentication', + 'component' => 'Creează componente', + 'incident' => 'Creează incidente', + 'customize' => 'Personalizează', + 'team' => 'Adaugă utilizatori', + 'api' => 'Generează un token pentru API', + 'two-factor' => 'Autentificare Two Factor', ], ], diff --git a/resources/lang/ro/forms.php b/resources/lang/ro/forms.php index e706de8a2a2..360ec491d85 100644 --- a/resources/lang/ro/forms.php +++ b/resources/lang/ro/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Name', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/ru-RU/cachet.php b/resources/lang/ru-RU/cachet.php new file mode 100644 index 00000000000..08dcc52186b --- /dev/null +++ b/resources/lang/ru-RU/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Последнее обновление :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Работает', + 2 => 'Падение производительности', + 3 => 'Перебои в работе', + 4 => 'Значительные неполадки', + ], + 'group' => [ + 'other' => 'Другие компоненты', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'Без происшествий', + 'past' => 'Последние инциденты', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', запланированы :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Проводим анализ проблемы', + 2 => 'Причина определена', + 3 => 'Под наблюдением', + 4 => 'Исправлено', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Сгенерировать ключ API заново', + 'revoke' => 'Отозвать ключ API', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Последний час', + 'hourly' => 'Последние 12 часов', + 'weekly' => 'Неделя', + 'monthly' => 'Месяц', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Подписаться', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Уведомления', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'Вы подписаны на все изменения.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'Вы подписаны на следующие изменения.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Подписка на рассылку об изменениях.', + 'subscribed' => 'Вы подписались на рассылку email уведомлений. Проверьте вашу почту, чтобы подтвердить подписку.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Ваша подписка подтверждена. Спасибо!', + 'manage' => 'Управление подпиской', + 'unsubscribe' => 'Отписаться от рассылки.', + 'unsubscribed' => 'Ваша подписка отменена.', + 'failure' => 'Произошла ошибка при подписке на рассылку.', + 'already-subscribed' => 'Невозможно оформить подписку на :email, т.к. на него уже оформлена подписка.', + ], + ], + + 'signup' => [ + 'title' => 'Зарегистрироваться', + 'username' => 'Имя пользователя', + 'email' => 'Email', + 'password' => 'Пароль', + 'success' => 'Ваша учетная запись создана.', + 'failure' => 'Что-то пошло не так при регистрации.', + ], + + 'system' => [ + 'update' => 'Доступна новая версия Cachet. Инструкции по обновлению можно получить здесь!', + ], + + // Modal + 'modal' => [ + 'close' => 'Закрыть', + 'subscribe' => [ + 'title' => 'Подписка на изменения статуса компонента', + 'body' => 'Введите ваш email, чтобы подписаться на изменения статуса этого компонента. Если вы уже подписаны на обновления, значит сообщения об этом компоненте вам должны приходить.', + 'button' => 'Подписаться', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Будьте в курсе последних новостей о состоянии сервиса от :app.', + ], + ], + + // Other + 'home' => 'Главный экран', + 'powered_by' => 'Работает на Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'Об этом сайте', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Статусная лента', + +]; diff --git a/resources/lang/ru-RU/dashboard.php b/resources/lang/ru-RU/dashboard.php new file mode 100644 index 00000000000..0948919056a --- /dev/null +++ b/resources/lang/ru-RU/dashboard.php @@ -0,0 +1,304 @@ + 'Панель управления', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Инциденты', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Создать шаблон', + 'incident-templates' => 'Шаблоны инцидентов', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Добавить инцидент', + 'success' => 'Инцидент добавлен.', + 'failure' => 'При добавлении инцидента произошла ошибка, пожалуйста, попробуйте ещё раз.', + ], + 'edit' => [ + 'title' => 'Изменить инцидент', + 'success' => 'Инцидент обновлен.', + 'failure' => 'При редактировании инцидента произошла ошибка, пожалуйста, попробуйте ещё раз.', + ], + 'delete' => [ + 'success' => 'Инцидент удалён и больше не будет отображаться на статусной странице.', + 'failure' => 'Инцидент не может быть уделён, пожалуйста, попробуйте ещё раз.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Шаблоны инцидентов', + 'add' => [ + 'title' => 'Создать шаблон инцидента', + 'message' => 'Create your first incident template.', + 'success' => 'Новый шаблон инцидента создан.', + 'failure' => 'С шаблоном инцидента что-то не так.', + ], + 'edit' => [ + 'title' => 'Изменить шаблон', + 'success' => 'Шаблон инцидента обновлён.', + 'failure' => 'Что-то пошло не так при изменении шаблона инцидента', + ], + 'delete' => [ + 'success' => 'Шаблон инцидента удалён.', + 'failure' => 'Шаблон инцидента не может быть уделён, пожалуйста, попробуйте ещё раз.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Запланировано на :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Компоненты', + 'component_statuses' => ' Статусы компонентов', + 'listed_group' => 'В группе :name', + 'add' => [ + 'title' => 'Добавить компонент', + 'message' => 'Необходимо добавить компонент.', + 'success' => 'Компонент создан.', + 'failure' => 'Что-то не так с компонентом, пожалуйста, повторите ещё раз.', + ], + 'edit' => [ + 'title' => 'Изменить компонент', + 'success' => 'Компонент обновлён.', + 'failure' => 'Что-то не так с компонентом, пожалуйста, повторите ещё раз.', + ], + 'delete' => [ + 'success' => 'Компонент удалён!', + 'failure' => 'Компонент не может быть удалён, пожалуйста, повторите ещё раз.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Группа компонентов|Группы компонентов', + 'no_components' => 'Необходимо добавить группу компонентов.', + 'add' => [ + 'title' => 'Добавить группу компонентов', + 'success' => 'Группа компонентов добавлена.', + 'failure' => 'Что-то не так с компонентом, пожалуйста, повторите ещё раз.', + ], + 'edit' => [ + 'title' => 'Изменить группу компонентов', + 'success' => 'Группа компонентов обновлена.', + 'failure' => 'Что-то не так с компонентом, пожалуйста, повторите ещё раз.', + ], + 'delete' => [ + 'success' => 'Группа компонентов удалена!', + 'failure' => 'Группа компонентов не может быть удалена, пожалуйста, повторите ещё раз.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Метрики', + 'add' => [ + 'title' => 'Создать метрику', + 'message' => 'Необходимо добавить метрику.', + 'success' => 'Метрика создана.', + 'failure' => 'С метрикой что-то пошло не так, пожалуйста, повторите ещё раз.', + ], + 'edit' => [ + 'title' => 'Изменить метрику', + 'success' => 'Метрика обновлена.', + 'failure' => 'С метрикой что-то пошло не так, пожалуйста, повторите ещё раз.', + ], + 'delete' => [ + 'success' => 'Метрика удалена и больше не будет отображаться на статусной странице.', + 'failure' => 'Метрика не может быть удалена, пожалуйста, повторите ещё раз.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Подписчики', + 'description' => 'Подписчики будут получать уведомления по электронной почте при добавлении инцидентов или изменении статусов компонентов.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Подтверждён', + 'not_verified' => 'Не подтверждён', + 'subscriber' => ':email, подписан :date', + 'no_subscriptions' => 'Подписан на все обновления', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Добавить нового подписчика', + 'success' => 'Подписчик добавлен!', + 'failure' => 'Что-то пошло не так при добавлении подписчика, пожалуйста, повторите ещё раз.', + 'help' => 'Введите каждого подписчика с новой строки.', + ], + 'edit' => [ + 'title' => 'Обновить подписчика', + 'success' => 'Подписчик обновлён!', + 'failure' => 'Что-то пошло не так при изменении подписчика, пожалуйста, попробуйте ещё раз.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Команда', + 'member' => 'Участник', + 'profile' => 'Профиль', + 'description' => 'Участники команды смогут добавлять и изменять компоненты и инциденты.', + 'add' => [ + 'title' => 'Добавить нового участника команды', + 'success' => 'Участник команды добавлен.', + 'failure' => 'Участник команды не может быть добавлен, пожалуйста, повторите ещё раз.', + ], + 'edit' => [ + 'title' => 'Обновить профиль', + 'success' => 'Профиль обновлён.', + 'failure' => 'Что-то пошло не так при обновлении профиля, пожалуйста, повторите ещё раз.', + ], + 'delete' => [ + 'success' => 'Участник команды удалён и больше не сможет получить доступ к панели управления!', + 'failure' => 'Участник команды не может быть добавлен, пожалуйста, повторите ещё раз.', + ], + 'invite' => [ + 'title' => 'Пригласить нового участника команды', + 'success' => 'Приглашение отправлено', + 'failure' => 'Не получается отправить приглашение, пожалуйста, попробуйте ещё раз.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Настройки', + 'app-setup' => [ + 'app-setup' => 'Настройки приложения', + 'images-only' => 'Можно загружать только изображения.', + 'too-big' => 'Загруженный вами файл слишком большой. Загрузите картинку меньше чем :size', + ], + 'analytics' => [ + 'analytics' => 'Аналитика', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Региональные настройки', + ], + 'customization' => [ + 'customization' => 'Пользовательские настройки', + 'header' => 'Верхний колонтитул HTML', + 'footer' => 'Нижний колонтитул HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Безопасность', + 'two-factor' => 'Пользователи без двухфакторной аутентификации', + ], + 'stylesheet' => [ + 'stylesheet' => 'Таблица стилей', + ], + 'theme' => [ + 'theme' => 'Тема', + ], + 'edit' => [ + 'success' => 'Настройки сохранены.', + 'failure' => 'Не удаётся сохранить настройки.', + ], + 'credits' => [ + 'credits' => 'Разработчики', + 'contributors' => 'Контрибьюторы', + 'license' => 'Cachet - это проект с открытым исходным кодом по лицензии BSD-3, разрабатываемый компанией Alt Three Services Limited.', + 'backers-title' => 'Партнеры и спонсоры', + 'backers' => 'Если вы хотите поддержать будущую разработку, присоединяйтесь к сбору средств в Cachet Patreon.', + 'thank-you' => 'Спасибо всем нашим :count контрибьюторам.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Войти', + 'logged_in' => 'Вы вошли в систему.', + 'welcome' => 'С возвращением!', + 'two-factor' => 'Пожалуйста, введите ваш токен.', + ], + + // Sidebar footer + 'help' => 'Помощь', + 'status_page' => 'Статусная страница', + 'logout' => 'Выйти', + + // Notifications + 'notifications' => [ + 'notifications' => 'Уведомления', + 'awesome' => 'Отлично.', + 'whoops' => 'Ой-ой!', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Поддержать Cachet', + 'support_subtitle' => 'Посетите нашу страницу на Patreon!', + 'news' => 'Последние новости', + 'news_subtitle' => 'Проверить обновления', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Добро пожаловать на вашу статусную страницу!', + 'message' => 'Ваша статусная страница почти готова! Возможно, вы захотите настроить дополнительные параметры', + 'close' => 'Закрыть и перейти к панели управления', + 'steps' => [ + 'component' => 'Создание компонентов', + 'incident' => 'Создание инцидентов', + 'customize' => 'Настройка', + 'team' => 'Добавление пользователей', + 'api' => 'Создание API токена', + 'two-factor' => 'Двухфакторная аутентификация', + ], + ], + +]; diff --git a/resources/lang/ru-RU/forms.php b/resources/lang/ru-RU/forms.php new file mode 100644 index 00000000000..b80957cfd3f --- /dev/null +++ b/resources/lang/ru-RU/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Имя пользователя', + 'password' => 'Пароль', + 'site_name' => 'Название сайта', + 'site_domain' => 'Домен сайта', + 'site_timezone' => 'Часовой пояс', + 'site_locale' => 'Язык интерфейса', + 'enable_google2fa' => 'Включить двухфакторную аутентификацию Google', + 'cache_driver' => 'Хранилище кеша', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Хранилище сессий', + 'mail_driver' => 'Водитель почты', + 'mail_host' => 'Почтовый хост', + 'mail_address' => 'Почту с адреса', + 'mail_username' => 'Имя пользователя электронной почты', + 'mail_password' => 'Почтовый пароль', + ], + + // Login form fields + 'login' => [ + 'login' => 'Имя пользователя или Email', + 'email' => 'Email', + 'password' => 'Пароль', + '2fauth' => 'Код аутентификации', + 'invalid' => 'Неверное имя пользователя или пароль', + 'invalid-token' => 'Неверный токен', + 'cookies' => 'Необходимо включить cookies для входа.', + 'rate-limit' => 'Превышено ограничение скорости.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Название', + 'status' => 'Статус', + 'component' => 'Компонент', + 'component_status' => 'Component Status', + 'message' => 'Сообщение', + 'message-help' => 'Вы также можете использовать Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Уведомить подписчиков?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Отображение инцидента', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Доступен публично', + 'logged_in_only' => 'Показывать только авторизованным пользователям', + 'templates' => [ + 'name' => 'Название', + 'template' => 'Шаблон', + 'twig' => 'В шаблонах инцидентов можно использовать Twig.', + ], + ], + + 'schedules' => [ + 'name' => 'Название', + 'status' => 'Статус', + 'message' => 'Сообщение', + 'message-help' => 'Вы также можете использовать Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Название', + 'template' => 'Шаблон', + 'twig' => 'В шаблонах инцидентов можно использовать Twig.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Название', + 'status' => 'Статус', + 'group' => 'Группа', + 'description' => 'Описание', + 'link' => 'Ссылка', + 'tags' => 'Теги', + 'tags-help' => 'Разделяйте запятыми.', + 'enabled' => 'Компонент включен?', + + 'groups' => [ + 'name' => 'Название', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Всегда развернута', + 'collapsed' => 'Свернута по умолчанию', + 'collapsed_incident' => 'Свернута, но разворачивать, если есть проблема', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Название', + 'description' => 'Описание', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Группа', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Название', + 'suffix' => 'Суффикс', + 'description' => 'Описание', + 'description-help' => 'Вы также можете использовать Markdown.', + 'display-chart' => 'Отображать график на статусной странице?', + 'default-value' => 'Значение по умолчанию', + 'calc_type' => 'Расчет метрики', + 'type_sum' => 'Сумма', + 'type_avg' => 'Среднее значение', + 'places' => 'Количество цифр после точки', + 'default_view' => 'Представление по умолчанию', + 'threshold' => 'Количество минут между снятием метрик?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Значение', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Название сайта', + 'site-url' => 'URL сайта', + 'display-graphs' => 'Отображать графики на статусной странице?', + 'about-this-page' => 'Об этой странице', + 'days-of-incidents' => 'За сколько дней показывать инциденты?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Картинка-баннер', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Разрешить посетителям подписываться на email-уведомления?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Автоматически переводить вашу статусную страницу на язык посетителя?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Код Google Analytics', + 'analytics_gosquared' => 'Код GoSquared Analytics', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Идентификатор сайта в Piwik', + ], + 'localization' => [ + 'site-timezone' => 'Часовой пояс сайта', + 'site-locale' => 'Язык сайта', + 'date-format' => 'Формат даты', + 'incident-date-format' => 'Формат даты и времени для инцидента', + ], + 'security' => [ + 'allowed-domains' => 'Разрешённые домены', + 'allowed-domains-help' => 'Разделяйте запятыми. Домен, установленный в настройках, разрешен по умолчанию.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Код пользовательских стилей (CSS)', + ], + 'theme' => [ + 'background-color' => 'Цвет фона', + 'background-fills' => 'Заливка фона (компоненты, инциденты, «подвал»)', + 'banner-background-color' => 'Цвет фона для баннера', + 'banner-padding' => 'Отступы баннера', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Цвет текста', + 'dashboard-login' => 'Отображать кнопку панели управления в «подвале»?', + 'reds' => 'Красный (для ошибок)', + 'blues' => 'Синий (для информации)', + 'greens' => 'Зеленый (для сообщений о выполнении)', + 'yellows' => 'Желтый (для тревожных сообщений)', + 'oranges' => 'Оранжевый (для предупреждений)', + 'metrics' => 'Заливка метрик', + 'links' => 'Ссылки', + ], + ], + + 'user' => [ + 'username' => 'Имя пользователя', + 'email' => 'Email', + 'password' => 'Пароль', + 'api-token' => 'API токен', + 'api-token-help' => 'Обновление вашего API токена заблокирует существующим приложениям доступ в Cachet. Вам будет необходимо прописать в них новый токен.', + 'gravatar' => 'Изменить своё изображение на Gravatar.', + 'user_level' => 'Тип пользователя', + 'levels' => [ + 'admin' => 'Администратор', + 'user' => 'Пользователь', + ], + '2fa' => [ + 'help' => 'Включение двухфакторной аутентификации увеличивает безопасность вашей учетной записи. Вам понадобится скачать Google Authenticator или аналогичное приложение на свой смартфон. Для входа в панель управления, вам понадобится код, выданный этим приложением.', + ], + 'team' => [ + 'description' => 'Пригласите своих коллег введя их адреса электронной почты.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Добавить', + 'save' => 'Сохранить', + 'update' => 'Обновить', + 'create' => 'Создать', + 'edit' => 'Изменить', + 'delete' => 'Удалить', + 'submit' => 'Отправить', + 'cancel' => 'Отменить', + 'remove' => 'Удалить', + 'invite' => 'Пригласить', + 'signup' => 'Зарегистрироваться', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Необязательно', +]; diff --git a/resources/lang/ru-RU/notifications.php b/resources/lang/ru-RU/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/ru-RU/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/ru-RU/pagination.php b/resources/lang/ru-RU/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/ru-RU/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/ru-RU/setup.php b/resources/lang/ru-RU/setup.php new file mode 100644 index 00000000000..4a80ab49575 --- /dev/null +++ b/resources/lang/ru-RU/setup.php @@ -0,0 +1,23 @@ + 'Установка', + 'title' => 'Установка Cachet', + 'service_details' => 'Параметры сервиса', + 'env_setup' => 'Настройка окружения', + 'status_page_setup' => 'Настройки статусной страницы', + 'show_support' => 'Показывать, что статусная страница создана на Cachet?', + 'admin_account' => 'Учетная запись администратора', + 'complete_setup' => 'Завершить установку', + 'completed' => 'Вы успешно настроили Cachet!', + 'finish_setup' => 'Перейти в панель управления', +]; diff --git a/resources/lang/ru-RU/validation.php b/resources/lang/ru-RU/validation.php new file mode 100644 index 00000000000..851af2f8d4b --- /dev/null +++ b/resources/lang/ru-RU/validation.php @@ -0,0 +1,122 @@ + ':attribute должен быть принят.', + 'active_url' => ':attribute не является допустимым URL.', + 'after' => ':attribute должно быть датой после :date.', + 'alpha' => ':attribute может содержать только буквы.', + 'alpha_dash' => ':attribute может содержать только латинские буквы, цифры и дефис.', + 'alpha_num' => ':attribute может содержать только буквы и цифры.', + 'array' => ': attribute должно быть массивом.', + 'before' => ':attribute должно быть датой до :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => ':attribute должно содержать от :min до :max элементов.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'Поле :attribute содержит дублирующееся значение.', + 'filled' => 'The :attribute field is required.', + 'image' => ':attribute должно быть изображением.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'Поле :attribute не существует в :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => ':attribute должен быть в JSON формате.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => ':attribute не может содержать больше чем :max элементов.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => ':attribute должно быть не меньше :min килобайт.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'Поле :attribute должно быть заполнено.', + 'regex' => 'Неправильный формат :attribute.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'Поле :attribute обязательно, если :other не из :values.', + 'required_with' => 'Поле :attribute является обязательным, если все :values заполнены.', + 'required_with_all' => 'Поле :attribute является обязательным, если все :values заполнены.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => ':attribute должно быть объемом :size килобайт.', + 'string' => 'Поле :attribute должно содержать :size символов.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => ':attribute должно быть корректным часовым поясом.', + 'unique' => ':attribute уже занято.', + 'url' => 'Неправильный формат :attribute.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'настраиваемое сообщение', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/ru/cachet.php b/resources/lang/ru/cachet.php index d724a20af37..870cbc9552d 100644 --- a/resources/lang/ru/cachet.php +++ b/resources/lang/ru/cachet.php @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "Вас пригласили в команду управления статусной страницей :app_name, перейдите по следующей ссылке, чтобы зарегистрироваться.\n:link\nБлагодарим за внимание, :app_name", - 'html' => '

Вас пригласили в команду управления статусной страницей :app_name, перейдите по следующей ссылке, чтобы зарегистрироваться.

:link

Благодарим за внимание, :app_name

', + 'text' => "Вас пригласили в команду управления статусной страницей :app_name, перейдите по следующей ссылке, чтобы зарегистрироваться.\n:link\nБлагодарим за внимание, :app_name", + 'html' => '

Вас пригласили в команду управления статусной страницей :app_name, перейдите по следующей ссылке, чтобы зарегистрироваться.

:link

Благодарим за внимание, :app_name

', ], ], ], diff --git a/resources/lang/ru/dashboard.php b/resources/lang/ru/dashboard.php index 590acd4d785..44fd4adb4bd 100644 --- a/resources/lang/ru/dashboard.php +++ b/resources/lang/ru/dashboard.php @@ -11,15 +11,17 @@ return [ - 'dashboard' => 'Панель управления', + 'dashboard' => 'Панель управления', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', // Incidents 'incidents' => [ - 'title' => 'Инциденты и плановые работы', + 'title' => 'Incidents & Schedule', 'incidents' => 'Инциденты', 'logged' => '{0} Нет инцидентов, отличная работа!|У вас зарегистрирован :count инцидент.|У вас зарегистрировано :count инцидента.|У вас зарегистрировано :count инцидентов.', 'incident-create-template' => 'Создать шаблон', 'incident-templates' => 'Шаблоны инцидентов', + 'updates' => '{0} Zero Updates|One Update|:count Updates', 'add' => [ 'title' => 'Добавить инцидент', 'success' => 'Инцидент добавлен.', @@ -34,6 +36,10 @@ 'success' => 'Инцидент удалён и больше не будет отображаться на статусной странице.', 'failure' => 'Инцидент не может быть уделён, пожалуйста, попробуйте ещё раз.', ], + 'update' => [ + 'title' => 'Create new incident update', + 'subtitle' => 'Добавить обновление к :incident', + ], // Incident templates 'templates' => [ @@ -105,12 +111,12 @@ 'add' => [ 'title' => 'Добавить группу компонентов', 'success' => 'Группа компонентов добавлена.', - 'failure' => 'Что-то не так с группой компонентов, пожалуйста, повторите ещё раз.', + 'failure' => 'Что-то не так с компонентом, пожалуйста, повторите ещё раз.', ], 'edit' => [ 'title' => 'Изменить группу компонентов', 'success' => 'Группа компонентов обновлена.', - 'failure' => 'Что-то не так с группой компонентов, пожалуйста, повторите ещё раз.', + 'failure' => 'Что-то не так с компонентом, пожалуйста, повторите ещё раз.', ], 'delete' => [ 'success' => 'Группа компонентов удалена!', @@ -150,7 +156,7 @@ 'title' => 'Добавить нового подписчика', 'success' => 'Подписчик добавлен!', 'failure' => 'Что-то пошло не так при добавлении подписчика, пожалуйста, повторите ещё раз.', - 'help' => 'Enter each subscriber on a new line.', + 'help' => 'Введите каждого подписчика с новой строки.', ], 'edit' => [ 'title' => 'Обновить подписчика', @@ -164,7 +170,7 @@ 'team' => 'Команда', 'member' => 'Участник', 'profile' => 'Профиль', - 'description' => 'Участники команды смогут добавлять и изменять компоненты и инциденты.', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', 'add' => [ 'title' => 'Добавить нового участника команды', 'success' => 'Участник команды добавлен.', @@ -197,6 +203,9 @@ 'analytics' => [ 'analytics' => 'Аналитика', ], + 'log' => [ + 'log' => 'Журнал', + ], 'localization' => [ 'localization' => 'Региональные настройки', ], @@ -205,6 +214,14 @@ 'header' => 'Верхний колонтитул HTML', 'footer' => 'Нижний колонтитул HTML', ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], 'security' => [ 'security' => 'Безопасность', 'two-factor' => 'Пользователи без двухфакторной аутентификации', @@ -221,11 +238,11 @@ ], 'credits' => [ 'credits' => 'Разработчики', - 'contributors' => 'Разработчики', - 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', - 'backers-title' => 'Партнеры & спонсоры', - 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', - 'thank-you' => 'Thank you to each and every one of the :count contributors.', + 'contributors' => 'Контрибьюторы', + 'license' => 'Cachet - это проект с открытым исходным кодом по лицензии BSD-3, разрабатываемый компанией Alt Three Services Limited.', + 'backers-title' => 'Партнеры и спонсоры', + 'backers' => 'Если вы хотите поддержать будущую разработку, присоединяйтесь к сбору средств в Cachet Patreon.', + 'thank-you' => 'Спасибо всем нашим :count контрибьюторам.', ], ], @@ -252,7 +269,7 @@ // Widgets 'widgets' => [ 'support' => 'Поддержать Cachet', - 'support_subtitle' => 'Check out our Patreon page!', + 'support_subtitle' => 'Посетите нашу страницу на Patreon!', 'news' => 'Последние новости', 'news_subtitle' => 'Проверить обновления', ], diff --git a/resources/lang/ru/forms.php b/resources/lang/ru/forms.php index 4b49c2d6bea..148f28458e3 100644 --- a/resources/lang/ru/forms.php +++ b/resources/lang/ru/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Название', 'template' => 'Шаблон', - 'twig' => 'В шаблонах инцидентов можно использовать Twig.', + 'twig' => 'В шаблонах инцидентов можно использовать Twig.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Идентификатор сайта в Piwik', ], 'localization' => [ - 'site-timezone' => 'Часовой пояс сайта', - 'site-locale' => 'Язык сайта', - 'date-format' => 'Формат даты', - 'incident-date-format' => 'Формат даты и времени для инцидента', + 'site-timezone' => 'Часовой пояс сайта', + 'site-locale' => 'Язык сайта', + 'date-format' => 'Формат даты', + 'incident-date-format' => 'Формат даты и времени для инцидента', ], 'security' => [ 'allowed-domains' => 'Разрешённые домены', diff --git a/resources/lang/sl-SI/cachet.php b/resources/lang/sl-SI/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/sl-SI/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/sl-SI/dashboard.php b/resources/lang/sl-SI/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/sl-SI/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/sl-SI/forms.php b/resources/lang/sl-SI/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/sl-SI/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/sl-SI/notifications.php b/resources/lang/sl-SI/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/sl-SI/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/sl-SI/pagination.php b/resources/lang/sl-SI/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/sl-SI/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/sl-SI/setup.php b/resources/lang/sl-SI/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/sl-SI/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/sl-SI/validation.php b/resources/lang/sl-SI/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/sl-SI/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/sq-AL/cachet.php b/resources/lang/sq-AL/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/sq-AL/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/sq-AL/dashboard.php b/resources/lang/sq-AL/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/sq-AL/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/sq-AL/forms.php b/resources/lang/sq-AL/forms.php new file mode 100644 index 00000000000..2cd3fff48be --- /dev/null +++ b/resources/lang/sq-AL/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => ' Përditëso', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/sq-AL/notifications.php b/resources/lang/sq-AL/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/sq-AL/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/sq-AL/pagination.php b/resources/lang/sq-AL/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/sq-AL/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/sq-AL/setup.php b/resources/lang/sq-AL/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/sq-AL/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/sq-AL/validation.php b/resources/lang/sq-AL/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/sq-AL/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/sq/cachet.php b/resources/lang/sq/cachet.php index 79080207c14..ad61104fd9f 100644 --- a/resources/lang/sq/cachet.php +++ b/resources/lang/sq/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/sq/forms.php b/resources/lang/sq/forms.php index 3149b3fc810..6e184e60064 100644 --- a/resources/lang/sq/forms.php +++ b/resources/lang/sq/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Emri', 'template' => 'Paraqitja', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/sr/cachet.php b/resources/lang/sr/cachet.php index f8a1cd83bae..0e018fef925 100644 --- a/resources/lang/sr/cachet.php +++ b/resources/lang/sr/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/sr/forms.php b/resources/lang/sr/forms.php index e706de8a2a2..360ec491d85 100644 --- a/resources/lang/sr/forms.php +++ b/resources/lang/sr/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Name', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/sv-SE/cachet.php b/resources/lang/sv-SE/cachet.php index dfa682c3f42..319cdda9b48 100644 --- a/resources/lang/sv-SE/cachet.php +++ b/resources/lang/sv-SE/cachet.php @@ -12,28 +12,31 @@ return [ // Components 'components' => [ - 'last_updated' => 'Last updated :timestamp', + 'last_updated' => 'Senast uppdaterad :timestamp', 'status' => [ + 0 => 'Unknown', 1 => 'Fungerar', 2 => 'Prestandaproblem', 3 => 'Mindre avbrott', 4 => 'Större avbrott', ], 'group' => [ - 'other' => 'Other Components', + 'other' => 'Andra komponenter', ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', ], // Incidents 'incidents' => [ - 'none' => 'Inga händelser har rapporterats', - 'past' => 'Tidigare händelser', - 'previous_week' => 'Förra veckan', - 'next_week' => 'Nästa vecka', - 'scheduled' => 'Planerat underhåll', - 'scheduled_at' => ', schemalagda: tidsstämpel', - 'status' => [ - 0 => 'Schemalagd', // TODO: Hopefully remove this. + 'none' => 'Inga händelser har rapporterats', + 'past' => 'Tidigare händelser', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Planerat underhåll', + 'scheduled_at' => ', schemalagda: tidsstämpel', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ 1 => 'Undersöker', 2 => 'Identifierat', 3 => 'Bevakar', @@ -41,11 +44,20 @@ ], ], + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + // Service Status 'service' => [ - 'good' => '[0,1] Systemet fungerar |[2,Inf] Alla system fungerar', - 'bad' => '[0,1] Systemet har för närvarande problem|[2,Inf] Vissa system har problem', - 'major' => '[0,1] Stora störningar på tjänsten [2,Inf] Stora störningar på vissa system', + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', ], 'api' => [ @@ -65,47 +77,29 @@ // Subscriber 'subscriber' => [ - 'subscribe' => 'Prenumerera för att få de senaste uppdateringarna', - 'button' => 'Prenumerera', - 'manage' => [ - 'no_subscriptions' => 'You\'re currently subscribed to all updates.', - 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Prenumerera', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifieringar', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'Du prenumererar på alla uppdateringar.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'Du prenumererar på följande uppdateringar.', + 'manage_at_link' => 'Manage your subscriptions at :link', ], 'email' => [ - 'subscribe' => 'Prenumerera på epost-uppdateringar.', - 'subscribed' => 'Du har börjat prenumerera på e-postmeddelanden, vänligen kontrollera din e-post för att bekräfta din prenumeration.', - 'verified' => 'Din epost-prenumeration har bekräftats. Tack!', - 'manage' => 'Manage your subscription', - 'unsubscribe' => 'Avbeställ epost-uppdateringar.', - 'unsubscribed' => 'Din epost-prenumeration har avbrutits.', - 'failure' => 'Något blev fel med prenumerationen.', - 'already-subscribed' => 'Kan inte skapa en prenumeration för :email eftersom den redan prenumererar.', - 'verify' => [ - 'text' => "Please confirm your email subscription to :app_name status updates.\n:link", - 'html' => '

Please confirm your email subscription to :app_name status updates.

', - 'button' => 'Confirm Subscription', - ], - 'maintenance' => [ - 'subject' => '[Maintenance Scheduled] :name', - ], - 'incident' => [ - 'subject' => '[New Incident] :status: :name', - ], - 'component' => [ - 'subject' => 'Komponentstatusuppdatering', - 'text' => 'Komponenten :component_name har fått en ny status. Komponenten har nu status :component_human_status.\nTack, :app_name', - 'html' => '

Komponenten :component_name har fått en ny status. Komponenten har nu status :component_human_status.

Tack, :app_name

', - 'tooltip-title' => 'Prenumerera på uppdateringar för :component_name.', - ], - ], - ], - - 'users' => [ - 'email' => [ - 'invite' => [ - 'text' => "Du har blivit inbjuden till teamet för :app_names statussida, registrera dig genom att trycka på länken.\n:link\nTack, :app_name", - 'html' => '

Du har blivit inbjuden till teamet :app_names statussida. Registrera dig genom att trycka på den här länken

Tack, :app_name

', - ], + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Prenumerera på epost-uppdateringar.', + 'subscribed' => 'Du har börjat prenumerera på e-postmeddelanden, vänligen kontrollera din e-post för att bekräfta din prenumeration.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Din epost-prenumeration har bekräftats. Tack!', + 'manage' => 'Hantera din prenumeration', + 'unsubscribe' => 'Avbeställ epost-uppdateringar.', + 'unsubscribed' => 'Din epost-prenumeration har avbrutits.', + 'failure' => 'Något blev fel med prenumerationen.', + 'already-subscribed' => 'Kan inte skapa en prenumeration för :email eftersom den redan prenumererar.', ], ], @@ -132,10 +126,20 @@ ], ], + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Håll dig uppdaterad med de senaste uppdateringarna från :app.', + ], + ], + // Other - 'home' => 'Home', - 'description' => 'Stay up to date with the latest service updates from :app.', - 'powered_by' => 'Powered by Cachet.', + 'home' => 'Hem', + 'powered_by' => 'Drivs av Cachet.', + 'timezone' => 'Times are shown in :timezone.', 'about_this_site' => 'Om sidan', 'rss-feed' => 'RSS', 'atom-feed' => 'Atom', diff --git a/resources/lang/sv-SE/dashboard.php b/resources/lang/sv-SE/dashboard.php index dc563901273..49427ace143 100644 --- a/resources/lang/sv-SE/dashboard.php +++ b/resources/lang/sv-SE/dashboard.php @@ -11,15 +11,31 @@ return [ - 'dashboard' => 'Översiktspanel', + 'dashboard' => 'Översiktspanel', + 'writeable_settings' => 'Cachets inställningskatalog är inte skrivbar. Kontrollera att ./bootstrap/cachet är skrivbar av webbservern.', // Incidents 'incidents' => [ - 'title' => 'Händelser & Schema', + 'title' => 'Incidents & Maintenance', 'incidents' => 'Händelser', - 'logged' => '{0} Det finns inga händelser, bra jobbat!|Du har skapat en händelse.|Du har skapat :count händelser.', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', 'incident-create-template' => 'Skapa mall', 'incident-templates' => 'Händelsemallar', + 'updates' => [ + 'title' => 'Uppdateringar för :incident', + 'count' => '{0}Inga uppdateringar|[1]En uppdatering|[2]Två uppdateringar|[3,*]Flera uppdateringar', + 'add' => [ + 'title' => 'Skapa en ny incidentuppdatering', + 'success' => 'Din nya incidentuppdatering har skapats.', + 'failure' => 'Något gick fel under uppdatering av incidenten.', + ], + 'edit' => [ + 'title' => 'Redigera incidentuppdatering', + 'success' => 'Incidentuppdateringen har uppdaterats.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', 'add' => [ 'title' => 'Lägg till händelse', 'success' => 'Incident added.', @@ -40,7 +56,7 @@ 'title' => 'Händelsemallar', 'add' => [ 'title' => 'Skapa en händelsemall', - 'message' => 'Du borde lägga till en händelsemall.', + 'message' => 'Create your first incident template.', 'success' => 'Your new incident template has been created.', 'failure' => 'Something went wrong with the incident template.', ], @@ -59,21 +75,21 @@ // Incident Maintenance 'schedule' => [ 'schedule' => 'Planerat underhåll', - 'logged' => '{0} Det finns inget schemalagt, bra jobbat!|Du har skapat ett schemalagt underhåll.|Du har skapat :count schemalagda underhåll.', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', 'scheduled_at' => 'Schemalagd till: tidsstämpel', 'add' => [ - 'title' => 'Add Scheduled Maintenance', - 'success' => 'Schedule added.', - 'failure' => 'Something went wrong adding the schedule, please try again.', + 'title' => 'Lägg till planerat underhåll', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', ], 'edit' => [ - 'title' => 'Edit Scheduled Maintenance', - 'success' => 'Schedule has been updated!', - 'failure' => 'Something went wrong editing the schedule, please try again.', + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', ], 'delete' => [ - 'success' => 'The scheduled maintenance has been deleted and will not show on your status page.', - 'failure' => 'The scheduled maintenance could not be deleted, please try again.', + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', ], ], @@ -86,12 +102,12 @@ 'title' => 'Lägg till en komponent', 'message' => 'Du borde lägga till en komponent.', 'success' => 'Component created.', - 'failure' => 'Something went wrong with the component, please try again.', + 'failure' => 'Something went wrong with the component group, please try again.', ], 'edit' => [ 'title' => 'Redigera komponent', 'success' => 'Component updated.', - 'failure' => 'Something went wrong with the component, please try again.', + 'failure' => 'Something went wrong with the component group, please try again.', ], 'delete' => [ 'success' => 'Komponenten har tagits bort!', @@ -140,13 +156,15 @@ ], // Subscribers 'subscribers' => [ - 'subscribers' => 'Prenumeranter', - 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', - 'verified' => 'Bekräftad', - 'not_verified' => 'Inte bekräftad', - 'subscriber' => ':email, subscribed :date', - 'no_subscriptions' => 'Subscribed to all updates', - 'add' => [ + 'subscribers' => 'Prenumeranter', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Bekräftad', + 'not_verified' => 'Inte bekräftad', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ 'title' => 'Lägg till en prenumerant', 'success' => 'Prenumerant tillagd!', 'failure' => 'Something went wrong adding the subscriber, please try again.', @@ -197,6 +215,9 @@ 'analytics' => [ 'analytics' => 'Analys', ], + 'log' => [ + 'log' => 'Log', + ], 'localization' => [ 'localization' => 'Platsanpassning', ], @@ -205,6 +226,14 @@ 'header' => 'Custom Header HTML', 'footer' => 'Custom Footer HTML', ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], 'security' => [ 'security' => 'Säkerhet', 'two-factor' => 'Användare utan tvåfaktorsautentisering', @@ -254,14 +283,14 @@ 'support' => 'Support Cachet', 'support_subtitle' => 'Check out our Patreon page!', 'news' => 'Latest News', - 'news_subtitle' => 'Get the latest updates', + 'news_subtitle' => 'Get the latest update', ], // Welcome modal 'welcome' => [ 'welcome' => 'Välkommen till din statussida!', 'message' => 'Din statussida är nästan redo. Du kan vilja konfigerara de här extra inställningarna', - 'close' => 'Take me straight to my dashboard', + 'close' => 'I\'m good thanks!', 'steps' => [ 'component' => 'Skapa komponenter', 'incident' => 'Skapa händelser', diff --git a/resources/lang/sv-SE/forms.php b/resources/lang/sv-SE/forms.php index 56dd1579c41..1c6f0a15c84 100644 --- a/resources/lang/sv-SE/forms.php +++ b/resources/lang/sv-SE/forms.php @@ -22,7 +22,13 @@ 'site_locale' => 'Välj ditt språk', 'enable_google2fa' => 'Aktivera Google tvåfaktorsautentisering', 'cache_driver' => 'Cachedrivrutin', + 'queue_driver' => 'Queue Driver', 'session_driver' => 'Sessionsdrivrutin', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', ], // Login form fields @@ -35,6 +41,7 @@ 'invalid-token' => 'Ogiltig nyckel', 'cookies' => 'Du måste aktivera cookies för att kunna logga in.', 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', ], // Incidents form fields @@ -42,18 +49,36 @@ 'name' => 'Namn', 'status' => 'Status', 'component' => 'Komponent', + 'component_status' => 'Component Status', 'message' => 'Meddelande', 'message-help' => 'Du kan även använda Markdown.', - 'scheduled_at' => 'När vill du schemalägga underhållet?', - 'incident_time' => 'När inträffade händelsen?', + 'occurred_at' => 'When did this incident occur?', 'notify_subscribers' => 'Meddela prenumeranter?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', 'public' => 'Kan ses av allmänheten', 'logged_in_only' => 'Endast synlig för inloggade användare', 'templates' => [ 'name' => 'Namn', 'template' => 'Mall', - 'twig' => 'Händelsmallar kan använda Twig-mallspråk.', + 'twig' => 'Händelsmallar kan använda Twig-mallspråk.', + ], + ], + + 'schedules' => [ + 'name' => 'Namn', + 'status' => 'Status', + 'message' => 'Meddelande', + 'message-help' => 'Du kan även använda Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Namn', + 'template' => 'Mall', + 'twig' => 'Händelsmallar kan använda Twig-mallspråk.', ], ], @@ -69,28 +94,50 @@ 'enabled' => 'Komponent aktiverad?', 'groups' => [ - 'name' => 'Namn', - 'collapsing' => 'Choose visibility of the group', - 'visible' => 'Always expanded', - 'collapsed' => 'Collapse the group by default', - 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'name' => 'Namn', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Namn', + 'description' => 'Beskrivning', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Grupp', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', ], ], // Metric form fields 'metrics' => [ - 'name' => 'Namn', - 'suffix' => 'Suffix', - 'description' => 'Beskrivning', - 'description-help' => 'Du kan även använda Markdown.', - 'display-chart' => 'Visa diagram på statussidan?', - 'default-value' => 'Standardvärde', - 'calc_type' => 'Beräkning av mätetal', - 'type_sum' => 'Summa', - 'type_avg' => 'Medelvärde', - 'places' => 'Decimalplatser', - 'default_view' => 'Standardvy', - 'threshold' => 'How many minutes of threshold between metric points?', + 'name' => 'Namn', + 'suffix' => 'Suffix', + 'description' => 'Beskrivning', + 'description-help' => 'Du kan även använda Markdown.', + 'display-chart' => 'Visa diagram på statussidan?', + 'default-value' => 'Standardvärde', + 'calc_type' => 'Beräkning av mätetal', + 'type_sum' => 'Summa', + 'type_avg' => 'Medelvärde', + 'places' => 'Decimalplatser', + 'default_view' => 'Standardvy', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', 'points' => [ 'value' => 'Värde', @@ -99,44 +146,53 @@ // Settings 'settings' => [ - /// Application setup + // Application setup 'app-setup' => [ - 'site-name' => 'Webbplatsens namn', - 'site-url' => 'Webbplatsens URL', - 'display-graphs' => 'Visa grafer på statussidan?', - 'about-this-page' => 'Om den här sidan', - 'days-of-incidents' => 'Hur många dagar av händelser ska visas?', - 'banner' => 'Banner Image', - 'banner-help' => 'Vi rekommenderar att du inte laddar upp bilder som är bredare än 930 px.', - 'subscribers' => 'Tillåt att registrera sig för notifikationer via e-post?', - 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'site-name' => 'Webbplatsens namn', + 'site-url' => 'Webbplatsens URL', + 'display-graphs' => 'Visa grafer på statussidan?', + 'about-this-page' => 'Om den här sidan', + 'days-of-incidents' => 'Hur många dagar av händelser ska visas?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Tillåt att registrera sig för notifikationer via e-post?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', ], 'analytics' => [ 'analytics_google' => 'Google Analytics-kod', 'analytics_gosquared' => 'GoSquared Analytics-code', - 'analytics_piwik_url' => 'URL till din Piwik-instans (utan http(s)://)', + 'analytics_piwik_url' => 'URL of your Piwik instance', 'analytics_piwik_siteid' => 'Piwik\'s sajt-id', ], 'localization' => [ - 'site-timezone' => 'Webbplatsens tidszon', - 'site-locale' => 'Webbplatsspråk', - 'date-format' => 'Datumformat', - 'incident-date-format' => 'Händelsens tidsstämpelformat', + 'site-timezone' => 'Webbplatsens tidszon', + 'site-locale' => 'Webbplatsspråk', + 'date-format' => 'Datumformat', + 'incident-date-format' => 'Händelsens tidsstämpelformat', ], 'security' => [ - 'allowed-domains' => 'Tillåtna domäner', - 'allowed-domains-help' => 'Kommaseparerad. Domänerna ovan tillåts automatiskt som standard.', + 'allowed-domains' => 'Tillåtna domäner', + 'allowed-domains-help' => 'Kommaseparerad. Domänerna ovan tillåts automatiskt som standard.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', ], 'stylesheet' => [ 'custom-css' => 'Custom Stylesheet', ], 'theme' => [ - 'background-color' => 'Background Color', + 'background-color' => 'Background color', 'background-fills' => 'Bakgrundsfärg (komponenter, händelser, sidfot)', 'banner-background-color' => 'Bakgrundsfärg för banner', 'banner-padding' => 'Bannerutfyllnad', - 'fullwidth-banner' => 'Aktivera fullbreddsbanner?', - 'text-color' => 'Text Color', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', 'dashboard-login' => 'Visa länk till översiktspanelen i sidfoten?', 'reds' => 'Röd (används för fel)', 'blues' => 'Blå (används för information)', @@ -165,22 +221,32 @@ ], 'team' => [ 'description' => 'Bjud in dina teammedlemmar genom att fylla i deras epostadresser här.', - 'email' => 'Epostadress #:id', + 'email' => 'Your Team Members Email Address', ], ], + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + // Buttons - 'add' => 'Lägg till', - 'save' => 'Spara', - 'update' => 'Uppdatera', - 'create' => 'Skapa', - 'edit' => 'Redigera', - 'delete' => 'Radera', - 'submit' => 'Skicka', - 'cancel' => 'Avbryt', - 'remove' => 'Ta bort', - 'invite' => 'Bjud In', - 'signup' => 'Registrera dig', + 'add' => 'Lägg till', + 'save' => 'Spara', + 'update' => 'Uppdatera', + 'create' => 'Skapa', + 'edit' => 'Redigera', + 'delete' => 'Radera', + 'submit' => 'Skicka', + 'cancel' => 'Avbryt', + 'remove' => 'Ta bort', + 'invite' => 'Bjud In', + 'signup' => 'Registrera dig', + 'manage_updates' => 'Manage Updates', // Other 'optional' => 'Valfri', diff --git a/resources/lang/sv-SE/notifications.php b/resources/lang/sv-SE/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/sv-SE/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/sv-SE/pagination.php b/resources/lang/sv-SE/pagination.php index 8c4ef806e8d..0ee724cf086 100644 --- a/resources/lang/sv-SE/pagination.php +++ b/resources/lang/sv-SE/pagination.php @@ -22,7 +22,7 @@ | */ - 'previous' => '« Föregående', - 'next' => 'Nästa »', + 'previous' => 'Previous', + 'next' => 'Next', ]; diff --git a/resources/lang/sv-SE/validation.php b/resources/lang/sv-SE/validation.php index 3c0173bc9fa..89e504e7bab 100644 --- a/resources/lang/sv-SE/validation.php +++ b/resources/lang/sv-SE/validation.php @@ -31,60 +31,60 @@ 'array' => '.attribute måste vara en lista med värden.', 'before' => ':attribute måste vara ett datum före :date.', 'between' => [ - 'numeric' => ':attribute måste vara ett datum före :date.', - 'file' => 'The :attribute must be between :min and :max.', - 'string' => 'The :attribute must be between :min and :max kilobytes.', + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', 'array' => ':attribute måste ha mellan :min och :max föremål.', ], - 'boolean' => ':attribute måste ha mellan :min och :max föremål.', - 'confirmed' => 'The :attribute field must be true or false.', - 'date' => 'The :attribute confirmation does not match.', - 'date_format' => 'The :attribute is not a valid date.', - 'different' => 'The :attribute does not match the format :format.', - 'digits' => 'The :attribute and :other must be different.', - 'digits_between' => 'The :attribute must be :digits digits.', - 'email' => 'The :attribute must be between :min and :max digits.', - 'exists' => 'The :attribute must be a valid email address.', + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', 'distinct' => 'The :attribute field has a duplicate value.', - 'filled' => ':attribute-formatet är ogiltigt.', + 'filled' => 'The :attribute field is required.', 'image' => ':attribute måste vara en bild.', - 'in' => ':attribute måste vara en bild.', + 'in' => 'The selected :attribute is invalid.', 'in_array' => 'The :attribute field does not exist in :other.', - 'integer' => 'The selected :attribute is invalid.', - 'ip' => 'The :attribute must be an integer.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', 'json' => ':attribute måste vara en giltig JSON-sträng.', 'max' => [ - 'numeric' => 'The :attribute must be a valid IP address.', - 'file' => 'The :attribute may not be greater than :max.', - 'string' => 'The :attribute may not be greater than :max kilobytes.', + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', 'array' => ':attribute får inte innehålla mer än :max föremål.', ], - 'mimes' => ':attribute får inte innehålla mer än :max föremål.', + 'mimes' => 'The :attribute must be a file of type: :values.', 'min' => [ - 'numeric' => 'The :attribute must be a file of type: :values.', + 'numeric' => 'The :attribute must be at least :min.', 'file' => ':attribute måste vara större än :min kilobyte.', - 'string' => ':attribute måste vara större än :min kilobyte.', - 'array' => 'The :attribute must be at least :min characters.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', ], - 'not_in' => 'The :attribute must have at least :min items.', - 'numeric' => 'The selected :attribute is invalid.', + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', 'present' => 'The :attribute field must be present.', - 'regex' => 'The :attribute must be a number.', - 'required' => ':attribute-formatet är ogiltigt.', - 'required_if' => 'The :attribute field is required.', + 'regex' => ':attribute-formatet är ogiltigt.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', 'required_unless' => ':attribute-fältet är obligatoriskt om inte :other är :value.', - 'required_with' => 'The :attribute field is required when :other is :value.', + 'required_with' => ':attribute fältet är obligatoriskt när :values är valda.', 'required_with_all' => ':attribute fältet är obligatoriskt när :values är valda.', - 'required_without' => ':attribute fältet är obligatoriskt när :values är valda.', - 'required_without_all' => 'The :attribute field is required when :values is not present.', - 'same' => 'The :attribute field is required when none of :values are present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', 'size' => [ - 'numeric' => 'The :attribute and :other must match.', + 'numeric' => 'The :attribute must be :size.', 'file' => ':attribute måste vara :size kilobyte.', 'string' => ':attribute måste vara :size tecken.', - 'array' => ':attribute måste vara :size tecken.', + 'array' => 'The :attribute must contain :size items.', ], - 'string' => 'The :attribute must contain :size items.', + 'string' => 'The :attribute must be a string.', 'timezone' => ':attribute måste vara en giltig zon.', 'unique' => ':attribute är upptaget.', 'url' => ':attribute-formatet är ogiltigt.', diff --git a/resources/lang/th-TH/cachet.php b/resources/lang/th-TH/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/th-TH/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/th-TH/dashboard.php b/resources/lang/th-TH/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/th-TH/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/th-TH/forms.php b/resources/lang/th-TH/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/th-TH/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/th-TH/notifications.php b/resources/lang/th-TH/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/th-TH/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/th-TH/pagination.php b/resources/lang/th-TH/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/th-TH/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/th-TH/setup.php b/resources/lang/th-TH/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/th-TH/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/th-TH/validation.php b/resources/lang/th-TH/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/th-TH/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/tr-TR/cachet.php b/resources/lang/tr-TR/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/tr-TR/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/tr-TR/dashboard.php b/resources/lang/tr-TR/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/tr-TR/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/tr-TR/forms.php b/resources/lang/tr-TR/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/tr-TR/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/tr-TR/notifications.php b/resources/lang/tr-TR/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/tr-TR/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/tr-TR/pagination.php b/resources/lang/tr-TR/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/tr-TR/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/tr-TR/setup.php b/resources/lang/tr-TR/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/tr-TR/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/tr-TR/validation.php b/resources/lang/tr-TR/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/tr-TR/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/tr/cachet.php b/resources/lang/tr/cachet.php index 9c89fd04a46..5caccfd8dfc 100644 --- a/resources/lang/tr/cachet.php +++ b/resources/lang/tr/cachet.php @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/tr/forms.php b/resources/lang/tr/forms.php index 1fadf9f0e69..18d35750a82 100644 --- a/resources/lang/tr/forms.php +++ b/resources/lang/tr/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'İsim', 'template' => 'Tema', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Site timezone', - 'site-locale' => 'Site language', - 'date-format' => 'Date format', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/uk-UA/cachet.php b/resources/lang/uk-UA/cachet.php new file mode 100644 index 00000000000..cb24fc10e7c --- /dev/null +++ b/resources/lang/uk-UA/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Operational', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/uk-UA/dashboard.php b/resources/lang/uk-UA/dashboard.php new file mode 100644 index 00000000000..7dc9af669de --- /dev/null +++ b/resources/lang/uk-UA/dashboard.php @@ -0,0 +1,304 @@ + 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/uk-UA/forms.php b/resources/lang/uk-UA/forms.php new file mode 100644 index 00000000000..075b7588a9c --- /dev/null +++ b/resources/lang/uk-UA/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Password', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Password', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Password', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/uk-UA/notifications.php b/resources/lang/uk-UA/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/uk-UA/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/uk-UA/pagination.php b/resources/lang/uk-UA/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/uk-UA/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/uk-UA/setup.php b/resources/lang/uk-UA/setup.php new file mode 100644 index 00000000000..bdc2a457873 --- /dev/null +++ b/resources/lang/uk-UA/setup.php @@ -0,0 +1,23 @@ + 'Setup', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/uk-UA/validation.php b/resources/lang/uk-UA/validation.php new file mode 100644 index 00000000000..7d196d984dd --- /dev/null +++ b/resources/lang/uk-UA/validation.php @@ -0,0 +1,122 @@ + 'The :attribute must be accepted.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/uk/cachet.php b/resources/lang/uk/cachet.php index 5fed6c5f97d..fb9f180a79b 100644 --- a/resources/lang/uk/cachet.php +++ b/resources/lang/uk/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/uk/dashboard.php b/resources/lang/uk/dashboard.php index 0078d64f576..335952b7c96 100644 --- a/resources/lang/uk/dashboard.php +++ b/resources/lang/uk/dashboard.php @@ -11,7 +11,8 @@ return [ - 'dashboard' => 'Dashboard', + 'dashboard' => 'Dashboard', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', // Incidents 'incidents' => [ @@ -20,6 +21,7 @@ 'logged' => '{0} There are no incidents, good work.|You have logged one incident.|You have reported :count incidents.', 'incident-create-template' => 'Create Template', 'incident-templates' => 'Incident Templates', + 'updates' => '{0} Zero Updates|One Update|:count Updates', 'add' => [ 'title' => 'Report an incident', 'success' => 'Incident added.', @@ -34,6 +36,10 @@ 'success' => 'The incident has been deleted and will not show on your status page.', 'failure' => 'The incident could not be deleted, please try again.', ], + 'update' => [ + 'title' => 'Create new incident update', + 'subtitle' => 'Add an update to :incident', + ], // Incident templates 'templates' => [ @@ -86,12 +92,12 @@ 'title' => 'Add a component', 'message' => 'You should add a component.', 'success' => 'Component created.', - 'failure' => 'Something went wrong with the component, please try again.', + 'failure' => 'Something went wrong with the component group, please try again.', ], 'edit' => [ 'title' => 'Edit a component', 'success' => 'Component updated.', - 'failure' => 'Something went wrong with the component, please try again.', + 'failure' => 'Something went wrong with the component group, please try again.', ], 'delete' => [ 'success' => 'The component has been deleted!', @@ -197,6 +203,9 @@ 'analytics' => [ 'analytics' => 'Analytics', ], + 'log' => [ + 'log' => 'Log', + ], 'localization' => [ 'localization' => 'Localization', ], @@ -205,6 +214,14 @@ 'header' => 'Custom Header HTML', 'footer' => 'Custom Footer HTML', ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], 'security' => [ 'security' => 'Security', 'two-factor' => 'Users without two-factor authentication', @@ -233,7 +250,7 @@ 'login' => [ 'login' => 'Login', 'logged_in' => 'You\'re logged in.', - 'welcome' => 'Welcome Back!', + 'welcome' => 'Welcome back!', 'two-factor' => 'Please enter your token.', ], @@ -254,21 +271,21 @@ 'support' => 'Support Cachet', 'support_subtitle' => 'Check out our Patreon page!', 'news' => 'Latest News', - 'news_subtitle' => 'Get the latest updates', + 'news_subtitle' => 'Get the latest update', ], // Welcome modal 'welcome' => [ - 'welcome' => 'Welcome to your new status page!', - 'message' => 'Your status page is almost ready! You might want to configure these extra settings', - 'close' => 'Take me straight to my dashboard', + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', 'steps' => [ - 'component' => 'Create components', - 'incident' => 'Create incidents', - 'customize' => 'Customize', - 'team' => 'Add users', - 'api' => 'Generate API token', - 'two-factor' => 'Two Factor Authentication', + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', ], ], diff --git a/resources/lang/uk/forms.php b/resources/lang/uk/forms.php index 7db00e87bba..91ebe7c550d 100644 --- a/resources/lang/uk/forms.php +++ b/resources/lang/uk/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Ім’я', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'id сайту Piwik', ], 'localization' => [ - 'site-timezone' => 'Часовий пояс сайту', - 'site-locale' => 'Мова сайту', - 'date-format' => 'формат дати', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Часовий пояс сайту', + 'site-locale' => 'Мова сайту', + 'date-format' => 'формат дати', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/vi-VN/cachet.php b/resources/lang/vi-VN/cachet.php new file mode 100644 index 00000000000..71eaee2c742 --- /dev/null +++ b/resources/lang/vi-VN/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'Last updated :timestamp', + 'status' => [ + 0 => 'Unknown', + 1 => 'Hoạt động', + 2 => 'Performance Issues', + 3 => 'Partial Outage', + 4 => 'Major Outage', + ], + 'group' => [ + 'other' => 'Other Components', + ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', + ], + + // Incidents + 'incidents' => [ + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ', scheduled :timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ + 1 => 'Investigating', + 2 => 'Identified', + 3 => 'Watching', + 4 => 'Fixed', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + + // Service Status + 'service' => [ + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', + ], + + 'api' => [ + 'regenerate' => 'Regenerate API Key', + 'revoke' => 'Revoke API Key', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'Last Hour', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => 'Notifications', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', + ], + 'email' => [ + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', + ], + ], + + 'signup' => [ + 'title' => 'Sign Up', + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Mật khẩu', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', + ], + + 'system' => [ + 'update' => 'There is a newer version of Cachet available. You can learn how to update here!', + ], + + // Modal + 'modal' => [ + 'close' => 'Close', + 'subscribe' => [ + 'title' => 'Subscribe to component updates', + 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', + ], + ], + + // Other + 'home' => 'Home', + 'powered_by' => 'Powered by Cachet.', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', + 'feed' => 'Status Feed', + +]; diff --git a/resources/lang/vi-VN/dashboard.php b/resources/lang/vi-VN/dashboard.php new file mode 100644 index 00000000000..270a50b1a37 --- /dev/null +++ b/resources/lang/vi-VN/dashboard.php @@ -0,0 +1,304 @@ + 'Bảng điều khiển', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', + + // Incidents + 'incidents' => [ + 'title' => 'Incidents & Maintenance', + 'incidents' => 'Incidents', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', + 'incident-create-template' => 'Create Template', + 'incident-templates' => 'Incident Templates', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', + 'add' => [ + 'title' => 'Report an incident', + 'success' => 'Incident added.', + 'failure' => 'There was an error adding the incident, please try again.', + ], + 'edit' => [ + 'title' => 'Edit an incident', + 'success' => 'Incident updated.', + 'failure' => 'There was an error editing the incident, please try again.', + ], + 'delete' => [ + 'success' => 'The incident has been deleted and will not show on your status page.', + 'failure' => 'The incident could not be deleted, please try again.', + ], + + // Incident templates + 'templates' => [ + 'title' => 'Incident Templates', + 'add' => [ + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', + 'success' => 'Your new incident template has been created.', + 'failure' => 'Something went wrong with the incident template.', + ], + 'edit' => [ + 'title' => 'Edit Template', + 'success' => 'The incident template has been updated.', + 'failure' => 'Something went wrong updating the incident template', + ], + 'delete' => [ + 'success' => 'The incident template has been deleted.', + 'failure' => 'The incident template could not be deleted, please try again.', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', + 'scheduled_at' => 'Scheduled at :timestamp', + 'add' => [ + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', + ], + 'edit' => [ + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', + ], + 'delete' => [ + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', + ], + ], + + // Components + 'components' => [ + 'components' => 'Components', + 'component_statuses' => 'Component Statuses', + 'listed_group' => 'Grouped under :name', + 'add' => [ + 'title' => 'Add a component', + 'message' => 'You should add a component.', + 'success' => 'Component created.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component', + 'success' => 'Component updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'The component has been deleted!', + 'failure' => 'The component could not be deleted, please try again.', + ], + + // Component groups + 'groups' => [ + 'groups' => 'Component group|Component groups', + 'no_components' => 'You should add a component group.', + 'add' => [ + 'title' => 'Add a component group', + 'success' => 'Component group added.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a component group', + 'success' => 'Component group updated.', + 'failure' => 'Something went wrong with the component group, please try again.', + ], + 'delete' => [ + 'success' => 'Component group has been deleted!', + 'failure' => 'The component group could not be deleted, please try again.', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'Metrics', + 'add' => [ + 'title' => 'Create a metric', + 'message' => 'You should add a metric.', + 'success' => 'Metric created.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'edit' => [ + 'title' => 'Edit a metric', + 'success' => 'Metric updated.', + 'failure' => 'Something went wrong with the metric, please try again.', + ], + 'delete' => [ + 'success' => 'The metric has been deleted and will no longer display on your status page.', + 'failure' => 'The metric could not be deleted, please try again.', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', + 'failure' => 'Something went wrong adding the subscriber, please try again.', + 'help' => 'Enter each subscriber on a new line.', + ], + 'edit' => [ + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', + 'failure' => 'Something went wrong editing the subscriber, please try again.', + ], + ], + + // Team + 'team' => [ + 'team' => 'Team', + 'member' => 'Member', + 'profile' => 'Profile', + 'description' => 'Team Members will be able to add, modify & edit components and incidents.', + 'add' => [ + 'title' => 'Add a new team member', + 'success' => 'Team member added.', + 'failure' => 'The team member could not be added, please try again.', + ], + 'edit' => [ + 'title' => 'Update profile', + 'success' => 'Profile updated.', + 'failure' => 'Something went wrong updating the profile, please try again.', + ], + 'delete' => [ + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', + 'failure' => 'The team member could not be added, please try again.', + ], + 'invite' => [ + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', + 'failure' => 'The invite could not be sent, please try again.', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'Settings', + 'app-setup' => [ + 'app-setup' => 'Application Setup', + 'images-only' => 'Only images may be uploaded.', + 'too-big' => 'The file you uploaded is too big. Upload an image smaller than :size', + ], + 'analytics' => [ + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', + ], + 'localization' => [ + 'localization' => 'Localization', + ], + 'customization' => [ + 'customization' => 'Customization', + 'header' => 'Custom Header HTML', + 'footer' => 'Custom Footer HTML', + ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], + 'security' => [ + 'security' => 'Security', + 'two-factor' => 'Users without two-factor authentication', + ], + 'stylesheet' => [ + 'stylesheet' => 'Stylesheet', + ], + 'theme' => [ + 'theme' => 'Theme', + ], + 'edit' => [ + 'success' => 'Settings saved.', + 'failure' => 'Settings could not be saved.', + ], + 'credits' => [ + 'credits' => 'Credits', + 'contributors' => 'Contributors', + 'license' => 'Cachet is a BSD-3-licensed open source project, released by Alt Three Services Limited.', + 'backers-title' => 'Backers & Sponsors', + 'backers' => 'If you\'d like to support future development, check out the Cachet Patreon campaign.', + 'thank-you' => 'Thank you to each and every one of the :count contributors.', + ], + ], + + // Login + 'login' => [ + 'login' => 'Login', + 'logged_in' => 'You\'re logged in.', + 'welcome' => 'Welcome back!', + 'two-factor' => 'Please enter your token.', + ], + + // Sidebar footer + 'help' => 'Help', + 'status_page' => 'Status Page', + 'logout' => 'Logout', + + // Notifications + 'notifications' => [ + 'notifications' => 'Notifications', + 'awesome' => 'Awesome.', + 'whoops' => 'Whoops.', + ], + + // Widgets + 'widgets' => [ + 'support' => 'Support Cachet', + 'support_subtitle' => 'Check out our Patreon page!', + 'news' => 'Latest News', + 'news_subtitle' => 'Get the latest update', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'Welcome to your new status page, :username!', + 'message' => 'You\'re almost ready but you might want to configure these extra settings first...', + 'close' => 'I\'m good thanks!', + 'steps' => [ + 'component' => 'Add your components', + 'incident' => 'Create an incident', + 'customize' => 'Customize your page', + 'team' => 'Add your team', + 'api' => 'Generate an API token', + 'two-factor' => 'Setup Two Factor Authentication', + ], + ], + +]; diff --git a/resources/lang/vi-VN/forms.php b/resources/lang/vi-VN/forms.php new file mode 100644 index 00000000000..bb757767ef8 --- /dev/null +++ b/resources/lang/vi-VN/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'Email', + 'username' => 'Username', + 'password' => 'Mật khẩu', + 'site_name' => 'Site Name', + 'site_domain' => 'Site Domain', + 'site_timezone' => 'Select your timezone', + 'site_locale' => 'Select your language', + 'enable_google2fa' => 'Enable Google Two Factor Authentication', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', + ], + + // Login form fields + 'login' => [ + 'login' => 'Username or Email', + 'email' => 'Email', + 'password' => 'Mật khẩu', + '2fauth' => 'Authentication Code', + 'invalid' => 'Invalid username or password', + 'invalid-token' => 'Invalid token', + 'cookies' => 'You must enable cookies to login.', + 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'Name', + 'status' => 'Status', + 'component' => 'Component', + 'component_status' => 'Component Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', + 'visibility' => 'Incident Visibility', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => 'Name', + 'status' => 'Status', + 'message' => 'Message', + 'message-help' => 'You may also use Markdown.', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => 'Name', + 'template' => 'Template', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'Name', + 'status' => 'Status', + 'group' => 'Group', + 'description' => 'Description', + 'link' => 'Link', + 'tags' => 'Tags', + 'tags-help' => 'Comma separated.', + 'enabled' => 'Component enabled?', + + 'groups' => [ + 'name' => 'Name', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'Name', + 'description' => 'Description', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => 'Group', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'Name', + 'suffix' => 'Suffix', + 'description' => 'Description', + 'description-help' => 'You may also use Markdown.', + 'display-chart' => 'Display chart on status page?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => 'Sum', + 'type_avg' => 'Average', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', + + 'points' => [ + 'value' => 'Value', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'Site Name', + 'site-url' => 'Site URL', + 'display-graphs' => 'Display graphs on status page?', + 'about-this-page' => 'About this page', + 'days-of-incidents' => 'How many days of incidents to show?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', + ], + 'analytics' => [ + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', + ], + 'localization' => [ + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', + ], + 'security' => [ + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', + ], + 'stylesheet' => [ + 'custom-css' => 'Custom Stylesheet', + ], + 'theme' => [ + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', + 'reds' => 'Red (used for errors)', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', + ], + ], + + 'user' => [ + 'username' => 'Username', + 'email' => 'Email', + 'password' => 'Mật khẩu', + 'api-token' => 'API Token', + 'api-token-help' => 'Regenerating your API token will prevent existing applications from accessing Cachet.', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', + 'levels' => [ + 'admin' => 'Admin', + 'user' => 'User', + ], + '2fa' => [ + 'help' => 'Enabling two factor authentication increases security of your account. You will need to download Google Authenticator or a similar app on to your mobile device. When you login you will be asked to provide a token generated by the app.', + ], + 'team' => [ + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', + ], + ], + + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + + // Buttons + 'add' => 'Add', + 'save' => 'Save', + 'update' => 'Update', + 'create' => 'Create', + 'edit' => 'Edit', + 'delete' => 'Delete', + 'submit' => 'Submit', + 'cancel' => 'Cancel', + 'remove' => 'Remove', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', + + // Other + 'optional' => '* Optional', +]; diff --git a/resources/lang/vi-VN/notifications.php b/resources/lang/vi-VN/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/vi-VN/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/vi-VN/pagination.php b/resources/lang/vi-VN/pagination.php new file mode 100644 index 00000000000..0ee724cf086 --- /dev/null +++ b/resources/lang/vi-VN/pagination.php @@ -0,0 +1,28 @@ + 'Previous', + 'next' => 'Next', + +]; diff --git a/resources/lang/vi-VN/setup.php b/resources/lang/vi-VN/setup.php new file mode 100644 index 00000000000..2293c30db52 --- /dev/null +++ b/resources/lang/vi-VN/setup.php @@ -0,0 +1,23 @@ + 'Cài đặt', + 'title' => 'Install Cachet', + 'service_details' => 'Service Details', + 'env_setup' => 'Environment Setup', + 'status_page_setup' => 'Status Page Setup', + 'show_support' => 'Show support for Cachet?', + 'admin_account' => 'Administrator Account', + 'complete_setup' => 'Complete Setup', + 'completed' => 'Cachet has been configured successfully!', + 'finish_setup' => 'Go to dashboard', +]; diff --git a/resources/lang/vi-VN/validation.php b/resources/lang/vi-VN/validation.php new file mode 100644 index 00000000000..c29028ebe0f --- /dev/null +++ b/resources/lang/vi-VN/validation.php @@ -0,0 +1,122 @@ + ':attribute phải được chấp nhận.', + 'active_url' => 'The :attribute is not a valid URL.', + 'after' => 'The :attribute must be a date after :date.', + 'alpha' => 'The :attribute may only contain letters.', + 'alpha_dash' => 'The :attribute may only contain letters, numbers, and dashes.', + 'alpha_num' => 'The :attribute may only contain letters and numbers.', + 'array' => 'The :attribute must be an array.', + 'before' => 'The :attribute must be a date before :date.', + 'between' => [ + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', + 'array' => 'The :attribute must have between :min and :max items.', + ], + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', + 'distinct' => 'The :attribute field has a duplicate value.', + 'filled' => 'The :attribute field is required.', + 'image' => 'The :attribute must be an image.', + 'in' => 'The selected :attribute is invalid.', + 'in_array' => 'The :attribute field does not exist in :other.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', + 'json' => 'The :attribute must be a valid JSON string.', + 'max' => [ + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', + 'array' => 'The :attribute may not have more than :max items.', + ], + 'mimes' => 'The :attribute must be a file of type: :values.', + 'min' => [ + 'numeric' => 'The :attribute must be at least :min.', + 'file' => 'The :attribute must be at least :min kilobytes.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', + ], + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', + 'present' => 'The :attribute field must be present.', + 'regex' => 'The :attribute format is invalid.', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', + 'required_unless' => 'The :attribute field is required unless :other is in :values.', + 'required_with' => 'The :attribute field is required when :values is present.', + 'required_with_all' => 'The :attribute field is required when :values is present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', + 'size' => [ + 'numeric' => 'The :attribute must be :size.', + 'file' => 'The :attribute must be :size kilobytes.', + 'string' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', + ], + 'string' => 'The :attribute must be a string.', + 'timezone' => 'The :attribute must be a valid zone.', + 'unique' => 'The :attribute has already been taken.', + 'url' => 'The :attribute format is invalid.', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'custom-message', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/lang/vi/cachet.php b/resources/lang/vi/cachet.php index cdd1216a9bb..23f39d8686f 100644 --- a/resources/lang/vi/cachet.php +++ b/resources/lang/vi/cachet.php @@ -45,7 +45,7 @@ 'service' => [ 'good' => '[0,1] System operational|[2,Inf] All systems are operational', 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'major' => '[0,1] The service is experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', ], 'api' => [ @@ -103,8 +103,8 @@ 'users' => [ 'email' => [ 'invite' => [ - 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", - 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', + 'text' => "You have been invited to the team :app_name status page, to sign up follow the next link.\n:link\nThank you, :app_name", + 'html' => '

You have been invited to the team :app_name status page, to sign up follow the next link.

:link

Thank you, :app_name

', ], ], ], diff --git a/resources/lang/vi/forms.php b/resources/lang/vi/forms.php index 1df3dcabe17..d9848d2a9f9 100644 --- a/resources/lang/vi/forms.php +++ b/resources/lang/vi/forms.php @@ -53,7 +53,7 @@ 'templates' => [ 'name' => 'Tên', 'template' => 'Template', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -118,10 +118,10 @@ 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => 'Múi giờ', - 'site-locale' => 'Ngôn ngữ', - 'date-format' => 'Định dạng ngày', - 'incident-date-format' => 'Incident timestamp format', + 'site-timezone' => 'Múi giờ', + 'site-locale' => 'Ngôn ngữ', + 'date-format' => 'Định dạng ngày', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ 'allowed-domains' => 'Allowed domains', diff --git a/resources/lang/zh-CN/cachet.php b/resources/lang/zh-CN/cachet.php index 1973dfa1229..47d5e6e4f99 100644 --- a/resources/lang/zh-CN/cachet.php +++ b/resources/lang/zh-CN/cachet.php @@ -12,28 +12,31 @@ return [ // Components 'components' => [ - 'last_updated' => '最后更新 :timestamp', + 'last_updated' => '最后更新于 :timestamp', 'status' => [ + 0 => '未知', 1 => '运行正常', - 2 => '负载较高', - 3 => 'Partial Outage', - 4 => 'Major Outage', + 2 => '性能问题', + 3 => '部分中断', + 4 => '严重中断', ], 'group' => [ 'other' => '其他组件', ], + 'select_all' => '全选', + 'deselect_all' => '反选所有', ], // Incidents 'incidents' => [ - 'none' => '无故障报告', - 'past' => '历史状态', - 'previous_week' => '前一周', - 'next_week' => '后一周', - 'scheduled' => 'Scheduled Maintenance', - 'scheduled_at' => ', scheduled :timestamp', - 'status' => [ - 0 => '计划中', // TODO: Hopefully remove this. + 'none' => '无故障报告', + 'past' => '历史状态', + 'stickied' => '已关注的故障', + 'scheduled' => '计划维护', + 'scheduled_at' => ',计划于 :timestamp', + 'posted' => '在 :timestamp 由 :username 发布', + 'posted_at' => '发布于 :timestamp', + 'status' => [ 1 => '确认中', 2 => '修复中', 3 => '已更新', @@ -41,15 +44,24 @@ ], ], + // Schedule + 'schedules' => [ + 'status' => [ + 0 => '即将进行', + 1 => '正在进行', + 2 => '已完成', + ], + ], + // Service Status 'service' => [ - 'good' => '[0,1] 系统工作正常|[2,Inf] 所有系统工作正常', - 'bad' => '[0,1] 一个系统出现了问题|[2,Inf] 一些系统出现了问题', - 'major' => '[0,1] 一个系统出现重大故障|[2,Inf] 一些系统出现重大故障', + 'good' => '[0,1] 系统工作正常|[2,*] 所有系统工作正常', + 'bad' => '[0,1] 系统出现了问题|[2,*] 一些系统出现了问题', + 'major' => '[0,1] 系统出现重大故障|[2,*] 一些系统出现重大故障', ], 'api' => [ - 'regenerate' => 'Regenerate API Key', + 'regenerate' => '重新生成 API 密钥', 'revoke' => '注销 API 密钥', ], @@ -65,55 +77,37 @@ // Subscriber 'subscriber' => [ - 'subscribe' => '订阅最新的更新。', - 'button' => 'Subscribe', - 'manage' => [ - 'no_subscriptions' => '您当前已订阅所有更新。', - 'my_subscriptions' => '您当前已订阅下列更新', + 'subscribe' => '关注状态更改和更新', + 'unsubscribe' => '取消订阅', + 'button' => '订阅', + 'manage_subscription' => '管理订阅', + 'manage' => [ + 'notifications' => '通知', + 'notifications_for' => '管理通知给', + 'no_subscriptions' => '您当前已订阅所有更新。', + 'update_subscription' => '更新订阅', + 'my_subscriptions' => '您当前已订阅下列更新', + 'manage_at_link' => '在 :link 管理你的订阅', ], 'email' => [ - 'subscribe' => 'Subscribe to email updates.', - 'subscribed' => '您已经订阅电子邮件通知,请检查您的电子邮件,确认您的订阅。', - 'verified' => 'Your email subscription has been confirmed. Thank you!', - 'manage' => '管理您的订阅', - 'unsubscribe' => '取消电子邮件订阅。', - 'unsubscribed' => 'Your email subscription has been cancelled.', - 'failure' => 'Something went wrong with the subscription.', - 'already-subscribed' => '无法订阅,因为这个邮箱地址 ( :email ) 已经在订阅列表中了。', - 'verify' => [ - 'text' => "请确认您的 :app_name 状态更新邮件订阅。\n:link", - 'html' => '

请确认您的 :app_name 状态更新邮件订阅。

', - 'button' => '确认订阅', - ], - 'maintenance' => [ - 'subject' => '[计划维护] :name', - ], - 'incident' => [ - 'subject' => '[新事件] :status: :name', - ], - 'component' => [ - 'subject' => '组件状态更新', - 'text' => '组件 :component_name 的状态已经更新。:component_name 现在的状态为 :component_human_status。\n谢谢, :app_name', - 'html' => '

组件 :component_name 有状态变更。:component_name 当前 :component_human_status。

谢谢, :app_name

', - 'tooltip-title' => '订阅来自 component_name 的更新', - ], - ], - ], - - 'users' => [ - 'email' => [ - 'invite' => [ - 'text' => "您已被邀请加入 :app_name 团队的状态页, 请点击以下链接进行注册。\n:link\n谢谢, :app_name", - 'html' => '

您已被邀请加入 :app_name 团队的状态页, 请点击以下链接进行注册。

:link

谢谢, :app_name

', - ], + 'manage_subscription' => '我们已经给您发送了一封电子邮件,请点击链接来管理您的订阅', + 'subscribe' => '订阅电子邮件更新。', + 'subscribed' => '您已经订阅电子邮件通知,请检查您的电子邮件进行确认。', + 'updated-subscribe' => '您已成功更新您的订阅。', + 'verified' => '您的电子邮件订阅已确认。谢谢!', + 'manage' => '管理您的订阅', + 'unsubscribe' => '取消电子邮件订阅。', + 'unsubscribed' => '您的电子邮件订阅已被取消。', + 'failure' => '邮件订阅失败。', + 'already-subscribed' => '无法订阅,因为这个邮箱地址 ( :email ) 已经在订阅列表中了。', ], ], 'signup' => [ 'title' => '注册', - 'username' => 'Username', + 'username' => '用户名', 'email' => '电子邮箱', - 'password' => 'Password', + 'password' => '密码', 'success' => '您的账号已注册成功。', 'failure' => '注册失败。', ], @@ -128,17 +122,27 @@ 'subscribe' => [ 'title' => '订阅组件状态更新', 'body' => '请输入您用于接收订阅该组件更新通知的电子邮箱。如果您已经订阅,您应已收到关于这个组件的一系列电子邮件。', - 'button' => 'Subscribe', + 'button' => '订阅', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => '有关于发生在 :date 的 :name 事件的细节与更新', + 'schedule' => '有关于计划维护时段 :name ,开始于 :startDate,的细节说明', + 'subscribe' => '订阅 :app 以接收故障更新和定期维护信息', + 'overview' => '始终保持对 :app 服务状态的关注。', ], ], // Other 'home' => '主屏幕', - 'description' => '始终保持对 :app 服务状态的关注。', 'powered_by' => '由 Cachet 驱动。', - 'about_this_site' => '关于我们', + 'timezone' => '时间将以 :timezone 时区显示。', + 'about_this_site' => '关于本站', 'rss-feed' => 'RSS', 'atom-feed' => 'Atom', - 'feed' => 'Status Feed', + 'feed' => '状态源', ]; diff --git a/resources/lang/zh-CN/dashboard.php b/resources/lang/zh-CN/dashboard.php index f675b48bdf9..7a8007d2ab5 100644 --- a/resources/lang/zh-CN/dashboard.php +++ b/resources/lang/zh-CN/dashboard.php @@ -11,15 +11,31 @@ return [ - 'dashboard' => '控制台', + 'dashboard' => '控制台', + 'writeable_settings' => 'Cachet 设置目录无法写入。请确认 ./bootstrap/cachet 文件夹可被服务器写入。', // Incidents 'incidents' => [ 'title' => '故障和维护计划', - 'incidents' => 'Incidents', - 'logged' => '{0} 当前没有故障信息|您已经记录了一个故障|您已经报告了 :count 个故障', - 'incident-create-template' => 'Create Template', + 'incidents' => '事件', + 'logged' => '{0} 当前没有故障信息|[1]您已经记录了一个故障.|[2,*]您已经报告了 :count 个故障', + 'incident-create-template' => '创建模板', 'incident-templates' => '故障模板', + 'updates' => [ + 'title' => '关于 :incident 事件的更新', + 'count' => '{0} 无更新|[1] 一个更新|[2] 2个更新|[3,*] 多个更新', + 'add' => [ + 'title' => '添加故障更新', + 'success' => '您已创建新的故障更新。', + 'failure' => '创建故障更新时出现了问题。', + ], + 'edit' => [ + 'title' => '编辑故障更新', + 'success' => '成功更新故障。', + 'failure' => '修改故障更新时出现问题', + ], + ], + 'reported_by' => '在 :timestamp 由 :user 报告', 'add' => [ 'title' => '添加故障', 'success' => '故障已添加', @@ -37,10 +53,10 @@ // Incident templates 'templates' => [ - 'title' => '事件模板', + 'title' => '故障模板', 'add' => [ 'title' => '添加故障模板', - 'message' => '你应该增加一个故障模板', + 'message' => '创建你的第一个故障模板', 'success' => '成功创建新的故障模板。', 'failure' => '创建模板失败。', ], @@ -59,8 +75,8 @@ // Incident Maintenance 'schedule' => [ 'schedule' => '计划维护', - 'logged' => '{0} 现在没有维护计划,好样的。|你已经记录下 1 个维护计划|你已经报告了 :count 个维护计划', - 'scheduled_at' => 'Scheduled at :timestamp', + 'logged' => '{0}目前没有任何维护信息,很棒!|[1]你已经记录下1个维护计划.|[2,*]你已经报告了 :count 个维护计划.', + 'scheduled_at' => '计划在 :timestamp', 'add' => [ 'title' => '添加维护计划', 'success' => '维护计划已添加。', @@ -79,9 +95,9 @@ // Components 'components' => [ - 'components' => 'Components', - 'component_statuses' => 'Component Statuses', - 'listed_group' => 'Grouped under :name', + 'components' => '组件', + 'component_statuses' => '组件状态', + 'listed_group' => '根据 :name 分组', 'add' => [ 'title' => '添加组件', 'message' => '没有组件,马上添加一个吧', @@ -105,12 +121,12 @@ 'add' => [ 'title' => '添加组件分组', 'success' => '分组已添加。', - 'failure' => '分组更新失败,请重试。', + 'failure' => '组件更新失败,请稍后再试。', ], 'edit' => [ 'title' => '编辑组件分组', 'success' => '分组已更新。', - 'failure' => '分组更新失败,请重试。', + 'failure' => '组件更新失败,请稍后再试。', ], 'delete' => [ 'success' => '组建分组已删除。', @@ -121,9 +137,9 @@ // Metrics 'metrics' => [ - 'metrics' => 'Metrics', + 'metrics' => '图表', 'add' => [ - 'title' => '添加图表', + 'title' => '创建图表', 'message' => '你应该添加一个图表。', 'success' => '图表已创建。', 'failure' => '添加图表时出错了,请再试一次。', @@ -140,13 +156,15 @@ ], // Subscribers 'subscribers' => [ - 'subscribers' => '通知', - 'description' => '有新增故障或有组件更新时,订阅者将会收到邮件提醒。', - 'verified' => '已认证', - 'not_verified' => '未认证', - 'subscriber' => ':email, 订阅于 :date', - 'no_subscriptions' => '已订阅全部更新', - 'add' => [ + 'subscribers' => '通知', + 'description' => '有新增故障或有组件更新时,订阅者将会收到邮件提醒。', + 'description_disabled' => '要使用此功能,您需要允许通知订阅。', + 'verified' => '已认证', + 'not_verified' => '未认证', + 'subscriber' => ':email, 订阅于 :date', + 'no_subscriptions' => '已订阅全部更新', + 'global' => '全局订阅', + 'add' => [ 'title' => '添加邮件订阅', 'success' => '邮件订阅已添加成功。', 'failure' => '无法添加订阅者,请稍后再试。', @@ -161,9 +179,9 @@ // Team 'team' => [ - 'team' => 'Team', - 'member' => 'Member', - 'profile' => 'Profile', + 'team' => '团队', + 'member' => '成员', + 'profile' => '用户信息', 'description' => '团队成员可维护组件和故障信息。', 'add' => [ 'title' => '添加团队成员', @@ -188,39 +206,50 @@ // Settings 'settings' => [ - 'settings' => 'Settings', + 'settings' => '系统设置', 'app-setup' => [ - 'app-setup' => '网站设置', - 'images-only' => 'Only images may be uploaded.', + 'app-setup' => '常规选项', + 'images-only' => '只能上传图像。', 'too-big' => '您上传的文件太大了。上传的图像大小应小于:size', ], 'analytics' => [ 'analytics' => '第三方统计', ], + 'log' => [ + 'log' => '日志', + ], 'localization' => [ - 'localization' => '本地化', + 'localization' => '时间和语言', ], 'customization' => [ - 'customization' => '自定义', + 'customization' => '个性定制', 'header' => '自定义页眉 HTML', 'footer' => '自定义页脚 HTML', ], + 'mail' => [ + 'mail' => '邮件', + 'test' => '测试', + 'email' => [ + 'subject' => 'Cachet 通知测试', + 'body' => '这是来自 Cachet 的测试通知邮件。', + ], + ], 'security' => [ 'security' => '安全设置', - 'two-factor' => 'Users without two-factor authentication', + 'two-factor' => '没有启用双因素身份验证的用户', ], 'stylesheet' => [ - 'stylesheet' => '自定义样式', + 'stylesheet' => '附加样式', ], 'theme' => [ - 'theme' => 'Theme', + 'theme' => '主题外观', ], 'edit' => [ - 'success' => 'Settings saved.', - 'failure' => 'Settings could not be saved.', + 'success' => '设置已保存。', + 'failure' => '无法保存设置。', ], 'credits' => [ - 'credits' => '团队', + 'credits' => '关于开发团队', 'contributors' => '贡献者', 'license' => 'Cachet 是 Alt Three Services Limited 开发的一个开源项目,使用 BSD-3 授权。', 'backers-title' => '后勤力量和赞助商', @@ -233,19 +262,19 @@ 'login' => [ 'login' => '登录', 'logged_in' => '您已登录', - 'welcome' => 'Welcome Back!', - 'two-factor' => 'Please enter your token.', + 'welcome' => '欢迎回来!', + 'two-factor' => '请输入您的双重验证码。', ], // Sidebar footer - 'help' => 'Help', + 'help' => '帮助', 'status_page' => '状态页', 'logout' => '退出', // Notifications 'notifications' => [ - 'notifications' => 'Notifications', - 'awesome' => 'Awesome.', + 'notifications' => '通知', + 'awesome' => '太棒了!', 'whoops' => '抱歉,', ], @@ -260,13 +289,13 @@ // Welcome modal 'welcome' => [ 'welcome' => '欢迎来到你的状态页!', - 'message' => 'Your status page is almost ready! You might want to configure these extra settings', + 'message' => '您的状态页面即将准备好了!您可能想要配置这些额外的设置', 'close' => '带我直接进入控制台', 'steps' => [ 'component' => '添加组件', 'incident' => '添加故障', 'customize' => '主题设置', - 'team' => 'Add users', + 'team' => '添加用户', 'api' => '生成 API Token', 'two-factor' => '双因素身份验证', ], diff --git a/resources/lang/zh-CN/forms.php b/resources/lang/zh-CN/forms.php index 02484c25096..1b74f77fa9e 100644 --- a/resources/lang/zh-CN/forms.php +++ b/resources/lang/zh-CN/forms.php @@ -15,14 +15,20 @@ 'setup' => [ 'email' => '电子邮箱', 'username' => '用户名', - 'password' => 'Password', - 'site_name' => '站点名称', + 'password' => '密码', + 'site_name' => '站点标题', 'site_domain' => '域名', - 'site_timezone' => 'Select your timezone', - 'site_locale' => 'Select your language', - 'enable_google2fa' => 'Enable Google Two Factor Authentication', - 'cache_driver' => 'Cache Driver', - 'session_driver' => 'Session Driver', + 'site_timezone' => '选择时区', + 'site_locale' => '选择您的语言', + 'enable_google2fa' => '启用谷歌两步身份验证', + 'cache_driver' => '缓存驱动', + 'queue_driver' => '队列存储方式', + 'session_driver' => '会话数据存储驱动', + 'mail_driver' => '邮件发送方式', + 'mail_host' => '电子邮件服务器', + 'mail_address' => '发件人', + 'mail_username' => '邮箱用户名', + 'mail_password' => '邮箱密码', ], // Login form fields @@ -30,112 +36,162 @@ 'login' => '用户名或者邮箱地址', 'email' => '电子邮箱', 'password' => '密码', - '2fauth' => 'Authentication Code', + '2fauth' => '两步验证代码', 'invalid' => '无效的用户名或密码', - 'invalid-token' => 'Invalid token', - 'cookies' => 'You must enable cookies to login.', + 'invalid-token' => '无效的代码。', + 'cookies' => '您必须启用 cookies 来进行登录。', 'rate-limit' => '已超出登陆次数限制。', + 'remember_me' => '记住我', ], // Incidents form fields 'incidents' => [ 'name' => '名称', - 'status' => 'Status', - 'component' => 'Component', + 'status' => '状态', + 'component' => '组件', + 'component_status' => '组件状态', 'message' => '描述', - 'message-help' => 'You may also use Markdown.', - 'scheduled_at' => 'When to schedule the maintenance for?', - 'incident_time' => '这次故障是什么时候发生的?', + 'message-help' => '您可以使用Markdown语言。', + 'occurred_at' => '这次故障是什么时候发生的?', 'notify_subscribers' => '通知订阅者', + 'notify_disabled' => '由于计划维护,关于此事件或此部件的通知将被静默处理。', 'visibility' => '故障的可见性', - 'public' => 'Viewable by public', + 'stick_status' => '关注故障', + 'stickied' => '已关注', + 'not_stickied' => '未关注', + 'public' => '公共可见', 'logged_in_only' => '仅登录用户可见', 'templates' => [ - 'name' => '事件名', - 'template' => 'Template', - 'twig' => '故障模板可以使用 Twig 模板语言', + 'name' => '名称', + 'template' => '模板', + 'twig' => '故障模板可以使用 Twig 模板语言', + ], + ], + + 'schedules' => [ + 'name' => '名称', + 'status' => '状态', + 'message' => '描述', + 'message-help' => '您可以使用Markdown语言。', + 'scheduled_at' => '这次维护将在何时进行?', + 'completed_at' => '这次维护将在何时结束?', + 'templates' => [ + 'name' => '名称', + 'template' => '模板', + 'twig' => '故障模板可以使用 Twig 模板语言', ], ], // Components form fields 'components' => [ - 'name' => '组件名', + 'name' => '名称', 'status' => '状态', 'group' => '组件分组', 'description' => '组件描述', - 'link' => 'Link', - 'tags' => 'Tags', - 'tags-help' => 'Comma separated.', + 'link' => '链接', + 'tags' => '标签', + 'tags-help' => '以逗号分隔。', 'enabled' => '启用', 'groups' => [ - 'name' => '组名', - 'collapsing' => '选择分组可见', - 'visible' => '总是展开', - 'collapsed' => '默认折叠', - 'collapsed_incident' => '折叠分组,但当有故障时展开', + 'name' => '名称', + 'collapsing' => '展开/折叠选项', + 'visible' => '总是展开', + 'collapsed' => '默认折叠', + 'collapsed_incident' => '折叠分组,但当有故障时展开', + 'visibility' => '可见性', + 'visibility_public' => '对所有人可见', + 'visibility_authenticated' => '只对已登录用户可见', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => '名称', + 'description' => '组件描述', + 'start_at' => '计划开始时间', + 'timezone' => '时区', + 'schedule_frequency' => '计划间隔 (秒)', + 'completion_latency' => '延误时长 (秒)', + 'group' => '组件分组', + 'active' => '活跃?', + 'groups' => [ + 'name' => '组名', ], ], // Metric form fields 'metrics' => [ - 'name' => '图表名', - 'suffix' => 'Suffix', - 'description' => '描述信息', - 'description-help' => '您可以使用Markdown语言。', - 'display-chart' => 'Display chart on status page?', - 'default-value' => '默认值', - 'calc_type' => '图表计算方法', - 'type_sum' => 'Sum', - 'type_avg' => 'Average', - 'places' => '小数点位数', - 'default_view' => '默认视图', - 'threshold' => '每个度量点之间应当间隔多少分钟?', + 'name' => '名称', + 'suffix' => '后缀', + 'description' => '组件描述', + 'description-help' => '您可以使用Markdown语言。', + 'display-chart' => '是否在状态页上显示图表?', + 'default-value' => '默认值', + 'calc_type' => '图表计算方法', + 'type_sum' => '求和', + 'type_avg' => '求平均', + 'places' => '小数点位数', + 'default_view' => '默认视图', + 'threshold' => '每个度量点之间应当间隔多少分钟?', + 'visibility' => '可见性', + 'visibility_authenticated' => '只对已登录用户可见', + 'visibility_public' => '对所有人可见', + 'visibility_hidden' => '总是隐藏', 'points' => [ - 'value' => 'Value', + 'value' => '数值', ], ], // Settings 'settings' => [ - /// Application setup + // Application setup 'app-setup' => [ - 'site-name' => '站点名称', - 'site-url' => '网址', - 'display-graphs' => 'Display graphs on status page?', - 'about-this-page' => '关于本页', - 'days-of-incidents' => '显示多少天的故障?', - 'banner' => '横幅图像', - 'banner-help' => "It's recommended that you upload files no bigger than 930px wide .", - 'subscribers' => 'Allow people to signup to email notifications?', - 'automatic_localization' => '根据访客的系统语言自动本地化状态页面?', + 'site-name' => '站点标题', + 'site-url' => '站点地址(URL)', + 'display-graphs' => '在状态页上显示图表', + 'about-this-page' => '关于本页', + 'days-of-incidents' => '每页最多显示故障天数', + 'time_before_refresh' => '状态页刷新速度(秒)', + 'major_outage_rate' => '重大故障阈值 (%)', + 'banner' => '横幅图像', + 'banner-help' => '建议上传文件宽度不大于 930 像素。', + 'subscribers' => '允许用户订阅邮件通知', + 'suppress_notifications_in_maintenance' => '当计划维护发生时静默处理事件通知?', + 'skip_subscriber_verification' => '是否跳过用户邮件验证?(小心,这可能会被滥用)', + 'automatic_localization' => '根据访客的系统语言自动本地化状态页面', + 'enable_external_dependencies' => '启用第三方服务 (Google Fonts, Tracker 等)', + 'show_timezone' => '显示状态页所在的时区', + 'only_disrupted_days' => '仅显示有故障的日期', ], 'analytics' => [ 'analytics_google' => 'Google Analytics 代码', 'analytics_gosquared' => 'GoSquared Analytics 代码', - 'analytics_piwik_url' => '输入Piwik实例的URL(不含http(s)://)', + 'analytics_piwik_url' => 'Piwik 实例的 URL', 'analytics_piwik_siteid' => 'Piwik 的站点 id', ], 'localization' => [ - 'site-timezone' => '系统时区', - 'site-locale' => '系统语言', - 'date-format' => '日期格式', - 'incident-date-format' => '故障的时间显示格式', + 'site-timezone' => '系统时区', + 'site-locale' => '系统语言', + 'date-format' => '日期格式', + 'incident-date-format' => '故障日期和时间格式', ], 'security' => [ - 'allowed-domains' => '允许的域', - 'allowed-domains-help' => 'Comma separated. The domain set above is automatically allowed by default.', + 'allowed-domains' => '允许的 CORS 域', + 'allowed-domains-help' => '以逗号分隔。默认情况下,API跨域请求将自动允许以上已设置的域。', + 'always-authenticate' => '始终验证', + 'always-authenticate-help' => '需要登录才能查看 Cachet 页面', ], 'stylesheet' => [ 'custom-css' => '自定义 CSS 样式表', ], 'theme' => [ - 'background-color' => '背景色', + 'background-color' => '网站背景', 'background-fills' => '区块填充色(组件, 故障, 页尾)', - 'banner-background-color' => '横幅背景色', - 'banner-padding' => '横幅Padding值', - 'fullwidth-banner' => '启用全宽横幅?', + 'banner-background-color' => '横幅背景', + 'banner-padding' => '横幅图像边距', + 'fullwidth-banner' => '是否启用full width banner?', 'text-color' => '文字颜色', 'dashboard-login' => '在页尾显示 管理后台 的入口?', 'reds' => '红 (用于错误类提示)', @@ -149,10 +205,10 @@ ], 'user' => [ - 'username' => 'Username', + 'username' => '用户名', 'email' => '电子邮箱', 'password' => '密码', - 'api-token' => 'API Token', + 'api-token' => 'API 令牌', 'api-token-help' => '重新生成您的 API Token将阻止现有的应用程序访问Cachet。', 'gravatar' => '修改您的 Gravatar 头像。', 'user_level' => '用户等级', @@ -165,23 +221,33 @@ ], 'team' => [ 'description' => '请输入您要邀请的团队成员的邮件地址:', - 'email' => 'Email #:id', + 'email' => '团队成员的电子邮箱地址', ], ], + 'general' => [ + 'timezone' => '选择时区', + ], + + 'seo' => [ + 'title' => 'SEO 标题', + 'description' => 'SEO 描述', + ], + // Buttons - 'add' => 'Add', - 'save' => 'Save', - 'update' => 'Update', - 'create' => 'Create', - 'edit' => 'Edit', - 'delete' => 'Delete', - 'submit' => 'Submit', - 'cancel' => 'Cancel', - 'remove' => 'Remove', - 'invite' => '邀请', - 'signup' => '注册', + 'add' => '增加', + 'save' => '保存​​', + 'update' => '更新', + 'create' => '创建', + 'edit' => '编辑', + 'delete' => '删除', + 'submit' => '提交', + 'cancel' => '取消', + 'remove' => '删除', + 'invite' => '邀请', + 'signup' => '注册', + 'manage_updates' => '管理更新', // Other - 'optional' => '* Optional', + 'optional' => '* 可选', ]; diff --git a/resources/lang/zh-CN/notifications.php b/resources/lang/zh-CN/notifications.php new file mode 100644 index 00000000000..54d4e2ff561 --- /dev/null +++ b/resources/lang/zh-CN/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => '组件状态已更新', + 'greeting' => '一个组件的状态已被更新!', + 'content' => ':name 状态已由 :old_status 变为 :new_status。', + 'action' => '查看', + ], + 'slack' => [ + 'title' => '组件状态已更新', + 'content' => ':name 状态已由 :old_status 变为 :new_status。', + ], + 'sms' => [ + 'content' => ':name 状态已由 :old_status 变为 :new_status。', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => '有新故障报告', + 'greeting' => '在 :app_name 处有新故障报告。', + 'content' => '故障 :name 已被报告', + 'action' => '查看', + ], + 'slack' => [ + 'title' => '故障 :name 已报告', + 'content' => '在 :app_name 处有新故障报告。', + ], + 'sms' => [ + 'content' => '在 :app_name 处有新故障报告。', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => '有故障更新', + 'content' => ':name 被更新', + 'title' => ':name 被更新至 :new_status', + 'action' => '查看', + ], + 'slack' => [ + 'title' => ':name 已更新', + 'content' => ':name 被更新至 :new_status', + ], + 'sms' => [ + 'content' => '故障 :name 已被更新', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => '新的维护计划已创建', + 'content' => ':name 已计划于 :date 进行', + 'title' => '新的计划维护已创建。', + 'action' => '查看', + ], + 'slack' => [ + 'title' => '新计划已创建!', + 'content' => ':name 已计划于 :date 进行', + ], + 'sms' => [ + 'content' => ':name 已计划于 :date 进行', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => '验证您的订阅', + 'content' => '点击验证您对 :app_name 状态页的订阅。', + 'title' => '验证您对 :app_name 状态页的订阅。', + 'action' => '验证', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => '管理您的订阅', + 'content' => '点击管理您对 :app_name 状态页的订阅。', + 'title' => '点击管理您对 :app_name 状态页的订阅。', + 'action' => '管理订阅', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => '这是来自 Cachet 的消息!', + 'content' => '这是来自 Cachet 的测试通知邮件!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => '这是您的邀请函...', + 'content' => '您已被邀请加入 :app_name 状态页。', + 'title' => '您被邀请加入 :app_name 状态页。', + 'action' => '接受', + ], + ], + ], +]; diff --git a/resources/lang/zh-CN/pagination.php b/resources/lang/zh-CN/pagination.php index 741cd8da871..c95f0ea289e 100644 --- a/resources/lang/zh-CN/pagination.php +++ b/resources/lang/zh-CN/pagination.php @@ -22,7 +22,7 @@ | */ - 'previous' => '« 上一个', - 'next' => '下一个 »', + 'previous' => '上一个', + 'next' => '下一个', ]; diff --git a/resources/lang/zh-CN/setup.php b/resources/lang/zh-CN/setup.php index b2f1e531cc3..021f0d24946 100644 --- a/resources/lang/zh-CN/setup.php +++ b/resources/lang/zh-CN/setup.php @@ -15,7 +15,7 @@ 'service_details' => '服务细节', 'env_setup' => '环境设置', 'status_page_setup' => '状态页面设置', - 'show_support' => '您想支持Cachet么?', + 'show_support' => '在页面底部显示 “由 Cachet 驱动。”', 'admin_account' => '管理员帐户', 'complete_setup' => '设置完成', 'completed' => 'Cachet已成功配置!', diff --git a/resources/lang/zh-CN/validation.php b/resources/lang/zh-CN/validation.php index fa7d926c3d3..5913f5d69fe 100644 --- a/resources/lang/zh-CN/validation.php +++ b/resources/lang/zh-CN/validation.php @@ -22,7 +22,7 @@ | */ - 'accepted' => ':attribute 必须是可以接受的。', + 'accepted' => '您必须同意 :attribute。', 'active_url' => ':attribute 不是一个有效的URL网址。', 'after' => ':attribute 必须在 :date 之后。', 'alpha' => ':attribute 只能包含字母。', @@ -31,60 +31,60 @@ 'array' => ':attribute 必须是个数组。', 'before' => ':attribute 必须在 :date 之前。', 'between' => [ - 'numeric' => ':attribute 必须在 :date 之前。', - 'file' => ':attribute 必须在 :min 和 :max 之间。', - 'string' => ':attribute 必须在 :min 到 :max Kb 之间。', + 'numeric' => ':attribute 必须在 :min 和 :max 之间。', + 'file' => ':attribute 必须在 :min KB 到 :max KB 之间。', + 'string' => ':attribute 包含的字符数量必须在 :min 到 :max 之间。', 'array' => ':attribute 必须在 :min 到 :max 个数目之间。', ], - 'boolean' => ':attribute 必须在 :min 到 :max 个数目之间。', - 'confirmed' => ':attribute 字段必须为 true 或 false。', - 'date' => ':attribute 与确认项目不匹配', - 'date_format' => ':attribute 不是有效的日期。', - 'different' => ':attribute 不符合格式 :format 。', - 'digits' => ':attribute 和 :other 不能相同。', - 'digits_between' => ':attribute 必须是 :digits 位数字。', - 'email' => ':attribute 必须在 :min 位和 :max 位数字之间。', - 'exists' => ':attribute 必须是一个有效的电子邮件地址。', + 'boolean' => ':attribute 字段必须为 true 或 false。', + 'confirmed' => ':attribute 的两次输入不匹配。', + 'date' => ':attribute 不是有效的日期。', + 'date_format' => ':attribute 不符合格式 :format 。', + 'different' => ':attribute 和 :other 不能相同。', + 'digits' => ':attribute 必须是 :digits 位数字。', + 'digits_between' => ':attribute 必须是 :min - :max 位数字。', + 'email' => ':attribute 必须是一个有效的电子邮件地址。', + 'exists' => '选择的 :attribute 无效。', 'distinct' => ':attribute 有重复。', - 'filled' => ':attribute 的格式无效', + 'filled' => ':attribute 字段必填。', 'image' => ':attribute 必须是图片。', - 'in' => ':attribute 必须是图片。', + 'in' => '选择的 :attribute 无效。', 'in_array' => ':attribute 不在 :other 中。', - 'integer' => '选择的 :attribute 无效', - 'ip' => ':attribute 必须是整数。', + 'integer' => ':attribute 必须是整数。', + 'ip' => ':attribute 必须是一个有效的 IP 地址。', 'json' => ':attribute 必须是规范的 JSON 字串。', 'max' => [ - 'numeric' => ':attribute 必须是一个有效的 IP 地址', - 'file' => ':attribute 不允许大于 :max', - 'string' => ':attribute 不能大于 :max Kb。', + 'numeric' => ':attribute 不允许大于 :max。', + 'file' => ':attribute 不能大于 :max KB。', + 'string' => ':attribute 的字符数量不能大于 :max 。', 'array' => ':attribute 不能超过 :max 个。', ], - 'mimes' => ':attribute 不能超过 :max 个。', + 'mimes' => ':attribute 文件类型必须是 :values。', 'min' => [ - 'numeric' => ':attribute 文件类型必须是 :values', + 'numeric' => ':attribute 必须至少是 :min。', 'file' => ':attribute 至少需要 :min KB。', - 'string' => ':attribute 至少需要 :min KB。', - 'array' => ':attribute 最少需要 :min 个字符。', + 'string' => ':attribute 最少需要有 :min 个字符。', + 'array' => ':attribute 至少需要有 :min 项。', ], - 'not_in' => ':attribute 至少需要有 :min 项。', - 'numeric' => '选择的 :attribute 无效', + 'not_in' => '选择的 :attribute 无效。', + 'numeric' => ':attribute 必须是数字。', 'present' => ':attribute 为必填项。', - 'regex' => ':attribute 必须是数字。', - 'required' => ':attribute 的格式无效', - 'required_if' => ':attribute 字段必填。', + 'regex' => ':attribute 的格式无效', + 'required' => ':attribute 字段必填。', + 'required_if' => ':attribute 字段在 :other 是 :value 时是必填的。', 'required_unless' => ':attribute 是必须的除非 :other 在 :values 中。', - 'required_with' => ':attribute 字段在 :other 是 :value 时是必填的。', + 'required_with' => '当含有 :values 时, :attribute 是必需的。', 'required_with_all' => '当含有 :values 时, :attribute 是必需的。', - 'required_without' => '当含有 :values 时, :attribute 是必需的。', - 'required_without_all' => '当 :values 不存在时, :attribute 是必填的。', - 'same' => '当没有任何 :values 存在时, :attribute 字段为必填项。', + 'required_without' => '当 :values 不存在时, :attribute 是必填的。', + 'required_without_all' => '当没有任何 :values 存在时,:attribute 字段为必填项。', + 'same' => ':attribute 和 :other 必须匹配。', 'size' => [ - 'numeric' => ':attribute 和 :other 必须匹配。', + 'numeric' => ':attribute 的大小必须是 :size 。', 'file' => ':attribute 必须是 :size KB大小', 'string' => ':attribute 必须是 :size 个字符', - 'array' => ':attribute 必须是 :size 个字符', + 'array' => ':attribute 必须包含 :size 个项。', ], - 'string' => ':attribute 必须包含 :size 个项。', + 'string' => ':attribute 必须是一个字符串。', 'timezone' => ':attribute 必须是个有效的区域。', 'unique' => ':attribute 已经被占用', 'url' => ':attribute 的格式无效', diff --git a/resources/lang/zh-TW/cachet.php b/resources/lang/zh-TW/cachet.php index 5fe154481d0..bb3af4ff2db 100644 --- a/resources/lang/zh-TW/cachet.php +++ b/resources/lang/zh-TW/cachet.php @@ -14,6 +14,7 @@ 'components' => [ 'last_updated' => 'Last updated :timestamp', 'status' => [ + 0 => 'Unknown', 1 => '正常', 2 => '效能問題', 3 => '部分停止運作', @@ -22,18 +23,20 @@ 'group' => [ 'other' => 'Other Components', ], + 'select_all' => 'Select All', + 'deselect_all' => 'Deselect All', ], // Incidents 'incidents' => [ - 'none' => 'No incidents reported', - 'past' => '過去的事件', - 'previous_week' => '上一週', - 'next_week' => '下一週', - 'scheduled' => '排程維護', - 'scheduled_at' => ',於:timestamp', - 'status' => [ - 0 => '排程中的維護', // TODO: Hopefully remove this. + 'none' => 'No incidents reported', + 'past' => 'Past Incidents', + 'stickied' => 'Stickied Incidents', + 'scheduled' => 'Maintenance', + 'scheduled_at' => ',於:timestamp', + 'posted' => 'Posted :timestamp by :username', + 'posted_at' => 'Posted at :timestamp', + 'status' => [ 1 => '調查中', 2 => '已辨明', 3 => '警戒中', @@ -41,11 +44,20 @@ ], ], + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'Upcoming', + 1 => 'In Progress', + 2 => 'Complete', + ], + ], + // Service Status 'service' => [ - 'good' => '[0,1] System operational|[2,Inf] All systems are operational', - 'bad' => '[0,1] The system is currently experiencing issues|[2,Inf] Some systems are experiencing issues', - 'major' => '[0,1] The service experiencing a major outage|[2,Inf] Some systems are experiencing a major outage', + 'good' => '[0,1]System operational|[2,*]All systems are operational', + 'bad' => '[0,1]The system is experiencing issues|[2,*]Some systems are experiencing issues', + 'major' => '[0,1]The system is experiencing major issues|[2,*]Some systems are experiencing major issues', ], 'api' => [ @@ -57,65 +69,47 @@ 'metrics' => [ 'filter' => [ 'last_hour' => 'Last Hour', - 'hourly' => '最近12小時', - 'weekly' => '週', - 'monthly' => '月', + 'hourly' => 'Last 12 Hours', + 'weekly' => 'Week', + 'monthly' => 'Month', ], ], // Subscriber 'subscriber' => [ - 'subscribe' => '訂閱最新的狀態更新。', - 'button' => '訂閱', - 'manage' => [ - 'no_subscriptions' => 'You\'re currently subscribed to all updates.', - 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'subscribe' => 'Subscribe to status changes and incident updates', + 'unsubscribe' => 'Unsubscribe', + 'button' => 'Subscribe', + 'manage_subscription' => 'Manage subscription', + 'manage' => [ + 'notifications' => '通知', + 'notifications_for' => 'Manage notifications for', + 'no_subscriptions' => 'You\'re currently subscribed to all updates.', + 'update_subscription' => 'Update Subscription', + 'my_subscriptions' => 'You\'re currently subscribed to the following updates.', + 'manage_at_link' => 'Manage your subscriptions at :link', ], 'email' => [ - 'subscribe' => '訂閱 電子郵件 系統狀態更新。', - 'subscribed' => '您已經訂閱電子郵件通知,請檢查您的電子郵件,確認您的訂閱。', - 'verified' => '您的電子郵件訂閱已確認。謝謝!', - 'manage' => 'Manage your subscription', - 'unsubscribe' => '取消電子郵件訂閱。', - 'unsubscribed' => '您的電子郵件訂閱已取消。', - 'failure' => '郵件訂閱失敗。', - 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', - 'verify' => [ - 'text' => "Please confirm your email subscription to :app_name status updates.\n:link", - 'html' => '

Please confirm your email subscription to :app_name status updates.

', - 'button' => 'Confirm Subscription', - ], - 'maintenance' => [ - 'subject' => '[Maintenance Scheduled] :name', - ], - 'incident' => [ - 'subject' => '[New Incident] :status: :name', - ], - 'component' => [ - 'subject' => 'Component Status Update', - 'text' => 'The component :component_name has seen a status change. The component is now at :component_human_status.\nThank you, :app_name', - 'html' => '

The component :component_name has seen a status change. The component is now at :component_human_status.

Thank you, :app_name

', - 'tooltip-title' => 'Subscribe to notifications for :component_name.', - ], - ], - ], - - 'users' => [ - 'email' => [ - 'invite' => [ - 'text' => "您已被邀請加入 :app_name 團隊的狀態頁, 請點擊以下鏈接進行註冊。\n:link\n謝謝, :app_name", - 'html' => '

您已被邀請加入 :app_name 團隊的狀態頁, 請點擊以下鏈接進行註冊。

:link

謝謝, :app_name

', - ], + 'manage_subscription' => 'We\'ve sent you an email, please click the link to manage your subscription', + 'subscribe' => 'Subscribe to email updates.', + 'subscribed' => 'You\'ve been subscribed to email notifications, please check your email to confirm your subscription.', + 'updated-subscribe' => 'You\'ve succesfully updated your subscriptions.', + 'verified' => 'Your email subscription has been confirmed. Thank you!', + 'manage' => 'Manage your subscription', + 'unsubscribe' => 'Unsubscribe from email updates.', + 'unsubscribed' => 'Your email subscription has been cancelled.', + 'failure' => 'Something went wrong with the subscription.', + 'already-subscribed' => 'Cannot subscribe :email because they\'re already subscribed.', ], ], 'signup' => [ - 'title' => '註冊', + 'title' => 'Sign Up', 'username' => '用戶名', 'email' => '電郵地址', 'password' => '密碼', - 'success' => '您的賬號已註冊成功。', - 'failure' => '註冊失敗。', + 'success' => 'Your account has been created.', + 'failure' => 'Something went wrong with the signup.', ], 'system' => [ @@ -128,17 +122,27 @@ 'subscribe' => [ 'title' => 'Subscribe to component updates', 'body' => 'Enter your email address to subscribe to updates for this component. If you\'re already subscribed, you\'ll already receive emails for this component.', - 'button' => '訂閱', + 'button' => 'Subscribe', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'Details and updates about the :name incident that occurred on :date', + 'schedule' => 'Details about the scheduled maintenance period :name starting :startDate', + 'subscribe' => 'Subscribe to :app in order to receive updates of incidents and scheduled maintenance periods', + 'overview' => 'Stay up to date with the latest service updates from :app.', ], ], // Other 'home' => 'Home', - 'description' => 'Stay up to date with the latest service updates from :app.', 'powered_by' => 'Powered by Cachet.', - 'about_this_site' => '關於此站點', - 'rss-feed' => 'RSS 訂閱', - 'atom-feed' => 'Atom 訂閱', + 'timezone' => 'Times are shown in :timezone.', + 'about_this_site' => 'About This Site', + 'rss-feed' => 'RSS', + 'atom-feed' => 'Atom', 'feed' => 'Status 訂閱', ]; diff --git a/resources/lang/zh-TW/dashboard.php b/resources/lang/zh-TW/dashboard.php index 64515a2f13a..9725ac86735 100644 --- a/resources/lang/zh-TW/dashboard.php +++ b/resources/lang/zh-TW/dashboard.php @@ -11,22 +11,38 @@ return [ - 'dashboard' => '儀表板', + 'dashboard' => '儀表板', + 'writeable_settings' => 'The Cachet settings directory is not writeable. Please make sure that ./bootstrap/cachet is writeable by the web server.', // Incidents 'incidents' => [ - 'title' => '事件與排程', + 'title' => 'Incidents & Maintenance', 'incidents' => '事件', - 'logged' => '{0} 做得好,沒有任何事件。|你記錄了一個事件。|你回報了 :count 個事件。', + 'logged' => '{0}There are no incidents, good work.|[1]You have logged one incident.|[2,*]You have reported :count incidents.', 'incident-create-template' => '新增模板', 'incident-templates' => '事件模板', + 'updates' => [ + 'title' => 'Incident updates for :incident', + 'count' => '{0}Zero Updates|[1]One Update|[2]Two Updates|[3,*]Several Updates', + 'add' => [ + 'title' => 'Create new incident update', + 'success' => 'Your new incident update has been created.', + 'failure' => 'Something went wrong with the incident update.', + ], + 'edit' => [ + 'title' => 'Edit incident update', + 'success' => 'The incident update has been updated.', + 'failure' => 'Something went wrong updating the incident update', + ], + ], + 'reported_by' => 'Reported :timestamp by :user', 'add' => [ - 'title' => '添加事件', + 'title' => 'Report an incident', 'success' => 'Incident added.', 'failure' => 'There was an error adding the incident, please try again.', ], 'edit' => [ - 'title' => '編輯事件', + 'title' => 'Edit an incident', 'success' => '事件更新成功。', 'failure' => 'There was an error editing the incident, please try again.', ], @@ -39,13 +55,13 @@ 'templates' => [ 'title' => '事件模板', 'add' => [ - 'title' => '添加事件模板', - 'message' => 'You should add an incident template.', + 'title' => 'Create an incident template', + 'message' => 'Create your first incident template.', 'success' => 'Your new incident template has been created.', 'failure' => 'Something went wrong with the incident template.', ], 'edit' => [ - 'title' => '編輯模板', + 'title' => 'Edit Template', 'success' => 'The incident template has been updated.', 'failure' => 'Something went wrong updating the incident template', ], @@ -58,22 +74,22 @@ // Incident Maintenance 'schedule' => [ - 'schedule' => '排程維護', - 'logged' => '{0} There are no schedules, good work.|You have logged one schedule.|You have reported :count schedules.', + 'schedule' => 'Maintenance', + 'logged' => '{0}There has been no Maintenance, good work.|[1]You have logged one schedule.|[2,*]You have reported :count schedules.', 'scheduled_at' => '排程於 :timestamp', 'add' => [ - 'title' => 'Add Scheduled Maintenance', - 'success' => 'Schedule added.', - 'failure' => 'Something went wrong adding the schedule, please try again.', + 'title' => 'Add Maintenance', + 'success' => 'Maintenance added.', + 'failure' => 'Something went wrong adding the Maintenance, please try again.', ], 'edit' => [ - 'title' => 'Edit Scheduled Maintenance', - 'success' => 'Schedule has been updated!', - 'failure' => 'Something went wrong editing the schedule, please try again.', + 'title' => 'Edit Maintenance', + 'success' => 'Maintenance has been updated!', + 'failure' => 'Something went wrong editing the Maintenance, please try again.', ], 'delete' => [ - 'success' => 'The scheduled maintenance has been deleted and will not show on your status page.', - 'failure' => 'The scheduled maintenance could not be deleted, please try again.', + 'success' => 'The Maintenance has been deleted and will not show on your status page.', + 'failure' => 'The Maintenance could not be deleted, please try again.', ], ], @@ -83,15 +99,15 @@ 'component_statuses' => '組件狀態', 'listed_group' => '屬於:name組', 'add' => [ - 'title' => '添加組件', + 'title' => 'Add a component', 'message' => '你應該先新增一個組件。', 'success' => 'Component created.', - 'failure' => 'Something went wrong with the component, please try again.', + 'failure' => 'Something went wrong with the component group, please try again.', ], 'edit' => [ - 'title' => '編輯組件', + 'title' => 'Edit a component', 'success' => 'Component updated.', - 'failure' => 'Something went wrong with the component, please try again.', + 'failure' => 'Something went wrong with the component group, please try again.', ], 'delete' => [ 'success' => 'The component has been deleted!', @@ -101,14 +117,14 @@ // Component groups 'groups' => [ 'groups' => '組件組|組件組', - 'no_components' => '您應添加壹個組件分組。', + 'no_components' => 'You should add a component group.', 'add' => [ - 'title' => '添加組件分組', + 'title' => 'Add a component group', 'success' => 'Component group added.', 'failure' => 'Something went wrong with the component group, please try again.', ], 'edit' => [ - 'title' => '編輯組件分組', + 'title' => 'Edit a component group', 'success' => 'Component group updated.', 'failure' => 'Something went wrong with the component group, please try again.', ], @@ -123,13 +139,13 @@ 'metrics' => [ 'metrics' => '效能度量', 'add' => [ - 'title' => '添加圖表', + 'title' => 'Create a metric', 'message' => 'You should add a metric.', 'success' => 'Metric created.', 'failure' => 'Something went wrong with the metric, please try again.', ], 'edit' => [ - 'title' => '編輯圖表', + 'title' => 'Edit a metric', 'success' => 'Metric updated.', 'failure' => 'Something went wrong with the metric, please try again.', ], @@ -140,21 +156,23 @@ ], // Subscribers 'subscribers' => [ - 'subscribers' => '訂閱者', - 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', - 'verified' => '已認證', - 'not_verified' => '未認證', - 'subscriber' => ':email, subscribed :date', - 'no_subscriptions' => 'Subscribed to all updates', - 'add' => [ - 'title' => '添加訂閱者', - 'success' => '訂閱者已添加成功.', + 'subscribers' => 'Subscribers', + 'description' => 'Subscribers will receive email updates when incidents are created or components are updated.', + 'description_disabled' => 'To use this feature, you need allow people to signup for notifications.', + 'verified' => 'Verified', + 'not_verified' => 'Not verified', + 'subscriber' => ':email, subscribed :date', + 'no_subscriptions' => 'Subscribed to all updates', + 'global' => 'Globally subscribed', + 'add' => [ + 'title' => 'Add a new subscriber', + 'success' => 'Subscriber has been added!', 'failure' => 'Something went wrong adding the subscriber, please try again.', 'help' => 'Enter each subscriber on a new line.', ], 'edit' => [ - 'title' => '更新訂閱者', - 'success' => '訂閱者信息已更新.', + 'title' => 'Update subscriber', + 'success' => 'Subscriber has been updated!', 'failure' => 'Something went wrong editing the subscriber, please try again.', ], ], @@ -166,22 +184,22 @@ 'profile' => '個人檔案', 'description' => '團隊成員可以新增、修改、或更新組件和事件。', 'add' => [ - 'title' => '添加團隊成員', + 'title' => 'Add a new team member', 'success' => 'Team member added.', 'failure' => 'The team member could not be added, please try again.', ], 'edit' => [ - 'title' => '更新配置文件', + 'title' => 'Update profile', 'success' => 'Profile updated.', 'failure' => 'Something went wrong updating the profile, please try again.', ], 'delete' => [ - 'success' => '團隊成員已刪除.', + 'success' => 'Team member has been deleted and will no longer have access to the dashboard!', 'failure' => 'The team member could not be added, please try again.', ], 'invite' => [ - 'title' => '邀請團隊成員', - 'success' => '團隊成員已邀請成功.', + 'title' => 'Invite a new team member', + 'success' => 'An invite has been sent', 'failure' => 'The invite could not be sent, please try again.', ], ], @@ -195,16 +213,27 @@ 'too-big' => '檔案大小過大。請嘗試上載一張大小小於 :size 的圖片。', ], 'analytics' => [ - 'analytics' => '第三方統計', + 'analytics' => 'Analytics', + ], + 'log' => [ + 'log' => 'Log', ], 'localization' => [ - 'localization' => '國際化', + 'localization' => 'Localization', ], 'customization' => [ 'customization' => 'Customization', 'header' => 'Custom Header HTML', 'footer' => 'Custom Footer HTML', ], + 'mail' => [ + 'mail' => 'Mail', + 'test' => 'Test', + 'email' => [ + 'subject' => 'Test notification from Cachet', + 'body' => 'This is a test notification from Cachet.', + ], + ], 'security' => [ 'security' => '安全', 'two-factor' => '下列用戶未使用雙重認證', @@ -254,21 +283,21 @@ 'support' => 'Support Cachet', 'support_subtitle' => 'Check out our Patreon page!', 'news' => 'Latest News', - 'news_subtitle' => 'Get the latest updates', + 'news_subtitle' => 'Get the latest update', ], // Welcome modal 'welcome' => [ - 'welcome' => 'Welcome to your new status page!', + 'welcome' => 'Welcome to your new status page, :username!', 'message' => '你的狀態頁快準備好了!不過你也許先想調整一下以下設定。', - 'close' => 'Take me straight to my dashboard', + 'close' => 'I\'m good thanks!', 'steps' => [ 'component' => '新增組件', 'incident' => '新增事件', 'customize' => '定制化', 'team' => '新增用戶', 'api' => '生成 API 密鑰', - 'two-factor' => '雙因素身份驗證', + 'two-factor' => 'Setup Two Factor Authentication', ], ], diff --git a/resources/lang/zh-TW/forms.php b/resources/lang/zh-TW/forms.php index 7d4bb127574..c1668f98a32 100644 --- a/resources/lang/zh-TW/forms.php +++ b/resources/lang/zh-TW/forms.php @@ -21,8 +21,14 @@ 'site_timezone' => '選擇你的時區', 'site_locale' => '選擇你的語言', 'enable_google2fa' => '啟用 Google 兩步驗證', - 'cache_driver' => '緩存驅動', - 'session_driver' => '會話驅動', + 'cache_driver' => 'Cache Driver', + 'queue_driver' => 'Queue Driver', + 'session_driver' => 'Session Driver', + 'mail_driver' => 'Mail Driver', + 'mail_host' => 'Mail Host', + 'mail_address' => 'Mail From Address', + 'mail_username' => 'Mail Username', + 'mail_password' => 'Mail Password', ], // Login form fields @@ -33,8 +39,9 @@ '2fauth' => '驗證碼', 'invalid' => 'Invalid username or password', 'invalid-token' => '錯誤的驗證碼', - 'cookies' => '您必須啟用 cookies 來進行登錄。', + 'cookies' => 'You must enable cookies to login.', 'rate-limit' => 'Rate limit exceeded.', + 'remember_me' => 'Remember me', ], // Incidents form fields @@ -42,18 +49,36 @@ 'name' => '名稱', 'status' => '狀態', 'component' => '組件', + 'component_status' => 'Component Status', 'message' => '訊息', 'message-help' => '你可以使用 Markdown 。', - 'scheduled_at' => '排期在什麼時候進行維護?', - 'incident_time' => '這次事件是什麽時候發生的?', - 'notify_subscribers' => '通知訂閱者', + 'occurred_at' => 'When did this incident occur?', + 'notify_subscribers' => 'Notify subscribers?', + 'notify_disabled' => 'Due to scheduled maintenance, notifications about this incident or its components will be suppressed.', 'visibility' => 'Incident Visibility', - 'public' => '公共可見', - 'logged_in_only' => '僅登錄用戶可見', + 'stick_status' => 'Stick Incident', + 'stickied' => 'Stickied', + 'not_stickied' => 'Not Stickied', + 'public' => 'Viewable by public', + 'logged_in_only' => 'Only visible to logged in users', 'templates' => [ 'name' => '名稱', 'template' => '範本', - 'twig' => 'Incident Templates can make use of the Twig templating language.', + 'twig' => 'Incident Templates can make use of the Twig templating language.', + ], + ], + + 'schedules' => [ + 'name' => '名稱', + 'status' => '狀態', + 'message' => '訊息', + 'message-help' => '你可以使用 Markdown 。', + 'scheduled_at' => 'When is this maintenance scheduled for?', + 'completed_at' => 'When did this maintenance complete?', + 'templates' => [ + 'name' => '名稱', + 'template' => '範本', + 'twig' => 'Incident Templates can make use of the Twig templating language.', ], ], @@ -66,31 +91,53 @@ 'link' => '連結', 'tags' => '標籤', 'tags-help' => '請以半角逗號分隔。', - 'enabled' => '啟用', + 'enabled' => 'Component enabled?', 'groups' => [ - 'name' => '名稱', - 'collapsing' => 'Choose visibility of the group', - 'visible' => 'Always expanded', - 'collapsed' => 'Collapse the group by default', - 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'name' => '名稱', + 'collapsing' => 'Expand/Collapse options', + 'visible' => 'Always expanded', + 'collapsed' => 'Collapse the group by default', + 'collapsed_incident' => 'Collapse the group, but expand if there are issues', + 'visibility' => 'Visibility', + 'visibility_public' => 'Visible to public', + 'visibility_authenticated' => 'Visible only to logged in users', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => '名稱', + 'description' => '描述', + 'start_at' => 'Schedule start time', + 'timezone' => 'Timezone', + 'schedule_frequency' => 'Schedule frequency (in seconds)', + 'completion_latency' => 'Completion latency (in seconds)', + 'group' => '組別', + 'active' => 'Active?', + 'groups' => [ + 'name' => 'Group Name', ], ], // Metric form fields 'metrics' => [ - 'name' => '名稱', - 'suffix' => '後綴', - 'description' => '描述', - 'description-help' => '你也可以使用 Markdown', - 'display-chart' => '在狀態頁上顯示圖表?', - 'default-value' => '默認值', - 'calc_type' => '圖表計算方法', - 'type_sum' => '總和', - 'type_avg' => '平均', - 'places' => '小數點位數', - 'default_view' => 'Default view', - 'threshold' => 'How many minutes of threshold between metric points?', + 'name' => '名稱', + 'suffix' => '後綴', + 'description' => '描述', + 'description-help' => '你可以使用 Markdown 。', + 'display-chart' => '在狀態頁上顯示圖表?', + 'default-value' => 'Default value', + 'calc_type' => 'Calculation of metrics', + 'type_sum' => '總和', + 'type_avg' => '平均', + 'places' => 'Decimal places', + 'default_view' => 'Default view', + 'threshold' => 'How many minutes of threshold between metric points?', + 'visibility' => 'Visibility', + 'visibility_authenticated' => 'Visible to authenticated users', + 'visibility_public' => 'Visible to everybody', + 'visibility_hidden' => 'Always hidden', 'points' => [ 'value' => '值', @@ -99,52 +146,61 @@ // Settings 'settings' => [ - /// Application setup + // Application setup 'app-setup' => [ - 'site-name' => '網站名稱', - 'site-url' => '網站 URL', - 'display-graphs' => '在狀態頁上顯示圖片?', - 'about-this-page' => '關於本站', - 'days-of-incidents' => '顯示多少天前的事件?', - 'banner' => 'Banner Image', - 'banner-help' => '橫幅寬度建議少於 930px 。', - 'subscribers' => '允許用戶訂閱郵件通知嗎?', - 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'site-name' => '網站名稱', + 'site-url' => '網站 URL', + 'display-graphs' => '在狀態頁上顯示圖片?', + 'about-this-page' => '關於本站', + 'days-of-incidents' => '顯示多少天前的事件?', + 'time_before_refresh' => 'Status page refresh rate (in seconds)', + 'major_outage_rate' => 'Major outage threshold (in %)', + 'banner' => 'Banner Image', + 'banner-help' => "It's recommended that you upload files no bigger than 930px wide", + 'subscribers' => 'Allow people to signup to email notifications?', + 'suppress_notifications_in_maintenance' => 'Suppress notifications when incident occurs during maintenance period?', + 'skip_subscriber_verification' => 'Skip verifying of users? (Be warned, you could be spammed)', + 'automatic_localization' => 'Automatically localise your status page to your visitor\'s language?', + 'enable_external_dependencies' => 'Enable Third Party Dependencies (Google Fonts, Trackers, etc...)', + 'show_timezone' => 'Show the timezone the status page is running in', + 'only_disrupted_days' => 'Only show days containing incidents in the timeline?', ], 'analytics' => [ - 'analytics_google' => 'Google Analytics 代碼', - 'analytics_gosquared' => 'GoSquared Analytics 代碼', - 'analytics_piwik_url' => '輸入Piwik實例的URL(不含http(s)://)', - 'analytics_piwik_siteid' => 'Piwik 的站點 id', + 'analytics_google' => 'Google Analytics code', + 'analytics_gosquared' => 'GoSquared Analytics code', + 'analytics_piwik_url' => 'URL of your Piwik instance', + 'analytics_piwik_siteid' => 'Piwik\'s site id', ], 'localization' => [ - 'site-timezone' => '站點時區', - 'site-locale' => '站點語言', - 'date-format' => '日期格式', - 'incident-date-format' => '事件的時間戳格式', + 'site-timezone' => 'Site timezone', + 'site-locale' => 'Site language', + 'date-format' => 'Date format', + 'incident-date-format' => 'Incident timestamp format', ], 'security' => [ - 'allowed-domains' => '允許的域', - 'allowed-domains-help' => '請以半角逗號分隔。以上域名將會自動允許訪問。', + 'allowed-domains' => 'Allowed domains', + 'allowed-domains-help' => '請以半角逗號分隔。以上域名將會自動允許訪問。', + 'always-authenticate' => 'Always authenticate', + 'always-authenticate-help' => 'Require login to view any Cachet page', ], 'stylesheet' => [ 'custom-css' => 'Custom Stylesheet', ], 'theme' => [ - 'background-color' => 'Background Color', - 'background-fills' => '區塊填充色(組件, 事件, 頁尾)', - 'banner-background-color' => '横幅背景色', - 'banner-padding' => '横幅Padding值', - 'fullwidth-banner' => '横幅全寬?', - 'text-color' => 'Text Color', - 'dashboard-login' => '在頁尾顯示 管理後臺 的入口?', + 'background-color' => 'Background color', + 'background-fills' => 'Background fills (components, incidents, footer)', + 'banner-background-color' => 'Banner background color', + 'banner-padding' => 'Banner padding', + 'fullwidth-banner' => 'Enable full width banner?', + 'text-color' => 'Text color', + 'dashboard-login' => 'Show dashboard button in the footer?', 'reds' => '紅(用於錯誤類提示)', - 'blues' => '藍 (用於信息類提示)', - 'greens' => '綠 (用於成功類提示)', - 'yellows' => '黃 (用於警告類提示)', - 'oranges' => '橙 (用於通知類提示)', - 'metrics' => '圖表填充色', - 'links' => '鏈接', + 'blues' => 'Blue (used for information)', + 'greens' => 'Green (used for success)', + 'yellows' => 'Yellow (used for alerts)', + 'oranges' => 'Orange (used for notices)', + 'metrics' => 'Metrics fill', + 'links' => 'Links', ], ], @@ -154,33 +210,43 @@ 'password' => '密碼', 'api-token' => 'API 密鑰', 'api-token-help' => '重新生成 API 密鑰將會導致現存的應用程序無法訪問 Cachet 。', - 'gravatar' => '修改您的 Gravatar 頭像。', - 'user_level' => '用戶等級', + 'gravatar' => 'Change your profile picture at Gravatar.', + 'user_level' => 'User Level', 'levels' => [ - 'admin' => '管理員', - 'user' => '普通用戶', + 'admin' => 'Admin', + 'user' => 'User', ], '2fa' => [ 'help' => '啟用兩步認證會使得你的賬戶更加安全。您需要下載 Google Authenticator 或類似的應用程序到您的設備上。啓用後,你需要提供由該應用程序生成的驗證碼方可登錄。', ], 'team' => [ - 'description' => '請輸入您要邀請的團隊成員的郵件地址:', - 'email' => 'Email #:id', + 'description' => 'Invite your team members by entering their email addresses here.', + 'email' => 'Your Team Members Email Address', ], ], + 'general' => [ + 'timezone' => 'Select Timezone', + ], + + 'seo' => [ + 'title' => 'SEO Title', + 'description' => 'SEO Description', + ], + // Buttons - 'add' => '增加', - 'save' => '儲存', - 'update' => '更新', - 'create' => '建立', - 'edit' => '編輯', - 'delete' => '刪除', - 'submit' => '送出', - 'cancel' => '取消', - 'remove' => '移除', - 'invite' => '邀請', - 'signup' => '註冊', + 'add' => '增加', + 'save' => '儲存', + 'update' => '更新', + 'create' => '建立', + 'edit' => '編輯', + 'delete' => '刪除', + 'submit' => '送出', + 'cancel' => '取消', + 'remove' => '移除', + 'invite' => 'Invite', + 'signup' => 'Sign Up', + 'manage_updates' => 'Manage Updates', // Other 'optional' => '* 可選項目', diff --git a/resources/lang/zh-TW/notifications.php b/resources/lang/zh-TW/notifications.php new file mode 100644 index 00000000000..4d98ec751ca --- /dev/null +++ b/resources/lang/zh-TW/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'Component Status Updated', + 'greeting' => 'A component\'s status was updated!', + 'content' => ':name status changed from :old_status to :new_status.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Component Status Updated', + 'content' => ':name status changed from :old_status to :new_status.', + ], + 'sms' => [ + 'content' => ':name status changed from :old_status to :new_status.', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Incident Reported', + 'greeting' => 'A new incident was reported at :app_name.', + 'content' => 'Incident :name was reported', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'Incident :name Reported', + 'content' => 'A new incident was reported at :app_name', + ], + 'sms' => [ + 'content' => 'A new incident was reported at :app_name.', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'Incident Updated', + 'content' => ':name was updated', + 'title' => ':name was updated to :new_status', + 'action' => 'View', + ], + 'slack' => [ + 'title' => ':name Updated', + 'content' => ':name was updated to :new_status', + ], + 'sms' => [ + 'content' => 'Incident :name was updated', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'New Schedule Created', + 'content' => ':name was scheduled for :date', + 'title' => 'A new scheduled maintenance was created.', + 'action' => 'View', + ], + 'slack' => [ + 'title' => 'New Schedule Created!', + 'content' => ':name was scheduled for :date', + ], + 'sms' => [ + 'content' => ':name was scheduled for :date', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'Verify Your Subscription', + 'content' => 'Click to verify your subscription to :app_name status page.', + 'title' => 'Verify your subscription to :app_name status page.', + 'action' => 'Verify', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'Manage Your Subscription', + 'content' => 'Click to manage your subscription to :app_name status page.', + 'title' => 'Click to manage your subscription to :app_name status page.', + 'action' => 'Manage subscription', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'Ping from Cachet!', + 'content' => 'This is a test notification from Cachet!', + 'title' => '🔔', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'Your invitation is inside...', + 'content' => 'You have been invited to join :app_name status page.', + 'title' => 'You\'re invited to join :app_name status page.', + 'action' => 'Accept', + ], + ], + ], +]; diff --git a/resources/lang/zh-TW/pagination.php b/resources/lang/zh-TW/pagination.php index 57b293ae7f6..0ee724cf086 100644 --- a/resources/lang/zh-TW/pagination.php +++ b/resources/lang/zh-TW/pagination.php @@ -22,7 +22,7 @@ | */ - 'previous' => '« 上一頁', - 'next' => '下一頁 »', + 'previous' => 'Previous', + 'next' => 'Next', ]; diff --git a/resources/lang/zh-TW/setup.php b/resources/lang/zh-TW/setup.php index 6db5de8bbc9..b7b4de9c9e9 100644 --- a/resources/lang/zh-TW/setup.php +++ b/resources/lang/zh-TW/setup.php @@ -13,9 +13,9 @@ 'setup' => '安裝', 'title' => '安裝 Cachet', 'service_details' => '服務詳細信息', - 'env_setup' => '环境设置', + 'env_setup' => 'Environment Setup', 'status_page_setup' => '設置狀態頁面', - 'show_support' => '您想支持Cachet么?', + 'show_support' => 'Show support for Cachet?', 'admin_account' => '管理員帳戶', 'complete_setup' => '完成安裝', 'completed' => '成功安裝 Cachet !', diff --git a/resources/lang/zh-TW/validation.php b/resources/lang/zh-TW/validation.php index 5f073e4380c..4305ac57c19 100644 --- a/resources/lang/zh-TW/validation.php +++ b/resources/lang/zh-TW/validation.php @@ -31,60 +31,60 @@ 'array' => ':attribute 必須是一個陣列', 'before' => ':attribute 必須在 :date 之前', 'between' => [ - 'numeric' => ':attribute 必須在 :date 之前', - 'file' => 'The :attribute must be between :min and :max.', - 'string' => 'The :attribute must be between :min and :max kilobytes.', + 'numeric' => 'The :attribute must be between :min and :max.', + 'file' => 'The :attribute must be between :min and :max kilobytes.', + 'string' => 'The :attribute must be between :min and :max characters.', 'array' => 'The :attribute must have between :min and :max items.', ], - 'boolean' => 'The :attribute must have between :min and :max items.', - 'confirmed' => 'The :attribute field must be true or false.', - 'date' => 'The :attribute confirmation does not match.', - 'date_format' => 'The :attribute is not a valid date.', - 'different' => 'The :attribute does not match the format :format.', - 'digits' => 'The :attribute and :other must be different.', - 'digits_between' => 'The :attribute must be :digits digits.', - 'email' => 'The :attribute must be between :min and :max digits.', - 'exists' => 'The :attribute must be a valid email address.', + 'boolean' => 'The :attribute field must be true or false.', + 'confirmed' => 'The :attribute confirmation does not match.', + 'date' => 'The :attribute is not a valid date.', + 'date_format' => 'The :attribute does not match the format :format.', + 'different' => 'The :attribute and :other must be different.', + 'digits' => 'The :attribute must be :digits digits.', + 'digits_between' => 'The :attribute must be between :min and :max digits.', + 'email' => 'The :attribute must be a valid email address.', + 'exists' => 'The selected :attribute is invalid.', 'distinct' => 'The :attribute field has a duplicate value.', - 'filled' => ':attribute 格式無效', + 'filled' => 'The :attribute field is required.', 'image' => ':attribute 必須是圖片', - 'in' => ':attribute 必須是圖片', + 'in' => 'The selected :attribute is invalid.', 'in_array' => 'The :attribute field does not exist in :other.', - 'integer' => 'The selected :attribute is invalid.', - 'ip' => 'The :attribute must be an integer.', + 'integer' => 'The :attribute must be an integer.', + 'ip' => 'The :attribute must be a valid IP address.', 'json' => 'The :attribute must be a valid JSON string.', 'max' => [ - 'numeric' => 'The :attribute must be a valid IP address.', - 'file' => 'The :attribute may not be greater than :max.', - 'string' => 'The :attribute may not be greater than :max kilobytes.', + 'numeric' => 'The :attribute may not be greater than :max.', + 'file' => 'The :attribute may not be greater than :max kilobytes.', + 'string' => 'The :attribute may not be greater than :max characters.', 'array' => 'The :attribute may not have more than :max items.', ], - 'mimes' => 'The :attribute may not have more than :max items.', + 'mimes' => 'The :attribute must be a file of type: :values.', 'min' => [ - 'numeric' => 'The :attribute must be a file of type: :values.', + 'numeric' => 'The :attribute must be at least :min.', 'file' => 'The :attribute must be at least :min kilobytes.', - 'string' => 'The :attribute must be at least :min kilobytes.', - 'array' => 'The :attribute must be at least :min characters.', + 'string' => 'The :attribute must be at least :min characters.', + 'array' => 'The :attribute must have at least :min items.', ], - 'not_in' => 'The :attribute must have at least :min items.', - 'numeric' => 'The selected :attribute is invalid.', + 'not_in' => 'The selected :attribute is invalid.', + 'numeric' => 'The :attribute must be a number.', 'present' => 'The :attribute field must be present.', - 'regex' => 'The :attribute must be a number.', - 'required' => ':attribute 格式無效', - 'required_if' => 'The :attribute field is required.', + 'regex' => ':attribute 格式無效', + 'required' => 'The :attribute field is required.', + 'required_if' => 'The :attribute field is required when :other is :value.', 'required_unless' => 'The :attribute field is required unless :other is in :values.', - 'required_with' => 'The :attribute field is required when :other is :value.', + 'required_with' => ':attribute 欄位在 :values 存在時,是必填的', 'required_with_all' => ':attribute 欄位在 :values 存在時,是必填的', - 'required_without' => ':attribute 欄位在 :values 存在時,是必填的', - 'required_without_all' => 'The :attribute field is required when :values is not present.', - 'same' => 'The :attribute field is required when none of :values are present.', + 'required_without' => 'The :attribute field is required when :values is not present.', + 'required_without_all' => 'The :attribute field is required when none of :values are present.', + 'same' => 'The :attribute and :other must match.', 'size' => [ - 'numeric' => 'The :attribute and :other must match.', + 'numeric' => 'The :attribute must be :size.', 'file' => 'The :attribute must be :size kilobytes.', 'string' => 'The :attribute must be :size characters.', - 'array' => 'The :attribute must be :size characters.', + 'array' => 'The :attribute must contain :size items.', ], - 'string' => 'The :attribute must contain :size items.', + 'string' => 'The :attribute must be a string.', 'timezone' => ':attribute 必須是有效的區域', 'unique' => ':attribute 已經被佔用', 'url' => ':attribute 格式無效', diff --git a/resources/lang/zu-ZA/cachet.php b/resources/lang/zu-ZA/cachet.php new file mode 100644 index 00000000000..4726b662bcc --- /dev/null +++ b/resources/lang/zu-ZA/cachet.php @@ -0,0 +1,148 @@ + [ + 'last_updated' => 'crwdns877:0crwdne877:0', + 'status' => [ + 0 => 'crwdns878:0crwdne878:0', + 1 => 'crwdns879:0crwdne879:0', + 2 => 'crwdns880:0crwdne880:0', + 3 => 'crwdns881:0crwdne881:0', + 4 => 'crwdns882:0crwdne882:0', + ], + 'group' => [ + 'other' => 'crwdns883:0crwdne883:0', + ], + 'select_all' => 'crwdns1510:0crwdne1510:0', + 'deselect_all' => 'crwdns1512:0crwdne1512:0', + ], + + // Incidents + 'incidents' => [ + 'none' => 'crwdns884:0crwdne884:0', + 'past' => 'crwdns885:0crwdne885:0', + 'stickied' => 'crwdns888:0crwdne888:0', + 'scheduled' => 'crwdns1395:0crwdne1395:0', + 'scheduled_at' => 'crwdns890:0crwdne890:0', + 'posted' => 'crwdns1540:0crwdne1540:0', + 'posted_at' => 'crwdns1396:0crwdne1396:0', + 'status' => [ + 1 => 'crwdns892:0crwdne892:0', + 2 => 'crwdns893:0crwdne893:0', + 3 => 'crwdns894:0crwdne894:0', + 4 => 'crwdns895:0crwdne895:0', + ], + ], + + // Schedule + 'schedules' => [ + 'status' => [ + 0 => 'crwdns896:0crwdne896:0', + 1 => 'crwdns897:0crwdne897:0', + 2 => 'crwdns898:0crwdne898:0', + ], + ], + + // Service Status + 'service' => [ + 'good' => 'crwdns1437:0crwdne1437:0', + 'bad' => 'crwdns1398:0crwdne1398:0', + 'major' => 'crwdns1399:0crwdne1399:0', + ], + + 'api' => [ + 'regenerate' => 'crwdns902:0crwdne902:0', + 'revoke' => 'crwdns903:0crwdne903:0', + ], + + // Metrics + 'metrics' => [ + 'filter' => [ + 'last_hour' => 'crwdns904:0crwdne904:0', + 'hourly' => 'crwdns905:0crwdne905:0', + 'weekly' => 'crwdns906:0crwdne906:0', + 'monthly' => 'crwdns907:0crwdne907:0', + ], + ], + + // Subscriber + 'subscriber' => [ + 'subscribe' => 'crwdns1520:0crwdne1520:0', + 'unsubscribe' => 'crwdns1447:0crwdne1447:0', + 'button' => 'crwdns909:0crwdne909:0', + 'manage_subscription' => 'crwdns1448:0crwdne1448:0', + 'manage' => [ + 'notifications' => 'crwdns1514:0crwdne1514:0', + 'notifications_for' => 'crwdns1516:0crwdne1516:0', + 'no_subscriptions' => 'crwdns910:0crwdne910:0', + 'update_subscription' => 'crwdns1518:0crwdne1518:0', + 'my_subscriptions' => 'crwdns911:0crwdne911:0', + 'manage_at_link' => 'crwdns1432:0crwdne1432:0', + ], + 'email' => [ + 'manage_subscription' => 'crwdns1530:0crwdne1530:0', + 'subscribe' => 'crwdns912:0crwdne912:0', + 'subscribed' => 'crwdns913:0crwdne913:0', + 'updated-subscribe' => 'crwdns1522:0crwdne1522:0', + 'verified' => 'crwdns914:0crwdne914:0', + 'manage' => 'crwdns915:0crwdne915:0', + 'unsubscribe' => 'crwdns916:0crwdne916:0', + 'unsubscribed' => 'crwdns917:0crwdne917:0', + 'failure' => 'crwdns918:0crwdne918:0', + 'already-subscribed' => 'crwdns919:0crwdne919:0', + ], + ], + + 'signup' => [ + 'title' => 'crwdns931:0crwdne931:0', + 'username' => 'crwdns932:0crwdne932:0', + 'email' => 'crwdns933:0crwdne933:0', + 'password' => 'crwdns934:0crwdne934:0', + 'success' => 'crwdns935:0crwdne935:0', + 'failure' => 'crwdns936:0crwdne936:0', + ], + + 'system' => [ + 'update' => 'crwdns937:0crwdne937:0', + ], + + // Modal + 'modal' => [ + 'close' => 'crwdns938:0crwdne938:0', + 'subscribe' => [ + 'title' => 'crwdns939:0crwdne939:0', + 'body' => 'crwdns940:0crwdne940:0', + 'button' => 'crwdns941:0crwdne941:0', + ], + ], + + // Meta descriptions + 'meta' => [ + 'description' => [ + 'incident' => 'crwdns1428:0crwdne1428:0', + 'schedule' => 'crwdns1429:0crwdne1429:0', + 'subscribe' => 'crwdns1430:0crwdne1430:0', + 'overview' => 'crwdns1431:0crwdne1431:0', + ], + ], + + // Other + 'home' => 'crwdns942:0crwdne942:0', + 'powered_by' => 'crwdns944:0crwdne944:0', + 'timezone' => 'crwdns945:0crwdne945:0', + 'about_this_site' => 'crwdns946:0crwdne946:0', + 'rss-feed' => 'crwdns947:0crwdne947:0', + 'atom-feed' => 'crwdns948:0crwdne948:0', + 'feed' => 'crwdns949:0crwdne949:0', + +]; diff --git a/resources/lang/zu-ZA/dashboard.php b/resources/lang/zu-ZA/dashboard.php new file mode 100644 index 00000000000..974517cdfbc --- /dev/null +++ b/resources/lang/zu-ZA/dashboard.php @@ -0,0 +1,304 @@ + 'crwdns950:0crwdne950:0', + 'writeable_settings' => 'crwdns951:0crwdne951:0', + + // Incidents + 'incidents' => [ + 'title' => 'crwdns1400:0crwdne1400:0', + 'incidents' => 'crwdns953:0crwdne953:0', + 'logged' => 'crwdns1441:0{0}crwdnd1441:0[1]crwdne1441:0', + 'incident-create-template' => 'crwdns955:0crwdne955:0', + 'incident-templates' => 'crwdns956:0crwdne956:0', + 'updates' => [ + 'title' => 'crwdns1402:0crwdne1402:0', + 'count' => 'crwdns1439:0{0}crwdnd1439:0[1]crwdnd1439:0[2]crwdne1439:0', + 'add' => [ + 'title' => 'crwdns1404:0crwdne1404:0', + 'success' => 'crwdns1405:0crwdne1405:0', + 'failure' => 'crwdns1406:0crwdne1406:0', + ], + 'edit' => [ + 'title' => 'crwdns1407:0crwdne1407:0', + 'success' => 'crwdns1408:0crwdne1408:0', + 'failure' => 'crwdns1409:0crwdne1409:0', + ], + ], + 'reported_by' => 'crwdns1542:0crwdne1542:0', + 'add' => [ + 'title' => 'crwdns958:0crwdne958:0', + 'success' => 'crwdns959:0crwdne959:0', + 'failure' => 'crwdns960:0crwdne960:0', + ], + 'edit' => [ + 'title' => 'crwdns961:0crwdne961:0', + 'success' => 'crwdns962:0crwdne962:0', + 'failure' => 'crwdns963:0crwdne963:0', + ], + 'delete' => [ + 'success' => 'crwdns964:0crwdne964:0', + 'failure' => 'crwdns965:0crwdne965:0', + ], + + // Incident templates + 'templates' => [ + 'title' => 'crwdns968:0crwdne968:0', + 'add' => [ + 'title' => 'crwdns969:0crwdne969:0', + 'message' => 'crwdns1443:0crwdne1443:0', + 'success' => 'crwdns971:0crwdne971:0', + 'failure' => 'crwdns972:0crwdne972:0', + ], + 'edit' => [ + 'title' => 'crwdns973:0crwdne973:0', + 'success' => 'crwdns974:0crwdne974:0', + 'failure' => 'crwdns975:0crwdne975:0', + ], + 'delete' => [ + 'success' => 'crwdns976:0crwdne976:0', + 'failure' => 'crwdns977:0crwdne977:0', + ], + ], + ], + + // Incident Maintenance + 'schedule' => [ + 'schedule' => 'crwdns1410:0crwdne1410:0', + 'logged' => 'crwdns1440:0{0}crwdnd1440:0[1]crwdne1440:0', + 'scheduled_at' => 'crwdns980:0crwdne980:0', + 'add' => [ + 'title' => 'crwdns1412:0crwdne1412:0', + 'success' => 'crwdns1413:0crwdne1413:0', + 'failure' => 'crwdns1414:0crwdne1414:0', + ], + 'edit' => [ + 'title' => 'crwdns1415:0crwdne1415:0', + 'success' => 'crwdns1416:0crwdne1416:0', + 'failure' => 'crwdns1417:0crwdne1417:0', + ], + 'delete' => [ + 'success' => 'crwdns1418:0crwdne1418:0', + 'failure' => 'crwdns1419:0crwdne1419:0', + ], + ], + + // Components + 'components' => [ + 'components' => 'crwdns989:0crwdne989:0', + 'component_statuses' => 'crwdns990:0crwdne990:0', + 'listed_group' => 'crwdns991:0crwdne991:0', + 'add' => [ + 'title' => 'crwdns992:0crwdne992:0', + 'message' => 'crwdns993:0crwdne993:0', + 'success' => 'crwdns994:0crwdne994:0', + 'failure' => 'crwdns995:0crwdne995:0', + ], + 'edit' => [ + 'title' => 'crwdns996:0crwdne996:0', + 'success' => 'crwdns997:0crwdne997:0', + 'failure' => 'crwdns998:0crwdne998:0', + ], + 'delete' => [ + 'success' => 'crwdns999:0crwdne999:0', + 'failure' => 'crwdns1000:0crwdne1000:0', + ], + + // Component groups + 'groups' => [ + 'groups' => 'crwdns1001:0crwdne1001:0', + 'no_components' => 'crwdns1002:0crwdne1002:0', + 'add' => [ + 'title' => 'crwdns1003:0crwdne1003:0', + 'success' => 'crwdns1004:0crwdne1004:0', + 'failure' => 'crwdns1005:0crwdne1005:0', + ], + 'edit' => [ + 'title' => 'crwdns1006:0crwdne1006:0', + 'success' => 'crwdns1007:0crwdne1007:0', + 'failure' => 'crwdns1008:0crwdne1008:0', + ], + 'delete' => [ + 'success' => 'crwdns1009:0crwdne1009:0', + 'failure' => 'crwdns1010:0crwdne1010:0', + ], + ], + ], + + // Metrics + 'metrics' => [ + 'metrics' => 'crwdns1011:0crwdne1011:0', + 'add' => [ + 'title' => 'crwdns1012:0crwdne1012:0', + 'message' => 'crwdns1013:0crwdne1013:0', + 'success' => 'crwdns1014:0crwdne1014:0', + 'failure' => 'crwdns1015:0crwdne1015:0', + ], + 'edit' => [ + 'title' => 'crwdns1016:0crwdne1016:0', + 'success' => 'crwdns1017:0crwdne1017:0', + 'failure' => 'crwdns1018:0crwdne1018:0', + ], + 'delete' => [ + 'success' => 'crwdns1019:0crwdne1019:0', + 'failure' => 'crwdns1020:0crwdne1020:0', + ], + ], + // Subscribers + 'subscribers' => [ + 'subscribers' => 'crwdns1021:0crwdne1021:0', + 'description' => 'crwdns1022:0crwdne1022:0', + 'description_disabled' => 'crwdns1420:0crwdne1420:0', + 'verified' => 'crwdns1023:0crwdne1023:0', + 'not_verified' => 'crwdns1024:0crwdne1024:0', + 'subscriber' => 'crwdns1025:0crwdne1025:0', + 'no_subscriptions' => 'crwdns1026:0crwdne1026:0', + 'global' => 'crwdns1421:0crwdne1421:0', + 'add' => [ + 'title' => 'crwdns1027:0crwdne1027:0', + 'success' => 'crwdns1028:0crwdne1028:0', + 'failure' => 'crwdns1029:0crwdne1029:0', + 'help' => 'crwdns1030:0crwdne1030:0', + ], + 'edit' => [ + 'title' => 'crwdns1031:0crwdne1031:0', + 'success' => 'crwdns1032:0crwdne1032:0', + 'failure' => 'crwdns1033:0crwdne1033:0', + ], + ], + + // Team + 'team' => [ + 'team' => 'crwdns1034:0crwdne1034:0', + 'member' => 'crwdns1035:0crwdne1035:0', + 'profile' => 'crwdns1036:0crwdne1036:0', + 'description' => 'crwdns1325:0crwdne1325:0', + 'add' => [ + 'title' => 'crwdns1038:0crwdne1038:0', + 'success' => 'crwdns1039:0crwdne1039:0', + 'failure' => 'crwdns1040:0crwdne1040:0', + ], + 'edit' => [ + 'title' => 'crwdns1041:0crwdne1041:0', + 'success' => 'crwdns1042:0crwdne1042:0', + 'failure' => 'crwdns1043:0crwdne1043:0', + ], + 'delete' => [ + 'success' => 'crwdns1044:0crwdne1044:0', + 'failure' => 'crwdns1045:0crwdne1045:0', + ], + 'invite' => [ + 'title' => 'crwdns1046:0crwdne1046:0', + 'success' => 'crwdns1047:0crwdne1047:0', + 'failure' => 'crwdns1048:0crwdne1048:0', + ], + ], + + // Settings + 'settings' => [ + 'settings' => 'crwdns1049:0crwdne1049:0', + 'app-setup' => [ + 'app-setup' => 'crwdns1050:0crwdne1050:0', + 'images-only' => 'crwdns1051:0crwdne1051:0', + 'too-big' => 'crwdns1052:0crwdne1052:0', + ], + 'analytics' => [ + 'analytics' => 'crwdns1053:0crwdne1053:0', + ], + 'log' => [ + 'log' => 'crwdns1054:0crwdne1054:0', + ], + 'localization' => [ + 'localization' => 'crwdns1055:0crwdne1055:0', + ], + 'customization' => [ + 'customization' => 'crwdns1056:0crwdne1056:0', + 'header' => 'crwdns1057:0crwdne1057:0', + 'footer' => 'crwdns1058:0crwdne1058:0', + ], + 'mail' => [ + 'mail' => 'crwdns1059:0crwdne1059:0', + 'test' => 'crwdns1060:0crwdne1060:0', + 'email' => [ + 'subject' => 'crwdns1061:0crwdne1061:0', + 'body' => 'crwdns1062:0crwdne1062:0', + ], + ], + 'security' => [ + 'security' => 'crwdns1063:0crwdne1063:0', + 'two-factor' => 'crwdns1064:0crwdne1064:0', + ], + 'stylesheet' => [ + 'stylesheet' => 'crwdns1065:0crwdne1065:0', + ], + 'theme' => [ + 'theme' => 'crwdns1066:0crwdne1066:0', + ], + 'edit' => [ + 'success' => 'crwdns1067:0crwdne1067:0', + 'failure' => 'crwdns1068:0crwdne1068:0', + ], + 'credits' => [ + 'credits' => 'crwdns1069:0crwdne1069:0', + 'contributors' => 'crwdns1070:0crwdne1070:0', + 'license' => 'crwdns1071:0%20Ccrwdnd1071:0%20crwdne1071:0', + 'backers-title' => 'crwdns1072:0crwdne1072:0', + 'backers' => 'crwdns1073:0crwdne1073:0', + 'thank-you' => 'crwdns1074:0crwdne1074:0', + ], + ], + + // Login + 'login' => [ + 'login' => 'crwdns1075:0crwdne1075:0', + 'logged_in' => 'crwdns1076:0crwdne1076:0', + 'welcome' => 'crwdns1077:0crwdne1077:0', + 'two-factor' => 'crwdns1078:0crwdne1078:0', + ], + + // Sidebar footer + 'help' => 'crwdns1079:0crwdne1079:0', + 'status_page' => 'crwdns1080:0crwdne1080:0', + 'logout' => 'crwdns1081:0crwdne1081:0', + + // Notifications + 'notifications' => [ + 'notifications' => 'crwdns1082:0crwdne1082:0', + 'awesome' => 'crwdns1083:0crwdne1083:0', + 'whoops' => 'crwdns1084:0crwdne1084:0', + ], + + // Widgets + 'widgets' => [ + 'support' => 'crwdns1085:0crwdne1085:0', + 'support_subtitle' => 'crwdns1086:0crwdne1086:0', + 'news' => 'crwdns1087:0crwdne1087:0', + 'news_subtitle' => 'crwdns1088:0crwdne1088:0', + ], + + // Welcome modal + 'welcome' => [ + 'welcome' => 'crwdns1089:0crwdne1089:0', + 'message' => 'crwdns1090:0crwdne1090:0', + 'close' => 'crwdns1091:0crwdne1091:0', + 'steps' => [ + 'component' => 'crwdns1092:0crwdne1092:0', + 'incident' => 'crwdns1093:0crwdne1093:0', + 'customize' => 'crwdns1094:0crwdne1094:0', + 'team' => 'crwdns1095:0crwdne1095:0', + 'api' => 'crwdns1096:0crwdne1096:0', + 'two-factor' => 'crwdns1097:0crwdne1097:0', + ], + ], + +]; diff --git a/resources/lang/zu-ZA/forms.php b/resources/lang/zu-ZA/forms.php new file mode 100644 index 00000000000..67bf72c1f00 --- /dev/null +++ b/resources/lang/zu-ZA/forms.php @@ -0,0 +1,253 @@ + [ + 'email' => 'crwdns1098:0crwdne1098:0', + 'username' => 'crwdns1099:0crwdne1099:0', + 'password' => 'crwdns1100:0crwdne1100:0', + 'site_name' => 'crwdns1101:0crwdne1101:0', + 'site_domain' => 'crwdns1102:0crwdne1102:0', + 'site_timezone' => 'crwdns1103:0crwdne1103:0', + 'site_locale' => 'crwdns1104:0crwdne1104:0', + 'enable_google2fa' => 'crwdns1105:0crwdne1105:0', + 'cache_driver' => 'crwdns1106:0crwdne1106:0', + 'queue_driver' => 'crwdns1107:0crwdne1107:0', + 'session_driver' => 'crwdns1108:0crwdne1108:0', + 'mail_driver' => 'crwdns1109:0crwdne1109:0', + 'mail_host' => 'crwdns1110:0crwdne1110:0', + 'mail_address' => 'crwdns1111:0crwdne1111:0', + 'mail_username' => 'crwdns1112:0crwdne1112:0', + 'mail_password' => 'crwdns1113:0crwdne1113:0', + ], + + // Login form fields + 'login' => [ + 'login' => 'crwdns1114:0crwdne1114:0', + 'email' => 'crwdns1115:0crwdne1115:0', + 'password' => 'crwdns1116:0crwdne1116:0', + '2fauth' => 'crwdns1117:0crwdne1117:0', + 'invalid' => 'crwdns1118:0crwdne1118:0', + 'invalid-token' => 'crwdns1119:0crwdne1119:0', + 'cookies' => 'crwdns1120:0crwdne1120:0', + 'rate-limit' => 'crwdns1121:0crwdne1121:0', + 'remember_me' => 'crwdns1122:0crwdne1122:0', + ], + + // Incidents form fields + 'incidents' => [ + 'name' => 'crwdns1123:0crwdne1123:0', + 'status' => 'crwdns1124:0crwdne1124:0', + 'component' => 'crwdns1125:0crwdne1125:0', + 'component_status' => 'crwdns1425:0crwdne1425:0', + 'message' => 'crwdns1126:0crwdne1126:0', + 'message-help' => 'crwdns1127:0crwdne1127:0', + 'occurred_at' => 'crwdns1128:0crwdne1128:0', + 'notify_subscribers' => 'crwdns1129:0crwdne1129:0', + 'notify_disabled' => 'crwdns1426:0crwdne1426:0', + 'visibility' => 'crwdns1130:0crwdne1130:0', + 'stick_status' => 'crwdns1131:0crwdne1131:0', + 'stickied' => 'crwdns1132:0crwdne1132:0', + 'not_stickied' => 'crwdns1133:0crwdne1133:0', + 'public' => 'crwdns1134:0crwdne1134:0', + 'logged_in_only' => 'crwdns1135:0crwdne1135:0', + 'templates' => [ + 'name' => 'crwdns1136:0crwdne1136:0', + 'template' => 'crwdns1137:0crwdne1137:0', + 'twig' => 'crwdns1138:0crwdne1138:0', + ], + ], + + 'schedules' => [ + 'name' => 'crwdns1139:0crwdne1139:0', + 'status' => 'crwdns1140:0crwdne1140:0', + 'message' => 'crwdns1141:0crwdne1141:0', + 'message-help' => 'crwdns1142:0crwdne1142:0', + 'scheduled_at' => 'crwdns1143:0crwdne1143:0', + 'completed_at' => 'crwdns1144:0crwdne1144:0', + 'templates' => [ + 'name' => 'crwdns1145:0crwdne1145:0', + 'template' => 'crwdns1146:0crwdne1146:0', + 'twig' => 'crwdns1147:0crwdne1147:0', + ], + ], + + // Components form fields + 'components' => [ + 'name' => 'crwdns1148:0crwdne1148:0', + 'status' => 'crwdns1149:0crwdne1149:0', + 'group' => 'crwdns1150:0crwdne1150:0', + 'description' => 'crwdns1151:0crwdne1151:0', + 'link' => 'crwdns1152:0crwdne1152:0', + 'tags' => 'crwdns1153:0crwdne1153:0', + 'tags-help' => 'crwdns1154:0crwdne1154:0', + 'enabled' => 'crwdns1155:0crwdne1155:0', + + 'groups' => [ + 'name' => 'crwdns1156:0crwdne1156:0', + 'collapsing' => 'crwdns1157:0crwdne1157:0', + 'visible' => 'crwdns1158:0crwdne1158:0', + 'collapsed' => 'crwdns1159:0crwdne1159:0', + 'collapsed_incident' => 'crwdns1160:0crwdne1160:0', + 'visibility' => 'crwdns1161:0crwdne1161:0', + 'visibility_public' => 'crwdns1162:0crwdne1162:0', + 'visibility_authenticated' => 'crwdns1163:0crwdne1163:0', + ], + ], + + // Action form fields + 'actions' => [ + 'name' => 'crwdns1164:0crwdne1164:0', + 'description' => 'crwdns1165:0crwdne1165:0', + 'start_at' => 'crwdns1166:0crwdne1166:0', + 'timezone' => 'crwdns1167:0crwdne1167:0', + 'schedule_frequency' => 'crwdns1168:0crwdne1168:0', + 'completion_latency' => 'crwdns1169:0crwdne1169:0', + 'group' => 'crwdns1170:0crwdne1170:0', + 'active' => 'crwdns1171:0crwdne1171:0', + 'groups' => [ + 'name' => 'crwdns1172:0crwdne1172:0', + ], + ], + + // Metric form fields + 'metrics' => [ + 'name' => 'crwdns1173:0crwdne1173:0', + 'suffix' => 'crwdns1174:0crwdne1174:0', + 'description' => 'crwdns1175:0crwdne1175:0', + 'description-help' => 'crwdns1176:0crwdne1176:0', + 'display-chart' => 'crwdns1177:0crwdne1177:0', + 'default-value' => 'crwdns1178:0crwdne1178:0', + 'calc_type' => 'crwdns1179:0crwdne1179:0', + 'type_sum' => 'crwdns1180:0crwdne1180:0', + 'type_avg' => 'crwdns1181:0crwdne1181:0', + 'places' => 'crwdns1182:0crwdne1182:0', + 'default_view' => 'crwdns1183:0crwdne1183:0', + 'threshold' => 'crwdns1184:0crwdne1184:0', + 'visibility' => 'crwdns1185:0crwdne1185:0', + 'visibility_authenticated' => 'crwdns1186:0crwdne1186:0', + 'visibility_public' => 'crwdns1187:0crwdne1187:0', + 'visibility_hidden' => 'crwdns1188:0crwdne1188:0', + + 'points' => [ + 'value' => 'crwdns1189:0crwdne1189:0', + ], + ], + + // Settings + 'settings' => [ + // Application setup + 'app-setup' => [ + 'site-name' => 'crwdns1190:0crwdne1190:0', + 'site-url' => 'crwdns1191:0crwdne1191:0', + 'display-graphs' => 'crwdns1192:0crwdne1192:0', + 'about-this-page' => 'crwdns1193:0crwdne1193:0', + 'days-of-incidents' => 'crwdns1194:0crwdne1194:0', + 'time_before_refresh' => 'crwdns1434:0crwdne1434:0', + 'major_outage_rate' => 'crwdns1444:0crwdne1444:0', + 'banner' => 'crwdns1195:0crwdne1195:0', + 'banner-help' => 'crwdns1435:0crwdne1435:0', + 'subscribers' => 'crwdns1197:0crwdne1197:0', + 'suppress_notifications_in_maintenance' => 'crwdns1427:0crwdne1427:0', + 'skip_subscriber_verification' => 'crwdns1198:0crwdne1198:0', + 'automatic_localization' => 'crwdns1199:0crwdne1199:0', + 'enable_external_dependencies' => 'crwdns1200:0crwdne1200:0', + 'show_timezone' => 'crwdns1436:0crwdne1436:0', + 'only_disrupted_days' => 'crwdns1202:0crwdne1202:0', + ], + 'analytics' => [ + 'analytics_google' => 'crwdns1203:0crwdne1203:0', + 'analytics_gosquared' => 'crwdns1204:0crwdne1204:0', + 'analytics_piwik_url' => 'crwdns1524:0crwdne1524:0', + 'analytics_piwik_siteid' => 'crwdns1206:0crwdne1206:0', + ], + 'localization' => [ + 'site-timezone' => 'crwdns1207:0crwdne1207:0', + 'site-locale' => 'crwdns1208:0crwdne1208:0', + 'date-format' => 'crwdns1209:0crwdne1209:0', + 'incident-date-format' => 'crwdns1210:0crwdne1210:0', + ], + 'security' => [ + 'allowed-domains' => 'crwdns1211:0crwdne1211:0', + 'allowed-domains-help' => 'crwdns1212:0crwdne1212:0', + 'always-authenticate' => 'crwdns1445:0crwdne1445:0', + 'always-authenticate-help' => 'crwdns1446:0crwdne1446:0', + ], + 'stylesheet' => [ + 'custom-css' => 'crwdns1213:0crwdne1213:0', + ], + 'theme' => [ + 'background-color' => 'crwdns1214:0crwdne1214:0', + 'background-fills' => 'crwdns1215:0crwdne1215:0', + 'banner-background-color' => 'crwdns1216:0crwdne1216:0', + 'banner-padding' => 'crwdns1217:0crwdne1217:0', + 'fullwidth-banner' => 'crwdns1442:0crwdne1442:0', + 'text-color' => 'crwdns1219:0crwdne1219:0', + 'dashboard-login' => 'crwdns1220:0crwdne1220:0', + 'reds' => 'crwdns1221:0crwdne1221:0', + 'blues' => 'crwdns1222:0crwdne1222:0', + 'greens' => 'crwdns1223:0crwdne1223:0', + 'yellows' => 'crwdns1224:0crwdne1224:0', + 'oranges' => 'crwdns1225:0crwdne1225:0', + 'metrics' => 'crwdns1226:0crwdne1226:0', + 'links' => 'crwdns1227:0crwdne1227:0', + ], + ], + + 'user' => [ + 'username' => 'crwdns1228:0crwdne1228:0', + 'email' => 'crwdns1229:0crwdne1229:0', + 'password' => 'crwdns1230:0crwdne1230:0', + 'api-token' => 'crwdns1231:0crwdne1231:0', + 'api-token-help' => 'crwdns1232:0crwdne1232:0', + 'gravatar' => 'crwdns1233:0crwdne1233:0', + 'user_level' => 'crwdns1234:0crwdne1234:0', + 'levels' => [ + 'admin' => 'crwdns1235:0crwdne1235:0', + 'user' => 'crwdns1236:0crwdne1236:0', + ], + '2fa' => [ + 'help' => 'crwdns1237:0crwdne1237:0', + ], + 'team' => [ + 'description' => 'crwdns1238:0crwdne1238:0', + 'email' => 'crwdns1423:0crwdne1423:0', + ], + ], + + 'general' => [ + 'timezone' => 'crwdns1240:0crwdne1240:0', + ], + + 'seo' => [ + 'title' => 'crwdns1526:0crwdne1526:0', + 'description' => 'crwdns1528:0crwdne1528:0', + ], + + // Buttons + 'add' => 'crwdns1241:0crwdne1241:0', + 'save' => 'crwdns1242:0crwdne1242:0', + 'update' => 'crwdns1243:0crwdne1243:0', + 'create' => 'crwdns1244:0crwdne1244:0', + 'edit' => 'crwdns1245:0crwdne1245:0', + 'delete' => 'crwdns1246:0crwdne1246:0', + 'submit' => 'crwdns1247:0crwdne1247:0', + 'cancel' => 'crwdns1248:0crwdne1248:0', + 'remove' => 'crwdns1249:0crwdne1249:0', + 'invite' => 'crwdns1250:0crwdne1250:0', + 'signup' => 'crwdns1251:0crwdne1251:0', + 'manage_updates' => 'crwdns1424:0crwdne1424:0', + + // Other + 'optional' => 'crwdns1252:0crwdne1252:0', +]; diff --git a/resources/lang/zu-ZA/notifications.php b/resources/lang/zu-ZA/notifications.php new file mode 100644 index 00000000000..b8bd9f13ca4 --- /dev/null +++ b/resources/lang/zu-ZA/notifications.php @@ -0,0 +1,116 @@ + [ + 'status_update' => [ + 'mail' => [ + 'subject' => 'crwdns1354:0crwdne1354:0', + 'greeting' => 'crwdns1355:0crwdne1355:0', + 'content' => 'crwdns1356:0crwdne1356:0', + 'action' => 'crwdns1357:0crwdne1357:0', + ], + 'slack' => [ + 'title' => 'crwdns1358:0crwdne1358:0', + 'content' => 'crwdns1359:0crwdne1359:0', + ], + 'sms' => [ + 'content' => 'crwdns1360:0crwdne1360:0', + ], + ], + ], + 'incident' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'crwdns1361:0crwdne1361:0', + 'greeting' => 'crwdns1362:0crwdne1362:0', + 'content' => 'crwdns1363:0crwdne1363:0', + 'action' => 'crwdns1364:0crwdne1364:0', + ], + 'slack' => [ + 'title' => 'crwdns1365:0crwdne1365:0', + 'content' => 'crwdns1366:0crwdne1366:0', + ], + 'sms' => [ + 'content' => 'crwdns1367:0crwdne1367:0', + ], + ], + 'update' => [ + 'mail' => [ + 'subject' => 'crwdns1368:0crwdne1368:0', + 'content' => 'crwdns1369:0crwdne1369:0', + 'title' => 'crwdns1370:0crwdne1370:0', + 'action' => 'crwdns1371:0crwdne1371:0', + ], + 'slack' => [ + 'title' => 'crwdns1372:0crwdne1372:0', + 'content' => 'crwdns1373:0crwdne1373:0', + ], + 'sms' => [ + 'content' => 'crwdns1374:0crwdne1374:0', + ], + ], + ], + 'schedule' => [ + 'new' => [ + 'mail' => [ + 'subject' => 'crwdns1375:0crwdne1375:0', + 'content' => 'crwdns1376:0crwdne1376:0', + 'title' => 'crwdns1377:0crwdne1377:0', + 'action' => 'crwdns1378:0crwdne1378:0', + ], + 'slack' => [ + 'title' => 'crwdns1379:0crwdne1379:0', + 'content' => 'crwdns1380:0crwdne1380:0', + ], + 'sms' => [ + 'content' => 'crwdns1381:0crwdne1381:0', + ], + ], + ], + 'subscriber' => [ + 'verify' => [ + 'mail' => [ + 'subject' => 'crwdns1382:0crwdne1382:0', + 'content' => 'crwdns1383:0crwdne1383:0', + 'title' => 'crwdns1384:0crwdne1384:0', + 'action' => 'crwdns1385:0crwdne1385:0', + ], + ], + 'manage' => [ + 'mail' => [ + 'subject' => 'crwdns1532:0crwdne1532:0', + 'content' => 'crwdns1534:0crwdne1534:0', + 'title' => 'crwdns1536:0crwdne1536:0', + 'action' => 'crwdns1538:0crwdne1538:0', + ], + ], + ], + 'system' => [ + 'test' => [ + 'mail' => [ + 'subject' => 'crwdns1386:0crwdne1386:0', + 'content' => 'crwdns1387:0crwdne1387:0', + 'title' => 'crwdns1388:0crwdne1388:0', + ], + ], + ], + 'user' => [ + 'invite' => [ + 'mail' => [ + 'subject' => 'crwdns1389:0crwdne1389:0', + 'content' => 'crwdns1390:0crwdne1390:0', + 'title' => 'crwdns1391:0crwdne1391:0', + 'action' => 'crwdns1392:0crwdne1392:0', + ], + ], + ], +]; diff --git a/resources/lang/zu-ZA/pagination.php b/resources/lang/zu-ZA/pagination.php new file mode 100644 index 00000000000..325882060d0 --- /dev/null +++ b/resources/lang/zu-ZA/pagination.php @@ -0,0 +1,28 @@ + 'crwdns1393:0crwdne1393:0', + 'next' => 'crwdns1394:0crwdne1394:0', + +]; diff --git a/resources/lang/zu-ZA/setup.php b/resources/lang/zu-ZA/setup.php new file mode 100644 index 00000000000..4f7bbbeed14 --- /dev/null +++ b/resources/lang/zu-ZA/setup.php @@ -0,0 +1,23 @@ + 'crwdns1255:0crwdne1255:0', + 'title' => 'crwdns1256:0crwdne1256:0', + 'service_details' => 'crwdns1257:0crwdne1257:0', + 'env_setup' => 'crwdns1258:0crwdne1258:0', + 'status_page_setup' => 'crwdns1259:0crwdne1259:0', + 'show_support' => 'crwdns1260:0crwdne1260:0', + 'admin_account' => 'crwdns1261:0crwdne1261:0', + 'complete_setup' => 'crwdns1262:0crwdne1262:0', + 'completed' => 'crwdns1263:0crwdne1263:0', + 'finish_setup' => 'crwdns1264:0crwdne1264:0', +]; diff --git a/resources/lang/zu-ZA/validation.php b/resources/lang/zu-ZA/validation.php new file mode 100644 index 00000000000..8a727c3857d --- /dev/null +++ b/resources/lang/zu-ZA/validation.php @@ -0,0 +1,122 @@ + 'crwdns1265:0crwdne1265:0', + 'active_url' => 'crwdns1266:0crwdne1266:0', + 'after' => 'crwdns1267:0crwdne1267:0', + 'alpha' => 'crwdns1268:0crwdne1268:0', + 'alpha_dash' => 'crwdns1269:0crwdne1269:0', + 'alpha_num' => 'crwdns1270:0crwdne1270:0', + 'array' => 'crwdns1271:0crwdne1271:0', + 'before' => 'crwdns1272:0crwdne1272:0', + 'between' => [ + 'numeric' => 'crwdns1273:0crwdne1273:0', + 'file' => 'crwdns1274:0crwdne1274:0', + 'string' => 'crwdns1275:0crwdne1275:0', + 'array' => 'crwdns1276:0crwdne1276:0', + ], + 'boolean' => 'crwdns1277:0crwdne1277:0', + 'confirmed' => 'crwdns1278:0crwdne1278:0', + 'date' => 'crwdns1279:0crwdne1279:0', + 'date_format' => 'crwdns1280:0crwdne1280:0', + 'different' => 'crwdns1281:0crwdne1281:0', + 'digits' => 'crwdns1282:0crwdne1282:0', + 'digits_between' => 'crwdns1283:0crwdne1283:0', + 'email' => 'crwdns1284:0crwdne1284:0', + 'exists' => 'crwdns1285:0crwdne1285:0', + 'distinct' => 'crwdns1286:0crwdne1286:0', + 'filled' => 'crwdns1287:0crwdne1287:0', + 'image' => 'crwdns1288:0crwdne1288:0', + 'in' => 'crwdns1289:0crwdne1289:0', + 'in_array' => 'crwdns1290:0crwdne1290:0', + 'integer' => 'crwdns1291:0crwdne1291:0', + 'ip' => 'crwdns1292:0crwdne1292:0', + 'json' => 'crwdns1293:0crwdne1293:0', + 'max' => [ + 'numeric' => 'crwdns1294:0crwdne1294:0', + 'file' => 'crwdns1295:0crwdne1295:0', + 'string' => 'crwdns1296:0crwdne1296:0', + 'array' => 'crwdns1297:0crwdne1297:0', + ], + 'mimes' => 'crwdns1298:0crwdne1298:0', + 'min' => [ + 'numeric' => 'crwdns1299:0crwdne1299:0', + 'file' => 'crwdns1300:0crwdne1300:0', + 'string' => 'crwdns1301:0crwdne1301:0', + 'array' => 'crwdns1302:0crwdne1302:0', + ], + 'not_in' => 'crwdns1303:0crwdne1303:0', + 'numeric' => 'crwdns1304:0crwdne1304:0', + 'present' => 'crwdns1305:0crwdne1305:0', + 'regex' => 'crwdns1306:0crwdne1306:0', + 'required' => 'crwdns1307:0crwdne1307:0', + 'required_if' => 'crwdns1308:0crwdne1308:0', + 'required_unless' => 'crwdns1309:0crwdne1309:0', + 'required_with' => 'crwdns1310:0crwdne1310:0', + 'required_with_all' => 'crwdns1311:0crwdne1311:0', + 'required_without' => 'crwdns1312:0crwdne1312:0', + 'required_without_all' => 'crwdns1313:0crwdne1313:0', + 'same' => 'crwdns1314:0crwdne1314:0', + 'size' => [ + 'numeric' => 'crwdns1315:0crwdne1315:0', + 'file' => 'crwdns1316:0crwdne1316:0', + 'string' => 'crwdns1317:0crwdne1317:0', + 'array' => 'crwdns1318:0crwdne1318:0', + ], + 'string' => 'crwdns1319:0crwdne1319:0', + 'timezone' => 'crwdns1320:0crwdne1320:0', + 'unique' => 'crwdns1321:0crwdne1321:0', + 'url' => 'crwdns1322:0crwdne1322:0', + + /* + |-------------------------------------------------------------------------- + | Custom Validation Language Lines + |-------------------------------------------------------------------------- + | + | Here you may specify custom validation messages for attributes using the + | convention "attribute.rule" to name the lines. This makes it quick to + | specify a specific custom language line for a given attribute rule. + | + */ + + 'custom' => [ + 'attribute-name' => [ + 'rule-name' => 'crwdns1323:0crwdne1323:0', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Custom Validation Attributes + |-------------------------------------------------------------------------- + | + | The following language lines are used to swap attribute place-holders + | with something more reader friendly such as E-Mail Address instead + | of "email". This simply helps us make messages a little cleaner. + | + */ + + 'attributes' => [], + +]; diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index e26c92d2453..a5f709bf931 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -10,7 +10,7 @@
-
+ @if(Session::has('error')) @@ -27,16 +27,24 @@
+
+ + +
-
+
diff --git a/resources/views/auth/two-factor-auth.blade.php b/resources/views/auth/two-factor-auth.blade.php index 048fa9a7c4b..4e339644658 100644 --- a/resources/views/auth/two-factor-auth.blade.php +++ b/resources/views/auth/two-factor-auth.blade.php @@ -7,17 +7,7 @@

@@ -28,7 +18,7 @@

{{ trans('dashboard.login.two-factor') }}


- +
@@ -38,7 +28,7 @@
- +
diff --git a/resources/views/dashboard/components/add.blade.php b/resources/views/dashboard/components/add.blade.php index 43fe12b672f..da0efe073d9 100644 --- a/resources/views/dashboard/components/add.blade.php +++ b/resources/views/dashboard/components/add.blade.php @@ -1,78 +1,78 @@ @extends('layout.dashboard') @section('content') -
- - - {{ trans('dashboard.components.components') }} - - > {{ trans('dashboard.components.add.title') }} +
+ -
-
-
- @include('dashboard.partials.errors') - - -
-
- - -
-
- - -
-
- - -
- @if($groups->count() > 0) -
- - -
- @else - - @endif -
-
- - -
-
- - - {{ trans('forms.components.tags-help') }} -
-
- -
-
+ + {{ trans('dashboard.components.components') }} + + > {{ trans('dashboard.components.add.title') }} +
+
+
+
+ @include('partials.errors') + + +
+
+ + +
+
+ + +
+
+ + +
+ @if($groups->count() > 0) +
+ + +
+ @else + + @endif +
+
+ + +
+
+ + + {{ trans('forms.components.tags-help') }} +
+
+ +
+
- + -
- - {{ trans('forms.cancel') }} -
- -
+
+ + {{ trans('forms.cancel') }} +
+
+
@stop diff --git a/resources/views/dashboard/components/edit.blade.php b/resources/views/dashboard/components/edit.blade.php index 6324f8783aa..a5d37796cf5 100644 --- a/resources/views/dashboard/components/edit.blade.php +++ b/resources/views/dashboard/components/edit.blade.php @@ -1,79 +1,79 @@ @extends('layout.dashboard') @section('content') -
- - - {{ trans('dashboard.components.components') }} - - > {{ trans('dashboard.components.edit.title') }} +
+ -
-
-
- @include('dashboard.partials.errors') -
- -
-
- - -
-
- - -
-
- - -
- @if($groups->count() > 0) -
- - -
- @else - - @endif -
-
- - -
-
- - - {{ trans('forms.components.tags-help') }} -
-
- -
-
+ + {{ trans('dashboard.components.components') }} + + > {{ trans('dashboard.components.edit.title') }} +
+
+
+
+ @include('partials.errors') + + +
+
+ + +
+
+ + +
+
+ + +
+ @if($groups->count() > 0) +
+ + +
+ @else + + @endif +
+
+ + +
+
+ + + {{ trans('forms.components.tags-help') }} +
+
+ +
+
- - + + -
- - {{ trans('forms.cancel') }} -
- -
+
+ + {{ trans('forms.cancel') }} +
+
- @stop +
+@stop diff --git a/resources/views/dashboard/components/groups/add.blade.php b/resources/views/dashboard/components/groups/add.blade.php index 3111e46308f..836e11d9c85 100644 --- a/resources/views/dashboard/components/groups/add.blade.php +++ b/resources/views/dashboard/components/groups/add.blade.php @@ -1,42 +1,49 @@ @extends('layout.dashboard') @section('content') -
- - - {{ trans_choice('dashboard.components.groups.groups', 2) }} - - > {{ trans('dashboard.components.groups.add.title') }} +
+ -
-
-
- @include('dashboard.partials.errors') -
- -
-
- - -
-
- - -
-
- -
- - {{ trans('forms.cancel') }} + + {{ trans_choice('dashboard.components.groups.groups', 2) }} + + > {{ trans('dashboard.components.groups.add.title') }} +
+
+
+
+ @include('partials.errors') + + +
+
+ + +
+
+ +
- -
+
+ + +
+
+ +
+ + {{ trans('forms.cancel') }} +
+
+
@stop diff --git a/resources/views/dashboard/components/groups/edit.blade.php b/resources/views/dashboard/components/groups/edit.blade.php index 72d27a1c006..1aef2dc676a 100644 --- a/resources/views/dashboard/components/groups/edit.blade.php +++ b/resources/views/dashboard/components/groups/edit.blade.php @@ -1,42 +1,49 @@ @extends('layout.dashboard') @section('content') -
- - - {{ trans_choice('dashboard.components.groups.groups', 2) }} - - > {{ trans('dashboard.components.groups.edit.title') }} +
+ -
-
-
- @include('dashboard.partials.errors') -
- -
-
- - -
-
- - -
-
- -
- - {{ trans('forms.cancel') }} + + {{ trans_choice('dashboard.components.groups.groups', 2) }} + + > {{ trans('dashboard.components.groups.edit.title') }} +
+
+
+
+ @include('partials.errors') + + +
+
+ + +
+
+ +
- -
+
+ + +
+ + +
+ + {{ trans('forms.cancel') }} +
+
+
@stop diff --git a/resources/views/dashboard/components/groups/index.blade.php b/resources/views/dashboard/components/groups/index.blade.php index fa8f4b4438d..aa46c0d3a9d 100644 --- a/resources/views/dashboard/components/groups/index.blade.php +++ b/resources/views/dashboard/components/groups/index.blade.php @@ -1,44 +1,42 @@ @extends('layout.dashboard') @section('content') -
- @if(isset($sub_menu)) - @include('dashboard.partials.sub-sidebar') - @endif -
-
- - {{ trans_choice('dashboard.components.groups.groups', 2) }} - - - {{ trans('dashboard.components.groups.add.title') }} - -
-
- @include('dashboard.partials.errors') -
-
- @forelse($groups as $group) -
-
-

- @if($groups->count() > 1) - - @endif - {{ $group->name }} - {{ $group->components->count() }} -

-
- +
+ @includeWhen(isset($subMenu), 'dashboard.partials.sub-sidebar') +
+
+ + {{ trans_choice('dashboard.components.groups.groups', 2) }} + + + {{ trans('dashboard.components.groups.add.title') }} + +
+
+ @include('partials.errors') +
+
+ @forelse($groups as $group) +
+
+

+ @if($groups->count() > 1) + + @endif + {{ $group->name }} + {{ $group->components->count() }} +

+
+ - @empty -
{{ trans('dashboard.components.groups.no_components') }}
- @endforelse
+ @empty +
{{ trans('dashboard.components.groups.no_components') }}
+ @endforelse
+
@stop diff --git a/resources/views/dashboard/components/index.blade.php b/resources/views/dashboard/components/index.blade.php index 2ba143c4945..5835a4773b6 100644 --- a/resources/views/dashboard/components/index.blade.php +++ b/resources/views/dashboard/components/index.blade.php @@ -1,49 +1,47 @@ @extends('layout.dashboard') @section('content') -
- @if(isset($sub_menu)) - @include('dashboard.partials.sub-sidebar') - @endif -
-
- - {{ trans('dashboard.components.components') }} - - - {{ trans('dashboard.components.add.title') }} - -
-
- @include('dashboard.partials.errors') -
-
- @forelse($components as $component) -
-
-

- @if($components->count() > 1) - - @endif - {{ $component->name }} {{ $component->human_status }} -

- @if($component->group) -

{{ trans('dashboard.components.listed_group', ['name' => $component->group->name]) }}

- @endif - @if($component->description) -

{{ $component->description }}

+
+ @includeWhen(isset($subMenu), 'dashboard.partials.sub-sidebar') +
+
+ + {{ trans('dashboard.components.components') }} + + + {{ trans('dashboard.components.add.title') }} + +
+
+ @include('partials.errors') +
+
+ @forelse($components as $component) +
+
+

+ @if($components->count() > 1) + @endif -

- + {!! $component->name !!} {{ $component->human_status }} + + @if($component->group) +

{{ trans('dashboard.components.listed_group', ['name' => $component->group->name]) }}

+ @endif + @if($component->description) +

{{ $component->description }}

+ @endif +
+ - @empty -
{{ trans('dashboard.components.add.message') }}
- @endforelse
+ @empty +
{{ trans('dashboard.components.add.message') }}
+ @endforelse
+
@stop diff --git a/resources/views/dashboard/incidents/add.blade.php b/resources/views/dashboard/incidents/add.blade.php index 821a633be74..421013bcf6c 100644 --- a/resources/views/dashboard/incidents/add.blade.php +++ b/resources/views/dashboard/incidents/add.blade.php @@ -1,28 +1,34 @@ @extends('layout.dashboard') @section('content') -
- - - {{ trans('dashboard.incidents.incidents') }} - - > {{ trans('dashboard.incidents.add.title') }} +
+ -
-
-
- @include('dashboard.partials.errors') + + {{ trans('dashboard.incidents.incidents') }} + + > {{ trans('dashboard.incidents.add.title') }} +
+
+
+
+ @if(!$notificationsEnabled) + + @endif + @include('partials.errors') +
- @if($incident_templates->count() > 0) + @if($incidentTemplates->count() > 0)
- - - @foreach($incident_templates as $tpl) + @foreach($incidentTemplates as $tpl) @endforeach @@ -30,65 +36,72 @@ @endif
- +

- + + + +
+
+ +
- @if(!$components_in_groups->isEmpty() || !$components_out_groups->isEmpty()) + @if(!$componentsInGroups->isEmpty() || !$componentsOutGroups->isEmpty())
- - + + @foreach($componentsInGroups as $group) @foreach($group->components as $component) - + @endforeach @endforeach - @foreach($components_out_groups as $component) - + @foreach($componentsOutGroups as $component) + @endforeach - {{ trans('forms.optional') }}
@endif -
-
+
+
@stop diff --git a/resources/views/dashboard/incidents/edit.blade.php b/resources/views/dashboard/incidents/edit.blade.php index 3d078179552..525a861b439 100644 --- a/resources/views/dashboard/incidents/edit.blade.php +++ b/resources/views/dashboard/incidents/edit.blade.php @@ -1,97 +1,134 @@ @extends('layout.dashboard') @section('content') -
- - - {{ trans('dashboard.incidents.incidents') }} - - > {{ trans('dashboard.incidents.edit.title') }} +
+ -
-
-
- @include('dashboard.partials.errors') -
- -
-
- - -
-
-
- - - - -
-
- - -
- @if($incident->component) -
-
-
{{ $incident->component->name }}
-
-
- @foreach(trans('cachet.components.status') as $statusID => $status) -
- -
- @endforeach + + {{ trans('dashboard.incidents.incidents') }} + + > {{ trans('dashboard.incidents.edit.title') }} +
+
+
+
+ @if(!$notificationsEnabled) + + @endif + @include('partials.errors') + + +
+
+ + +
+
+
+ + + + +
+ @if($incident->component) +
- - id}}> - +
+ @endif
-
- - {{ trans('forms.cancel') }} + +
+
- -
+
+ {{ trans('forms.optional') }} + +
+
+ {{ trans('forms.optional') }} + +
+
+ {{ trans('forms.optional') }} + +
+
+ +
+
+ + {{ trans('forms.cancel') }} +
+
+
+
@stop diff --git a/resources/views/dashboard/incidents/index.blade.php b/resources/views/dashboard/incidents/index.blade.php index e9b8951b980..69103049676 100644 --- a/resources/views/dashboard/incidents/index.blade.php +++ b/resources/views/dashboard/incidents/index.blade.php @@ -1,43 +1,45 @@ @extends('layout.dashboard') @section('content') -
- @if(isset($sub_menu)) - @include('dashboard.partials.sub-sidebar') - @endif -
-
- - {{ trans('dashboard.incidents.incidents') }} - - - {{ trans('dashboard.incidents.add.title') }} - -
-
-
-
- @include('dashboard.partials.errors') -

{!! trans_choice('dashboard.incidents.logged', $incidents->count(), ['count' => $incidents->count()]) !!}

+
+ @includeWhen(isset($subMenu), 'dashboard.partials.sub-sidebar') +
+
+ + {{ trans('dashboard.incidents.incidents') }} + + + {{ trans('dashboard.incidents.add.title') }} + +
+
+
+
+ @include('partials.errors') +

{!! trans_choice('dashboard.incidents.logged', $incidents->count(), ['count' => $incidents->count()]) !!}

-
- @foreach($incidents as $incident) -
-
- {{ $incident->name }} - @if($incident->message) -

{{ Str::words($incident->message, 5) }}

- @endif -
- +
+ @foreach($incidents as $incident) +
+
+ {{ $incident->name }} {{ trans_choice('dashboard.incidents.updates.count', $incident->updates()->count()) }} + @if($incident->message) +

{{ Str::words($incident->message, 5) }}

+ @endif + @if ($incident->user) +

— {{ trans('dashboard.incidents.reported_by', ['timestamp' => $incident->created_at_diff, 'user' => $incident->user->username]) }}

+ @endif +
+ - @endforeach
+ @endforeach
+
@stop diff --git a/resources/views/dashboard/incidents/updates/add.blade.php b/resources/views/dashboard/incidents/updates/add.blade.php new file mode 100644 index 00000000000..12d99621a68 --- /dev/null +++ b/resources/views/dashboard/incidents/updates/add.blade.php @@ -0,0 +1,119 @@ +@extends('layout.dashboard') + +@section('content') +
+ + + {{ trans('dashboard.incidents.incidents') }} + + > {{ trans('dashboard.incidents.updates.title', ['incident' => $incident->name]) }} > {{ trans('dashboard.incidents.updates.add.title') }} +
+
+
+
+ @if(!$notificationsEnabled) + + @endif + @include('partials.errors') + +
+ +
+ @if($incidentTemplates->count() > 0) +
+ + +
+ @endif +
+
+ + + + +
+ @if($incident->component) + + @endif + @if($incident->component) +
+
+
{{ $incident->component->name }}
+
+
+ @foreach(trans('cachet.components.status') as $statusID => $status) +
+ +
+ @endforeach +
+
+
+
+ @endif +
+ +
+ +
+
+
+ + + +
+
+ + {{ trans('forms.cancel') }} +
+
+
+
+
+
+
+@stop diff --git a/resources/views/dashboard/incidents/updates/edit.blade.php b/resources/views/dashboard/incidents/updates/edit.blade.php new file mode 100644 index 00000000000..7f9f01ff64a --- /dev/null +++ b/resources/views/dashboard/incidents/updates/edit.blade.php @@ -0,0 +1,85 @@ +@extends('layout.dashboard') + +@section('content') +
+ + + {{ trans('dashboard.incidents.incidents') }} + + > {{ trans('dashboard.incidents.updates.title', ['incident' => $incident->name]) }} > {{ trans('dashboard.incidents.updates.edit.title') }} +
+
+
+
+ @if(!$notificationsEnabled) + + @endif + @include('partials.errors') +
+ +
+
+
+ + + + +
+ @if($incident->component) +
+
+
{{ $incident->component->name }}
+
+
+ @foreach(trans('cachet.components.status') as $statusID => $status) +
+ +
+ @endforeach +
+
+
+
+ @endif +
+ +
+ +
+
+
+ +
+
+ + {{ trans('forms.cancel') }} +
+
+
+
+
+
+@stop diff --git a/resources/views/dashboard/incidents/updates/index.blade.php b/resources/views/dashboard/incidents/updates/index.blade.php new file mode 100644 index 00000000000..8220a7de50b --- /dev/null +++ b/resources/views/dashboard/incidents/updates/index.blade.php @@ -0,0 +1,42 @@ +@extends('layout.dashboard') + +@section('content') +
+ + + {{ trans('dashboard.incidents.incidents') }} + + > {{ trans('dashboard.incidents.updates.title', ['incident' => $incident->name]) }} +
+
+ +
+
+ @include('partials.errors') + +
+ @foreach($incident->updates as $update) +
+
+ {{ Str::words($update->message, 8) }} +

{{ trans('cachet.incidents.posted', ['timestamp' => $update->created_at_diff, 'username' => $update->user->username]) }}

+
+ +
+ @endforeach +
+
+
+
+@stop diff --git a/resources/views/dashboard/index.blade.php b/resources/views/dashboard/index.blade.php index 4c65a86bfd0..dce3aaecce4 100644 --- a/resources/views/dashboard/index.blade.php +++ b/resources/views/dashboard/index.blade.php @@ -1,99 +1,95 @@ @extends('layout.dashboard') @section('content') -
- - - {{ trans('dashboard.dashboard') }} - -
-
-
-
- + +
+
+ + + {{ trans('dashboard.dashboard') }} +
-
- -
-
-

{{ trans('dashboard.components.component_statuses') }}

-
- @if(!$component_groups->isEmpty() || !$ungrouped_components->isEmpty()) - @include('dashboard.partials.components') - @else - - @endif -
-
-
- -
-
-
-
- {{ $incidents->map(function($incident) { return count($incident); })->sum() }} - {{ trans('dashboard.incidents.incidents') }} -
-
-
+
+
+
+
-
-
-
- -
-
-
+
+
+
+ @if(!$componentGroups->isEmpty() || !$ungroupedComponents->isEmpty()) + @include('dashboard.partials.components') + @else + + @endif +
+
-
-
-
-
-
-
- {{ trans('dashboard.widgets.support') }} - {!! trans('dashboard.widgets.support_subtitle') !!} +
+
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
-
- @if($entries) -
-
-
- {{ trans('dashboard.widgets.news') }} - {{ trans('dashboard.widgets.news_subtitle') }} +
+
+
+
+ {{ trans('dashboard.widgets.support') }} + {!! trans('dashboard.widgets.support_subtitle') !!} +
+
-
-
- @foreach($entries as $entry) - {{ $entry->title }}, {{ $entry->pubDate }} - @endforeach + + @if($entries) +
+
+
+ {{ trans('dashboard.widgets.news') }} + {{ trans('dashboard.widgets.news_subtitle') }} +
+
+
+ @foreach($entries as $entry) + {{ $entry->title }}, {{ $entry->pubDate }} + @endforeach +
+
+ @endif
+ @includeWhen($welcomeUser, 'dashboard.partials.welcome-modal')
- @endif
-@if(Session::get('setup.done')) -@include('dashboard.partials.welcome-modal') - -@endif @stop diff --git a/resources/views/dashboard/maintenance/add.blade.php b/resources/views/dashboard/maintenance/add.blade.php new file mode 100644 index 00000000000..07c5d6fa7ea --- /dev/null +++ b/resources/views/dashboard/maintenance/add.blade.php @@ -0,0 +1,80 @@ +@extends('layout.dashboard') + +@section('content') +
+ + + {{ trans('dashboard.schedule.schedule') }} + + > {{ trans('dashboard.schedule.add.title') }} +
+
+
+
+ @include('partials.errors') + +
+ +
+ @if($incidentTemplates->count() > 0) +
+ + +
+ @endif +
+ + +
+
+
+ @foreach(trans('cachet.schedules.status') as $id => $status) + + @endforeach +
+
+ +
+ +
+
+
+ + +
+
+ + +
+
+ @if($notificationsEnabled) + +
+ +
+ @endif +
+
+ + {{ trans('forms.cancel') }} +
+
+
+
+
+
+
+@stop diff --git a/resources/views/dashboard/maintenance/edit.blade.php b/resources/views/dashboard/maintenance/edit.blade.php new file mode 100644 index 00000000000..456e0797ae8 --- /dev/null +++ b/resources/views/dashboard/maintenance/edit.blade.php @@ -0,0 +1,71 @@ +@extends('layout.dashboard') + +@section('content') +
+ + + {{ trans('dashboard.schedule.schedule') }} + + > {{ trans('dashboard.schedule.edit.title') }} +
+
+
+
+ @include('partials.errors') +
+ + +
+ @if($incidentTemplates->count() > 0) +
+ + +
+ @endif +
+ + +
+
+
+ @foreach(trans('cachet.schedules.status') as $id => $status) + + @endforeach +
+
+ +
+ +
+
+
+ + +
+
+ + +
+
+ +
+
+ + {{ trans('forms.cancel') }} +
+
+
+
+
+
+@stop diff --git a/resources/views/dashboard/maintenance/index.blade.php b/resources/views/dashboard/maintenance/index.blade.php new file mode 100644 index 00000000000..c58a1deea5d --- /dev/null +++ b/resources/views/dashboard/maintenance/index.blade.php @@ -0,0 +1,43 @@ +@extends('layout.dashboard') + +@section('content') +
+ @includeWhen(isset($subMenu), 'dashboard.partials.sub-sidebar') +
+
+ + {{ trans('dashboard.schedule.schedule') }} + + + {{ trans('dashboard.schedule.add.title') }} + +
+
+
+
+ @include('partials.errors') +

{!! trans_choice('dashboard.schedule.logged', $schedule->count(), ['count' => $schedule->count()]) !!}

+ +
+ @foreach($schedule as $incident) +
+
+ {{ $incident->name }} +
+ {{ trans('dashboard.schedule.scheduled_at', ['timestamp' => $incident->scheduled_at_formatted]) }} + @if($incident->message) +

{{ Str::words($incident->message, 5) }}

+ @endif +
+ +
+ @endforeach +
+
+
+
+
+@stop diff --git a/resources/views/dashboard/metrics/add.blade.php b/resources/views/dashboard/metrics/add.blade.php index ac42e9c1106..2df0dbbecc1 100644 --- a/resources/views/dashboard/metrics/add.blade.php +++ b/resources/views/dashboard/metrics/add.blade.php @@ -1,80 +1,88 @@ @extends('layout.dashboard') @section('content') -
- - - {{ trans('dashboard.metrics.metrics') }} - - > {{ trans('dashboard.metrics.add.title') }} +
+ -
-
-
- @include('dashboard.partials.errors') -
- -
-
- - -
-
- - -
-
- -
- -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
-
-
-
- - {{ trans('forms.cancel') }} + + {{ trans('dashboard.metrics.metrics') }} + + > {{ trans('dashboard.metrics.add.title') }} +
+
+
+
+ @include('partials.errors') + + +
+
+ + +
+
+ + +
+
+ +
+
- -
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+ +
+
+ + {{ trans('forms.cancel') }} +
+
+
+
@stop diff --git a/resources/views/dashboard/metrics/edit.blade.php b/resources/views/dashboard/metrics/edit.blade.php index 149aa327805..0ad227f3989 100644 --- a/resources/views/dashboard/metrics/edit.blade.php +++ b/resources/views/dashboard/metrics/edit.blade.php @@ -1,83 +1,91 @@ @extends('layout.dashboard') @section('content') -
- - - {{ trans('dashboard.metrics.metrics') }} - - > {{ trans('dashboard.metrics.edit.title') }} +
+ -
-
-
- @include('dashboard.partials.errors') -
- -
-
- - -
-
- - -
-
- -
- -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- + + {{ trans('dashboard.metrics.metrics') }} + + > {{ trans('dashboard.metrics.edit.title') }} +
+
+
+
+ @include('partials.errors') + + +
+
+ + +
+
+ + +
+
+ +
+
-
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
- id}}> + id}}> -
-
- - {{ trans('forms.cancel') }} -
+
+
+ + {{ trans('forms.cancel') }}
- -
+
+
+
@stop diff --git a/resources/views/dashboard/metrics/index.blade.php b/resources/views/dashboard/metrics/index.blade.php index 9de3652be94..31fb0b705af 100644 --- a/resources/views/dashboard/metrics/index.blade.php +++ b/resources/views/dashboard/metrics/index.blade.php @@ -1,22 +1,21 @@ @extends('layout.dashboard') @section('content') -
-