├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── config └── mailcoach-sdk.php └── src ├── Exceptions └── MailcoachException.php ├── Facades └── Mailcoach.php ├── MailcoachSdkServiceProvider.php └── Testing └── MailcoachFake.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `laravel-mailcoach-sdk` will be documented in this file. 4 | 5 | ## 1.4.0 - 2025-02-25 6 | 7 | ### What's Changed 8 | 9 | * Bump dependabot/fetch-metadata from 2.2.0 to 2.3.0 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/30 10 | * Bump aglipanci/laravel-pint-action from 2.4 to 2.5 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/31 11 | * Add Laravel 12 support by @the-pulli in https://github.com/spatie/laravel-mailcoach-sdk/pull/33 12 | 13 | ### New Contributors 14 | 15 | * @the-pulli made their first contribution in https://github.com/spatie/laravel-mailcoach-sdk/pull/33 16 | 17 | **Full Changelog**: https://github.com/spatie/laravel-mailcoach-sdk/compare/1.3.0...1.4.0 18 | 19 | ## 1.3.0 - 2024-07-30 20 | 21 | ### What's Changed 22 | 23 | * Add a basic `Mailcoach::fake()` method that creates a fake and records the requests 24 | * Bump aglipanci/laravel-pint-action from 2.3.1 to 2.4 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/25 25 | * Bump dependabot/fetch-metadata from 1.6.0 to 2.1.0 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/26 26 | * Bump dependabot/fetch-metadata from 2.1.0 to 2.2.0 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/27 27 | 28 | **Full Changelog**: https://github.com/spatie/laravel-mailcoach-sdk/compare/1.2.0...1.3.0 29 | 30 | ## 1.2.0 - 2024-03-14 31 | 32 | ### What's Changed 33 | 34 | * Bump aglipanci/laravel-pint-action from 2.3.0 to 2.3.1 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/23 35 | 36 | **Full Changelog**: https://github.com/spatie/laravel-mailcoach-sdk/compare/1.1.0...1.2.0 37 | 38 | ## 1.1.0 - 2023-10-11 39 | 40 | ### What's Changed 41 | 42 | - improve error exception for missing credentials by @Nielsvanpach in https://github.com/spatie/laravel-mailcoach-sdk/pull/21 43 | - Add tags attribute to example by @janiskelemen in https://github.com/spatie/laravel-mailcoach-sdk/pull/9 44 | - Bump actions/checkout from 3 to 4 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/19 45 | - Bump dependabot/fetch-metadata from 1.3.5 to 1.3.6 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/7 46 | - Bump aglipanci/laravel-pint-action from 2.1.0 to 2.2.0 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/12 47 | - Bump dependabot/fetch-metadata from 1.3.6 to 1.4.0 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/13 48 | - Bump dependabot/fetch-metadata from 1.4.0 to 1.5.0 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/15 49 | - Bump aglipanci/laravel-pint-action from 2.2.0 to 2.3.0 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/16 50 | - Bump dependabot/fetch-metadata from 1.5.0 to 1.5.1 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/17 51 | - Bump dependabot/fetch-metadata from 1.5.1 to 1.6.0 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/18 52 | - Bump stefanzweifel/git-auto-commit-action from 4 to 5 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/20 53 | 54 | ### New Contributors 55 | 56 | - @janiskelemen made their first contribution in https://github.com/spatie/laravel-mailcoach-sdk/pull/9 57 | - @Nielsvanpach made their first contribution in https://github.com/spatie/laravel-mailcoach-sdk/pull/21 58 | 59 | **Full Changelog**: https://github.com/spatie/laravel-mailcoach-sdk/compare/1.0.2...1.1.0 60 | 61 | ## 1.0.2 - 2023-01-26 62 | 63 | - support L10 64 | 65 | ## 1.0.1 - 2023-01-04 66 | 67 | ### What's Changed 68 | 69 | - Fix typo by @michaelnabil230 in https://github.com/spatie/laravel-mailcoach-sdk/pull/1 70 | - Update readme by @1stevengrant in https://github.com/spatie/laravel-mailcoach-sdk/pull/3 71 | - Use correct class name in @see docblock by @ash-jc-allen in https://github.com/spatie/laravel-mailcoach-sdk/pull/5 72 | - Bump aglipanci/laravel-pint-action from 1.0.0 to 2.1.0 by @dependabot in https://github.com/spatie/laravel-mailcoach-sdk/pull/4 73 | - Removed unused command by @ash-jc-allen in https://github.com/spatie/laravel-mailcoach-sdk/pull/6 74 | 75 | ### New Contributors 76 | 77 | - @michaelnabil230 made their first contribution in https://github.com/spatie/laravel-mailcoach-sdk/pull/1 78 | - @1stevengrant made their first contribution in https://github.com/spatie/laravel-mailcoach-sdk/pull/3 79 | - @ash-jc-allen made their first contribution in https://github.com/spatie/laravel-mailcoach-sdk/pull/5 80 | - @dependabot made their first contribution in https://github.com/spatie/laravel-mailcoach-sdk/pull/4 81 | 82 | **Full Changelog**: https://github.com/spatie/laravel-mailcoach-sdk/compare/1.0.0...1.0.1 83 | 84 | ## 1.0.0 - 2022-11-08 85 | 86 | - initial release 87 | 88 | ## 0.0.1 - 2022-11-08 89 | 90 | - experimental release 91 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) spatie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # An SDK to easily work with the Mailcoach API in Laravel apps 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/spatie/laravel-mailcoach-sdk.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-mailcoach-sdk) 4 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/spatie/laravel-mailcoach-sdk/run-tests.yml?label=tests)](https://github.com/spatie/laravel-mailcoach-sdk/actions?query=workflow%3Arun-tests+branch%3Amain) 5 | [![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/spatie/laravel-mailcoach-sdk/fix-php-code-style-issues.yml?label=code%20style)](https://github.com/spatie/laravel-mailcoach-sdk/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/spatie/laravel-mailcoach-sdk.svg?style=flat-square)](https://packagist.org/packages/spatie/laravel-mailcoach-sdk) 7 | 8 | This package contains the PHP SDK to work with [Mailcoach](https://mailcoach.app). Both self-hosted (v6 and up) and hosted Mailcoach (aka Mailcoach Cloud) are supported. Using this package you can manage email lists, subscribers and campaigns. 9 | 10 | Here are a few examples: 11 | 12 | ```php 13 | use Spatie\MailcoachSdk\Facades\Mailcoach; 14 | 15 | // creating a campaign 16 | $campaign = Mailcoach::createCampaign([ 17 | 'email_list_uuid' => 'use-a-real-email-list-uuid-here', 18 | 'name' => 'My new campaign', 19 | 'fields' => [ 20 | 'title' => 'The title on top of the newsletter', 21 | 'content' => '# Welcome to my newsletter', 22 | ], 23 | ]); 24 | 25 | // sending a test of the campaign to the given email address 26 | $campaign->sendTest('john@example.com'); 27 | 28 | // sending a campaign 29 | $campaign->send(); 30 | ``` 31 | 32 | By default, Mailcoach' endpoints will are paginated with a limit of 1000. The package makes it easy to work with paginated resources. Just call `->next()` to get the next page. 33 | 34 | ```php 35 | // listing all subscribers of a list 36 | $subscribers = $mailcoach->emailList('use-a-real-email-list-uuid-here')->subscribers(); 37 | 38 | do { 39 | foreach($subscribers as $subscriber) { 40 | echo $subscriber->email; 41 | } 42 | } while($subscribers = $subscribers->next()) 43 | ``` 44 | 45 | ## Support us 46 | 47 | [](https://spatie.be/github-ad-click/laravel-mailcoach-sdk) 48 | 49 | We invest a lot of resources into creating [best in class open source packages](https://spatie.be/open-source). You can support us by [buying one of our paid products](https://spatie.be/open-source/support-us). 50 | 51 | We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on [our contact page](https://spatie.be/about-us). We publish all received postcards on [our virtual postcard wall](https://spatie.be/open-source/postcards). 52 | 53 | ## Installation 54 | 55 | You can install the package via composer: 56 | 57 | ```bash 58 | composer require spatie/laravel-mailcoach-sdk 59 | ``` 60 | 61 | You must publish the config file with: 62 | 63 | ```bash 64 | php artisan vendor:publish --tag="mailcoach-sdk-config" 65 | ``` 66 | 67 | This is the contents of the published config file: 68 | 69 | ```php 70 | return [ 71 | /* 72 | * You'll find both the API token and endpoint on Mailcoach' 73 | * API tokens screen in the Mailcoach settings. 74 | */ 75 | 'api_token' => env('MAILCOACH_API_TOKEN'), 76 | 77 | 'endpoint' => env('MAILCOACH_API_ENDPOINT'), 78 | ]; 79 | ``` 80 | 81 | In your `.env` file you should add the entries from the config file mentioned above. You'll find both the API token and endpoint on Mailcoach' API tokens screen in the Mailcoach settings. 82 | 83 | ## Usage 84 | 85 | You can use the `Spatie\MailcoachSdk\Facades\Mailcoach` facade to perform most operations. 86 | 87 | ### Handling pagination 88 | 89 | There are several methods, such as `emailLists()`, 'subscribers()' and `campaigns()` to will return paginated results. To get the next page of results just call `next()` on a result. If there are no more results, that method returns `null`. 90 | 91 | Here's how you display the email addresses of every subscriber on a list 92 | 93 | ```php 94 | use Spatie\MailcoachSdk\Facades\Mailcoach; 95 | 96 | $subscribers = Mailcoach::subscribers('email; 101 | } 102 | } while($subscribers = $subscribers->next()) 103 | ``` 104 | 105 | On paginated results, `$subscribers` in the example above there are also some more convenience methods: 106 | 107 | - `results()`: get the results. A results object is also iterable, so you can also get to the results by simply using the object in a loop 108 | - `next()`: fetch the next page of results 109 | - `previous()`: fetch the previous page of results 110 | - `currentPage()`: get the current page number 111 | - `total()`: get the total number of results across all pages 112 | - `nextUrl()`: get the URL that will be called to get the next page of results 113 | - `previousUrl()`: get the URL that will be called to get the previous page of results 114 | 115 | ### Working with email lists 116 | 117 | Here's how to get all email lists: 118 | 119 | ```php 120 | use Spatie\MailcoachSdk\Facades\Mailcoach; 121 | 122 | $emailLists = Mailcoach::emailLists(); 123 | ``` 124 | 125 | You can get a single email list: 126 | 127 | ```php 128 | $emailList = $this->mailcoach->emailList(''); 129 | ``` 130 | 131 | This is how you can create an email list: 132 | 133 | ```php 134 | use Spatie\MailcoachSdk\Facades\Mailcoach; 135 | 136 | Mailcoach::createEmailList(['name' => 'My new email list']); 137 | ``` 138 | 139 | You can get properties of email list: 140 | 141 | ```php 142 | $emailList->name; 143 | $emailList->uuid; 144 | // ... 145 | ``` 146 | 147 | Take a look at the source code of `Spatie\MailcoachSdk\Resources\EmailList` to see the list of available properties. 148 | 149 | You can update an email list by change one of the properties and calling `save()`. 150 | 151 | ```php 152 | $emailList->name = 'Updated name'; 153 | $emailList->save(); 154 | ``` 155 | 156 | You can delete an email list by calling `delete()`. 157 | 158 | ```php 159 | $emailList->delete(); 160 | ``` 161 | 162 | ### Working with subscribers 163 | 164 | To get all subscribers of a list, you can call `subscribers()` on an email list. 165 | 166 | ```php 167 | use Spatie\MailcoachSdk\Facades\Mailcoach; 168 | 169 | $subscribers = Mailcoach::emailList('')->subscribers(); 170 | ``` 171 | 172 | Optionally, you can pass filters to `subscribers()`. Here how to get all subscribers with a Gmail-address. 173 | 174 | ```php 175 | use Spatie\MailcoachSdk\Facades\Mailcoach; 176 | 177 | $subscribers = Mailcoach::emailList('') 178 | ->subscribers(['filter[email]=gmail.com']); 179 | ``` 180 | 181 | Alternatively, you can call `subscribers()` on `$mailcoach` 182 | 183 | ```php 184 | use Spatie\MailcoachSdk\Facades\Mailcoach; 185 | 186 | $subscribers = Mailcoach::subscribers('', $optionalFilters); 187 | ``` 188 | 189 | There's also a convenience method to quickly get a subscriber from a list. 190 | 191 | ```php 192 | // returns instance of Spatie\MailcoachSdk\Resources\Subscriber 193 | // or null if the subscriber does not exist. 194 | 195 | $subscriber = $emaillist->subscriber('john@example.com'); 196 | ``` 197 | Alternatively, you can get a subscriber by its UUID: 198 | 199 | ```php 200 | $subscriber = $mailcoach->subscriber(''); 201 | ``` 202 | 203 | This how you can create a subscriber: 204 | 205 | ```php 206 | use Spatie\MailcoachSdk\Facades\Mailcoach; 207 | 208 | $subscriber = Mailcoach::createSubscriber( 209 | emailListUuid: '', 210 | attributes: [ 211 | 'email' => '', 212 | 'first_name' => 'John', 213 | 'last_name' => 'Doe', 214 | 'tags' => ['Newsletter'], 215 | ]); 216 | ``` 217 | 218 | You can get properties of a subscriber: 219 | 220 | ```php 221 | $subscriber->firstName; 222 | $subscriber->email; 223 | // ... 224 | ``` 225 | 226 | Take a look at the source code of `Spatie\MailcoachSdk\Resources\Subscriber` to see the list of available properties. 227 | 228 | You can update a subscriber by change one of the properties and calling `save()`. 229 | 230 | ```php 231 | $subscriber->firstName = 'Updated name'; 232 | $subscriber->save(); 233 | ``` 234 | 235 | You can confirm, unsubscribe and delete a subscriber by calling these methods. 236 | 237 | ```php 238 | $subscriber->confirm(); 239 | $subscriber->unsubscribe(); 240 | $subscriber->delete(); 241 | ``` 242 | 243 | ### Working with campaigns 244 | 245 | Here's how to get all campaigns. 246 | 247 | ```php 248 | use Spatie\MailcoachSdk\Facades\Mailcoach; 249 | 250 | $campaigns = Mailcoach::campaigns(); 251 | ``` 252 | 253 | You can also get a single campaign(); 254 | 255 | ```php 256 | use Spatie\MailcoachSdk\Facades\Mailcoach; 257 | 258 | $campaign = Mailcoach::campaign(''); 259 | ``` 260 | 261 | This is how you can create a campaign: 262 | 263 | ```php 264 | use Spatie\MailcoachSdk\Facades\Mailcoach; 265 | 266 | $campaign = Mailcoach::createCampaign([ 267 | 'name' => 'My new campaign', 268 | 'subject' => 'Here is some fantastic content for you', 269 | 'email_list_uuid' => '', 270 | 271 | // optionally, you can specify the uuid of a template 272 | 'template_uuid' => '', 273 | 274 | // if that template has field, you can pass the values 275 | // in the `fields` array. If you use the markdown editor, 276 | // we'll automatically handle any passed markdown 277 | 'fields' => [ 278 | 'title' => 'Content for the title place holder', 279 | 'content' => '# My title', 280 | ], 281 | ]); 282 | ``` 283 | 284 | You can get properties of a campaign: 285 | 286 | ```php 287 | $campaign->name; 288 | $campaign->subject; 289 | // ... 290 | ``` 291 | 292 | Take a look at the source code of `Spatie\MailcoachSdk\Resources\Campaign` to see the list of available properties. 293 | 294 | You can update a campaign by change one of the properties and calling `save()`. 295 | 296 | ```php 297 | $campaign->name = 'Campaign'; 298 | $campaign->save(); 299 | ``` 300 | 301 | A test mail will be sent when calling `sendTest()`: 302 | 303 | ```php 304 | // sending a test to a single person 305 | $campaign->sendTest('john@example.com'); 306 | 307 | // sending a test to multiple persons 308 | $campaign->sendTest(['john@example.com', 'jane@example.com']); 309 | ``` 310 | 311 | The campaign will be sent to all subscribers of your list, by calling `send()`: 312 | 313 | ```php 314 | $campaign->send(); 315 | ``` 316 | 317 | A campaign can be deleted: 318 | 319 | ```php 320 | $campaign->delete(); 321 | ``` 322 | 323 | ## Testing 324 | 325 | ```bash 326 | composer test 327 | ``` 328 | 329 | ## Changelog 330 | 331 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 332 | 333 | ## Contributing 334 | 335 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 336 | 337 | ## Security Vulnerabilities 338 | 339 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 340 | 341 | ## Credits 342 | 343 | - [Freek Van der Herten](https://github.com/freekmurze) 344 | - [All Contributors](../../contributors) 345 | 346 | ## License 347 | 348 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 349 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spatie/laravel-mailcoach-sdk", 3 | "description": "An SDK to easily work with the Mailcoach API in Laravel apps", 4 | "keywords": [ 5 | "spatie", 6 | "laravel", 7 | "laravel-mailcoach-sdk" 8 | ], 9 | "homepage": "https://github.com/spatie/laravel-mailcoach-sdk", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Freek Van der Herten", 14 | "email": "freek@spatie.be", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.2", 20 | "guzzlehttp/guzzle": "^6.0|^7.5", 21 | "illuminate/contracts": "^9.0|^10.0|^11.0|^12.0", 22 | "spatie/laravel-package-tools": "^1.13.0", 23 | "spatie/mailcoach-sdk-php": "^1.0" 24 | }, 25 | "require-dev": { 26 | "laravel/pint": "^1.0", 27 | "nunomaduro/collision": "^6.0|^7.0|^8.0", 28 | "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", 29 | "pestphp/pest": "^1.19|^2.0|^3.0", 30 | "pestphp/pest-plugin-laravel": "^v1.4.0|^2.0|^3.0", 31 | "spatie/laravel-ray": "^1.26" 32 | }, 33 | "autoload": { 34 | "psr-4": { 35 | "Spatie\\MailcoachSdk\\": "src", 36 | "Spatie\\MailcoachSdk\\Database\\Factories\\": "database/factories" 37 | } 38 | }, 39 | "autoload-dev": { 40 | "psr-4": { 41 | "Spatie\\MailcoachSdk\\Tests\\": "tests" 42 | } 43 | }, 44 | "scripts": { 45 | "post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi", 46 | "test": "vendor/bin/pest", 47 | "test-coverage": "vendor/bin/pest --coverage", 48 | "format": "vendor/bin/pint" 49 | }, 50 | "config": { 51 | "sort-packages": true, 52 | "allow-plugins": { 53 | "pestphp/pest-plugin": true, 54 | "phpstan/extension-installer": true 55 | } 56 | }, 57 | "extra": { 58 | "laravel": { 59 | "providers": [ 60 | "Spatie\\MailcoachSdk\\MailcoachSdkServiceProvider" 61 | ], 62 | "aliases": { 63 | "MailcoachSdk": "Spatie\\MailcoachSdk\\Facades\\MailcoachSdk" 64 | } 65 | } 66 | }, 67 | "minimum-stability": "dev", 68 | "prefer-stable": true 69 | } 70 | -------------------------------------------------------------------------------- /config/mailcoach-sdk.php: -------------------------------------------------------------------------------- 1 | env('MAILCOACH_API_TOKEN'), 9 | 10 | 'endpoint' => env('MAILCOACH_API_ENDPOINT'), 11 | ]; 12 | -------------------------------------------------------------------------------- /src/Exceptions/MailcoachException.php: -------------------------------------------------------------------------------- 1 | name('laravel-mailcoach-sdk') 15 | ->hasConfigFile(); 16 | } 17 | 18 | public function registeringPackage(): void 19 | { 20 | $this->app->bind(Mailcoach::class, function () { 21 | if (config('mailcoach-sdk.api_token') === null) { 22 | throw MailcoachException::missingApiToken(); 23 | } 24 | 25 | if (config('mailcoach-sdk.endpoint') === null) { 26 | throw MailcoachException::missingEndpoint(); 27 | } 28 | 29 | return new Mailcoach( 30 | config('mailcoach-sdk.api_token'), 31 | config('mailcoach-sdk.endpoint'), 32 | ); 33 | }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Testing/MailcoachFake.php: -------------------------------------------------------------------------------- 1 | requests[] = [ 20 | 'verb' => $verb, 21 | 'uri' => $uri, 22 | 'payload' => $payload, 23 | ]; 24 | 25 | return [ 26 | 'data' => [], 27 | 'links' => [], 28 | 'meta' => [], 29 | ]; 30 | } 31 | 32 | public function getRequests(): array 33 | { 34 | return $this->requests; 35 | } 36 | } 37 | --------------------------------------------------------------------------------