Commit 74a8fc83 authored by webchick's avatar webchick

Issue #2578815 by hussainweb: Upgrade behat/mink and behat/mink-goutte-driver

parent 5b5d4035
......@@ -5,7 +5,6 @@
"This file is @generated automatically"
],
"hash": "8c9fdf621ce53640f24b24749e59717c",
"content-hash": "f38613812a285c03a1a18458384fe0b1",
"packages": [
{
"name": "composer/installers",
......@@ -2196,21 +2195,24 @@
"packages-dev": [
{
"name": "behat/mink",
"version": "v1.6.1",
"version": "v1.7.0",
"source": {
"type": "git",
"url": "https://github.com/minkphp/Mink.git",
"reference": "8b68523a339ec991bcd638b39dc8f04f808da88a"
"reference": "6c129030ec2cc029905cf969a56ca8f087b2dfdf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/minkphp/Mink/zipball/8b68523a339ec991bcd638b39dc8f04f808da88a",
"reference": "8b68523a339ec991bcd638b39dc8f04f808da88a",
"url": "https://api.github.com/repos/minkphp/Mink/zipball/6c129030ec2cc029905cf969a56ca8f087b2dfdf",
"reference": "6c129030ec2cc029905cf969a56ca8f087b2dfdf",
"shasum": ""
},
"require": {
"php": ">=5.3.1",
"symfony/css-selector": "~2.0"
"symfony/css-selector": "~2.1"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7"
},
"suggest": {
"behat/mink-browserkit-driver": "extremely fast headless driver for Symfony\\Kernel-based apps (Sf2, Silex)",
......@@ -2221,7 +2223,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.6.x-dev"
"dev-master": "1.7.x-dev"
}
},
"autoload": {
......@@ -2247,40 +2249,41 @@
"testing",
"web"
],
"time": "2015-02-04 17:02:06"
"time": "2015-09-20 20:24:03"
},
{
"name": "behat/mink-browserkit-driver",
"version": "v1.2.0",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/minkphp/MinkBrowserKitDriver.git",
"reference": "aed8f4a596b79014a75254c3e337511c33e38cbd"
"reference": "da47df1593dac132f04d24e7277ef40d33d9f201"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/minkphp/MinkBrowserKitDriver/zipball/aed8f4a596b79014a75254c3e337511c33e38cbd",
"reference": "aed8f4a596b79014a75254c3e337511c33e38cbd",
"url": "https://api.github.com/repos/minkphp/MinkBrowserKitDriver/zipball/da47df1593dac132f04d24e7277ef40d33d9f201",
"reference": "da47df1593dac132f04d24e7277ef40d33d9f201",
"shasum": ""
},
"require": {
"behat/mink": "~1.6@dev",
"php": ">=5.3.1",
"symfony/browser-kit": "~2.0",
"symfony/dom-crawler": "~2.0"
"behat/mink": "~1.7@dev",
"php": ">=5.3.6",
"symfony/browser-kit": "~2.3",
"symfony/dom-crawler": "~2.3"
},
"require-dev": {
"silex/silex": "~1.2"
"silex/silex": "~1.2",
"symfony/phpunit-bridge": "~2.7"
},
"type": "mink-driver",
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
"dev-master": "1.3.x-dev"
}
},
"autoload": {
"psr-0": {
"Behat\\Mink\\Driver": "src/"
"psr-4": {
"Behat\\Mink\\Driver\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
......@@ -2302,20 +2305,20 @@
"browser",
"testing"
],
"time": "2014-09-26 11:35:19"
"time": "2015-09-21 20:56:13"
},
{
"name": "behat/mink-goutte-driver",
"version": "dev-master",
"version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/minkphp/MinkGoutteDriver.git",
"reference": "cc5ce119b5a8e06662f634b35967aff0b0c7dfdd"
"reference": "c8e254f127d6f2242b994afd4339fb62d471df3f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/minkphp/MinkGoutteDriver/zipball/c8e254f127d6f2242b994afd4339fb62d471df3f",
"reference": "cc5ce119b5a8e06662f634b35967aff0b0c7dfdd",
"reference": "c8e254f127d6f2242b994afd4339fb62d471df3f",
"shasum": ""
},
"require": {
......@@ -2324,10 +2327,13 @@
"fabpot/goutte": "~1.0.4|~2.0|~3.1",
"php": ">=5.3.1"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7"
},
"type": "mink-driver",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
"dev-master": "1.2.x-dev"
}
},
"autoload": {
......@@ -2354,7 +2360,7 @@
"headless",
"testing"
],
"time": "2015-06-27 00:15:11"
"time": "2015-09-21 21:31:11"
},
{
"name": "doctrine/instantiator",
......@@ -3544,7 +3550,7 @@
"symfony/psr-http-message-bridge": 0,
"zendframework/zend-diactoros": 0,
"behat/mink": 0,
"behat/mink-goutte-driver": 20,
"behat/mink-goutte-driver": 0,
"mikey179/vfsstream": 0,
"phpunit/phpunit": 0,
"symfony/css-selector": 0
......
......@@ -32,7 +32,7 @@
},
"require-dev": {
"behat/mink": "~1.6",
"behat/mink-goutte-driver": "dev-master#cc5ce119b5a8e06662f634b35967aff0b0c7dfdd",
"behat/mink-goutte-driver": "~1.2",
"mikey179/vfsStream": "~1.2",
"phpunit/phpunit": "4.8.*",
"symfony/css-selector": "2.7.*"
......
language: php
sudo: false
php: [5.3, 5.4, 5.5, 5.6, hhvm]
matrix:
......@@ -9,12 +11,17 @@ matrix:
- php: 5.5
env: SYMFONY_VERSION='2.5.*@dev'
before_script:
cache:
directories:
- $HOME/.composer/cache/files
before_install:
- sh -c 'if [ "$SYMFONY_VERSION" != "" ]; then composer require -n --no-update symfony/symfony=$SYMFONY_VERSION; fi;'
- composer install -n --prefer-source
install:
- composer install -n
script: phpunit -v --coverage-clover=coverage.clover
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover coverage.clover
- wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover
1.3.0 / 2015-09-21
==================
BC break:
* Dropped support for Symfony 2.2 and older
* Bumped required PHP version to 5.3.6
New features:
* Updated the driver to use findElementsXpaths for Mink 1.7 and forward compatibility with Mink 2
Bug fixes:
* Improved the exception message when clicking on an invalid element
* Use `saveHTML` to get correct HTML code back
Misc:
* Updated the repository structure to PSR-4
1.2.0 / 2014-09-26
==================
......
......@@ -4,9 +4,9 @@ Mink BrowserKit Driver
[![Latest Stable Version](https://poser.pugx.org/behat/mink-browserkit-driver/v/stable.png)](https://packagist.org/packages/behat/mink-browserkit-driver)
[![Latest Unstable Version](https://poser.pugx.org/behat/mink-browserkit-driver/v/unstable.svg)](https://packagist.org/packages/behat/mink-browserkit-driver)
[![Total Downloads](https://poser.pugx.org/behat/mink-browserkit-driver/downloads.png)](https://packagist.org/packages/behat/mink-browserkit-driver)
[![Build Status](https://travis-ci.org/Behat/MinkBrowserKitDriver.svg?branch=master)](https://travis-ci.org/Behat/MinkBrowserKitDriver)
[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/Behat/MinkBrowserKitDriver/badges/quality-score.png?s=0443d284940e099ea560eb39b6b2fcdc5d4e7f29)](https://scrutinizer-ci.com/g/Behat/MinkBrowserKitDriver/)
[![Code Coverage](https://scrutinizer-ci.com/g/Behat/MinkBrowserKitDriver/badges/coverage.png?s=48960c4495488ab0b7d310b62322f017497f5bfa)](https://scrutinizer-ci.com/g/Behat/MinkBrowserKitDriver/)
[![Build Status](https://travis-ci.org/minkphp/MinkBrowserKitDriver.svg?branch=master)](https://travis-ci.org/minkphp/MinkBrowserKitDriver)
[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/minkphp/MinkBrowserKitDriver/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/minkphp/MinkBrowserKitDriver/)
[![Code Coverage](https://scrutinizer-ci.com/g/minkphp/MinkBrowserKitDriver/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/minkphp/MinkBrowserKitDriver/)
[![License](https://poser.pugx.org/behat/mink-browserkit-driver/license.svg)](https://packagist.org/packages/behat/mink-browserkit-driver)
Usage Example
......@@ -50,5 +50,5 @@ $> php composer.phar install
Maintainers
-----------
* Konstantin Kudryashov [everzet](http://github.com/everzet)
* Other [awesome developers](https://github.com/Behat/MinkBrowserKitDriver/graphs/contributors)
* Christophe Coevoet [stof](https://github.com/stof)
* Other [awesome developers](https://github.com/minkphp/MinkBrowserKitDriver/graphs/contributors)
......@@ -15,19 +15,20 @@
],
"require": {
"php": ">=5.3.1",
"behat/mink": "~1.6@dev",
"symfony/browser-kit": "~2.0",
"symfony/dom-crawler": "~2.0"
"php": ">=5.3.6",
"behat/mink": "~1.7@dev",
"symfony/browser-kit": "~2.3",
"symfony/dom-crawler": "~2.3"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7",
"silex/silex": "~1.2"
},
"autoload": {
"psr-0": {
"Behat\\Mink\\Driver": "src/"
"psr-4": {
"Behat\\Mink\\Driver\\": "src/"
}
},
......@@ -39,7 +40,7 @@
"extra": {
"branch-alias": {
"dev-master": "1.2.x-dev"
"dev-master": "1.3.x-dev"
}
}
}
......@@ -15,7 +15,7 @@
<filter>
<whitelist>
<directory>./src/Behat/Mink/Driver</directory>
<directory>./src</directory>
</whitelist>
</filter>
</phpunit>
......@@ -10,13 +10,10 @@
namespace Behat\Mink\Driver;
use Behat\Mink\Element\NodeElement;
use Behat\Mink\Exception\DriverException;
use Behat\Mink\Exception\UnsupportedDriverActionException;
use Behat\Mink\Session;
use Symfony\Component\BrowserKit\Client;
use Symfony\Component\BrowserKit\Cookie;
use Symfony\Component\BrowserKit\Request;
use Symfony\Component\BrowserKit\Response;
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\DomCrawler\Field\ChoiceFormField;
......@@ -25,8 +22,6 @@
use Symfony\Component\DomCrawler\Field\InputFormField;
use Symfony\Component\DomCrawler\Field\TextareaFormField;
use Symfony\Component\DomCrawler\Form;
use Symfony\Component\HttpFoundation\Request as HttpFoundationRequest;
use Symfony\Component\HttpFoundation\Response as HttpFoundationResponse;
use Symfony\Component\HttpKernel\Client as HttpKernelClient;
/**
......@@ -36,7 +31,6 @@
*/
class BrowserKitDriver extends CoreDriver
{
private $session;
private $client;
/**
......@@ -74,14 +68,6 @@ public function getClient()
return $this->client;
}
/**
* {@inheritdoc}
*/
public function setSession(Session $session)
{
$this->session = $session;
}
/**
* Tells driver to remove hostname from URL.
*
......@@ -164,19 +150,7 @@ public function visit($url)
*/
public function getCurrentUrl()
{
if (method_exists($this->client, 'getInternalRequest')) {
$request = $this->client->getInternalRequest();
} else {
// BC layer for BrowserKit 2.2.x and older
$request = $this->client->getRequest();
if (null !== $request && !$request instanceof Request && !$request instanceof HttpFoundationRequest) {
throw new DriverException(sprintf(
'The BrowserKit client returned an unsupported request implementation: %s. Please upgrade your BrowserKit package to 2.3 or newer.',
get_class($request)
));
}
}
$request = $this->client->getInternalRequest();
if ($request === null) {
throw new DriverException('Unable to access the request before visiting a page');
......@@ -345,13 +319,13 @@ public function getContent()
/**
* {@inheritdoc}
*/
public function find($xpath)
public function findElementXpaths($xpath)
{
$nodes = $this->getCrawler()->filterXPath($xpath);
$elements = array();
foreach ($nodes as $i => $node) {
$elements[] = new NodeElement(sprintf('(%s)[%d]', $xpath, $i + 1), $this->session);
$elements[] = sprintf('(%s)[%d]', $xpath, $i + 1);
}
return $elements;
......@@ -393,7 +367,7 @@ public function getOuterHtml($xpath)
{
$node = $this->getCrawlerNode($this->getFilteredCrawler($xpath));
return $node->ownerDocument->saveXML($node);
return $node->ownerDocument->saveHTML($node);
}
/**
......@@ -415,7 +389,7 @@ public function getAttribute($xpath, $name)
*/
public function getValue($xpath)
{
if (in_array($this->getAttribute($xpath, 'type'), array('submit', 'image', 'button'))) {
if (in_array($this->getAttribute($xpath, 'type'), array('submit', 'image', 'button'), true)) {
return $this->getAttribute($xpath, 'value');
}
......@@ -487,7 +461,7 @@ public function isSelected($xpath)
$selectField = $this->getFormField('(' . $xpath . ')/ancestor-or-self::*[local-name()="select"]');
$selectValue = $selectField->getValue();
return is_array($selectValue) ? in_array($optionValue, $selectValue) : $optionValue == $selectValue;
return is_array($selectValue) ? in_array($optionValue, $selectValue, true) : $optionValue === $selectValue;
}
/**
......@@ -495,19 +469,19 @@ public function isSelected($xpath)
*/
public function click($xpath)
{
$node = $this->getFilteredCrawler($xpath);
$crawlerNode = $this->getCrawlerNode($node);
$tagName = $crawlerNode->nodeName;
$crawler = $this->getFilteredCrawler($xpath);
$node = $this->getCrawlerNode($crawler);
$tagName = $node->nodeName;
if ('a' === $tagName) {
$this->client->click($node->link());
$this->client->click($crawler->link());
$this->forms = array();
} elseif ($this->canSubmitForm($crawlerNode)) {
$this->submit($node->form());
} elseif ($this->canResetForm($crawlerNode)) {
$this->resetForm($crawlerNode);
} elseif ($this->canSubmitForm($node)) {
$this->submit($crawler->form());
} elseif ($this->canResetForm($node)) {
$this->resetForm($node);
} else {
$message = sprintf('%%s supports clicking on links and buttons only. But "%s" provided', $tagName);
$message = sprintf('%%s supports clicking on links and submit or reset buttons only. But "%s" provided', $tagName);
throw new UnsupportedDriverActionException($message, $this);
}
......@@ -564,16 +538,6 @@ public function submitForm($xpath)
*/
protected function getResponse()
{
if (!method_exists($this->client, 'getInternalResponse')) {
$implementationResponse = $this->client->getResponse();
if (null === $implementationResponse) {
throw new DriverException('Unable to access the response before visiting a page');
}
return $this->convertImplementationResponse($implementationResponse);
}
$response = $this->client->getInternalResponse();
if (null === $response) {
......@@ -583,64 +547,6 @@ protected function getResponse()
return $response;
}
/**
* Gets the BrowserKit Response for legacy BrowserKit versions.
*
* Before 2.3.0, there was no Client::getInternalResponse method, and the
* return value of Client::getResponse can be anything when the implementation
* uses Client::filterResponse because of a bad choice done in BrowserKit and
* kept for BC reasons (the Client::getInternalResponse method has been added
* to solve it).
*
* This implementation supports client which don't rely Client::filterResponse
* and clients which use an HttpFoundation Response (like the HttpKernel client).
*
* @param object $response the response specific to the BrowserKit implementation
*
* @return Response
*
* @throws DriverException If the response cannot be converted to a BrowserKit response
*/
private function convertImplementationResponse($response)
{
if ($response instanceof Response) {
return $response;
}
// due to a bug, the HttpKernel client implementation returns the HttpFoundation response
// The conversion logic is copied from Symfony\Component\HttpKernel\Client::filterResponse
if ($response instanceof HttpFoundationResponse) {
$headers = $response->headers->all();
if ($response->headers->getCookies()) {
$cookies = array();
foreach ($response->headers->getCookies() as $cookie) {
$cookies[] = new Cookie(
$cookie->getName(),
$cookie->getValue(),
$cookie->getExpiresTime(),
$cookie->getPath(),
$cookie->getDomain(),
$cookie->isSecure(),
$cookie->isHttpOnly()
);
}
$headers['Set-Cookie'] = $cookies;
}
// this is needed to support StreamedResponse
ob_start();
$response->sendContent();
$content = ob_get_clean();
return new Response($content, $response->getStatusCode(), $headers);
}
throw new DriverException(sprintf(
'The BrowserKit client returned an unsupported response implementation: %s. Please upgrade your BrowserKit package to 2.3 or newer.',
get_class($response)
));
}
/**
* Prepares URL for visiting.
* Removes "*.php/" from urls and then passes it to BrowserKitDriver::visit().
......@@ -810,11 +716,11 @@ private function canSubmitForm(\DOMElement $node)
{
$type = $node->hasAttribute('type') ? $node->getAttribute('type') : null;
if ('input' == $node->nodeName && in_array($type, array('submit', 'image'))) {
if ('input' === $node->nodeName && in_array($type, array('submit', 'image'), true)) {
return true;
}
return 'button' == $node->nodeName && (null === $type || 'submit' == $type);
return 'button' === $node->nodeName && (null === $type || 'submit' === $type);
}
/**
......@@ -828,7 +734,7 @@ private function canResetForm(\DOMElement $node)
{
$type = $node->hasAttribute('type') ? $node->getAttribute('type') : null;
return in_array($node->nodeName, array('input', 'button')) && 'reset' == $type;
return in_array($node->nodeName, array('input', 'button'), true) && 'reset' === $type;
}
/**
......@@ -881,10 +787,10 @@ private function mergeForms(Form $to, Form $from)
$nodeReflection->setAccessible(true);
$valueReflection->setAccessible(true);
if (!($field instanceof InputFormField && in_array(
$nodeReflection->getValue($field)->getAttribute('type'),
array('submit', 'button', 'image')
))) {
$isIgnoredField = $field instanceof InputFormField &&
in_array($nodeReflection->getValue($field)->getAttribute('type'), array('submit', 'button', 'image'), true);
if (!$isIgnoredField) {
$valueReflection->setValue($to[$name], $valueReflection->getValue($field));
}
}
......
......@@ -127,7 +127,7 @@ public function testManipulateInputWithoutForm()
/**
* @expectedException \Behat\Mink\Exception\DriverException
* @expectedExceptionMessage Behat\Mink\Driver\BrowserKitDriver supports clicking on links and buttons only. But "div" provided
* @expectedExceptionMessage Behat\Mink\Driver\BrowserKitDriver supports clicking on links and submit or reset buttons only. But "div" provided
*/
public function testClickOnUnsupportedElement()
{
......
language: php
sudo: false
cache:
directories:
- $HOME/.composer/cache/files
php: [5.3, 5.4, 5.5, 5.6, hhvm]
before_install:
# Force using Goutte 2 on HHVM for now because Guzzle 6 is broken there
- if [ "hhvm" = "$TRAVIS_PHP_VERSION" ]; then composer require fabpot/goutte '~2' --no-update; fi
before_script:
- export WEB_FIXTURES_HOST=http://localhost
install:
- composer install
- composer install --dev --prefer-source
before_script:
- export WEB_FIXTURES_HOST=http://localhost:8000
- sudo apt-get update
- sudo apt-get install -y --force-yes apache2 libapache2-mod-php5
- sudo sed -i -e "s,/var/www,$(pwd)/vendor/behat/mink/driver-testsuite/web-fixtures,g" /etc/apache2/sites-available/default
- sudo /etc/init.d/apache2 restart
# Start a webserver for web fixtures. Force using PHP 5.6 to be able to run it on PHP 5.3 and HHVM jobs too
- ~/.phpenv/versions/5.6/bin/php -S localhost:8000 -t vendor/behat/mink/driver-testsuite/web-fixtures > /dev/null 2>&1 &
script: phpunit -v --coverage-clover=coverage.clover
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover coverage.clover
- wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover
1.2.0 / 2015-09-21
==================
New features:
* Added support for Goutte 3.1+
Misc:
* Updated the repository structure to PSR-4
1.1.0 / 2014-10-09
==================
......
......@@ -21,6 +21,10 @@
"fabpot/goutte": "~1.0.4|~2.0|~3.1"
},
"require-dev": {
"symfony/phpunit-bridge": "~2.7"
},
"autoload": {
"psr-4": {
"Behat\\Mink\\Driver\\": "src/"
......@@ -35,7 +39,7 @@
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
"dev-master": "1.2.x-dev"
}
}
}
......@@ -2,16 +2,27 @@ language: php
sudo: false
php: [5.3, 5.4, 5.5, 5.6, hhvm]
php: [5.3, 5.4, 5.5, 5.6, 7.0, hhvm]
matrix:
fast_finish: true
include:
- php: 5.3
env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable' SYMFONY_DEPRECATIONS_HELPER=weak
allow_failures:
- php: 7.0
cache:
directories:
- $HOME/.composer/cache
- $HOME/.composer/cache/files
before_install:
- composer self-update
install:
- composer install
- composer update $COMPOSER_FLAGS
script: phpunit -v --coverage-clover=coverage.clover
after_script:
- wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover
- if [[ "7.0" != "$TRAVIS_PHP_VERSION" && "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then wget https://scrutinizer-ci.com/ocular.phar && php ocular.phar code-coverage:upload --format=php-clover coverage.clover; fi
1.7.0 / 2015-09-20
==================
New features:
* Added `Session::getResponseHeader` to access a response header easily
* Added support for header assertions
* Added a forward compatibility layer for drivers to allow them to prepare
for Mink 2.0 (they won't require any change if they use it). They should
now overwrite `CoreDriver::findElementXpaths` instead of implementing `find`
and `setSession` themselves.
* Added escaping of the locator in the NamedSelector rather than expecting
the caller to perform the escaping. Passing an escaped locator is still
supported but deprecated.
* Remove the dependency on the Session in expectation exceptions. Passing
the session in the exception constructor is now deprecated. The driver
should be passed instead.
Bug fixes:
* Fixed the URL assertions when comparing paths ending in ``.php``
* Silenced deprecation warnings (following the Symfony convention) to make
them less invasive. Use the `symfony/phpunit-bridge` to get them reported
when using Mink in your PHPUnit tests.
* Fixed `NodeElement::hasClass` in case the class attribute contains newlines
Testsuite:
* Made the testsuite compatible with PHPUnit strict timing mode (only the library testsuite, not the driver one)
* Added testing against PHP 7
* Added testing against lowest version of dependencies to ensure we got the lower bounds right
Driver testsuite:
* Added an extra test to ensure the right behavior when getting the HTML with empty elements
* Added a few more safeguards to ensure test failures rather than fatal errors for misbehaving drivers
* Added a test ensuring that drivers follow recommended practices
Misc:
* Added a few missing deprecation warnings for deprecated APIs or classes.
1.6.1 / 2015-02-04
==================