Skip to content

Commit

Permalink
Merge pull request #1 from PHPCompatibility/feature/initial-release
Browse files Browse the repository at this point in the history
Initial commit / v 1.0.0
  • Loading branch information
jrfnl committed Oct 7, 2018
2 parents fb5bdf5 + 18c0fac commit 83d18e6
Show file tree
Hide file tree
Showing 20 changed files with 417 additions and 1 deletion.
15 changes: 15 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#
# Exclude these files from release archives.
# https://blog.madewithlove.be/post/gitattributes/
#
/.gitattributes export-ignore
/.gitignore export-ignore
/.travis.yml export-ignore
/.github/ export-ignore
/Test/ export-ignore

#
# Auto detect text files and perform LF normalization
# http://davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
#
* text=auto
9 changes: 9 additions & 0 deletions .github/issue_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!--
This repository is only for the PHPCompatibilitySymfony rulesets, which prevent false positives from the PHPCompatibility standard by excluding the poly-fills which are provided by the various Symfony polyfill libraries.
If your issue is related to the PHPCompatibility sniffs, please open an issue in the PHPCompatibility repository: https://github.com/PHPCompatibility/PHPCompatibility/issues
Before opening a new issue, please search for your issue to prevent opening a duplicate. If there is already an open issue, please leave a comment there.
Thanks!
-->
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/vendor/
composer.lock
60 changes: 60 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
sudo: false

dist: trusty

cache:
apt: true

language: php

## Cache composer downloads.
cache:
directories:
- $HOME/.cache/composer/files

matrix:
fast_finish: true
include:
- php: 7.2
addons:
apt:
packages:
- libxml2-utils
- php: 5.4

before_install:
# Speed up build time by disabling Xdebug when its not needed.
- if [[ $COVERALLS_VERSION == "notset" ]]; then phpenv config-rm xdebug.ini || echo 'No xdebug config.'; fi
- export XMLLINT_INDENT=" "
- composer install
- vendor/bin/phpcs -i

script:
- |
if [[ $TRAVIS_PHP_VERSION == "7.2" ]]; then
# Validate the xml files.
# @link http://xmlsoft.org/xmllint.html
xmllint --noout ./*/ruleset.xml
# Check the code-style consistency of the xml files.
diff -B ./PHPCompatibilitySymfonyPolyfillPHP54/ruleset.xml <(xmllint --format "./PHPCompatibilitySymfonyPolyfillPHP54/ruleset.xml")
diff -B ./PHPCompatibilitySymfonyPolyfillPHP55/ruleset.xml <(xmllint --format "./PHPCompatibilitySymfonyPolyfillPHP55/ruleset.xml")
diff -B ./PHPCompatibilitySymfonyPolyfillPHP56/ruleset.xml <(xmllint --format "./PHPCompatibilitySymfonyPolyfillPHP56/ruleset.xml")
diff -B ./PHPCompatibilitySymfonyPolyfillPHP70/ruleset.xml <(xmllint --format "./PHPCompatibilitySymfonyPolyfillPHP70/ruleset.xml")
diff -B ./PHPCompatibilitySymfonyPolyfillPHP71/ruleset.xml <(xmllint --format "./PHPCompatibilitySymfonyPolyfillPHP71/ruleset.xml")
diff -B ./PHPCompatibilitySymfonyPolyfillPHP72/ruleset.xml <(xmllint --format "./PHPCompatibilitySymfonyPolyfillPHP72/ruleset.xml")
diff -B ./PHPCompatibilitySymfonyPolyfillPHP73/ruleset.xml <(xmllint --format "./PHPCompatibilitySymfonyPolyfillPHP73/ruleset.xml")
fi
# Test the rulesets.
- vendor/bin/phpcs ./Test/SymfonyPolyfillPHP54Test.php --standard=PHPCompatibilitySymfonyPolyfillPHP54 --runtime-set testVersion 5.3
- vendor/bin/phpcs ./Test/SymfonyPolyfillPHP55Test.php --standard=PHPCompatibilitySymfonyPolyfillPHP55 --runtime-set testVersion 5.3
- vendor/bin/phpcs ./Test/SymfonyPolyfillPHP56Test.php --standard=PHPCompatibilitySymfonyPolyfillPHP56 --runtime-set testVersion 5.3
- vendor/bin/phpcs ./Test/SymfonyPolyfillPHP70Test.php --standard=PHPCompatibilitySymfonyPolyfillPHP70 --runtime-set testVersion 5.3
- vendor/bin/phpcs ./Test/SymfonyPolyfillPHP71Test.php --standard=PHPCompatibilitySymfonyPolyfillPHP71 --runtime-set testVersion 5.3
- vendor/bin/phpcs ./Test/SymfonyPolyfillPHP72Test.php --standard=PHPCompatibilitySymfonyPolyfillPHP72 --runtime-set testVersion 5.3
- vendor/bin/phpcs ./Test/SymfonyPolyfillPHP73Test.php --standard=PHPCompatibilitySymfonyPolyfillPHP73 --runtime-set testVersion 5.3

# Validate the composer.json file.
# @link https://getcomposer.org/doc/03-cli.md#validate
- composer validate --no-check-all --strict
18 changes: 18 additions & 0 deletions PHPCompatibilitySymfonyPolyfillPHP54/ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<ruleset name="PHPCompatibilitySymfonyPolyfillPHP54">
<description>PHPCompatibility ruleset for PHP_CodeSniffer which accounts for polyfills provided by the Symfony PHP 5.4 library.</description>

<rule ref="PHPCompatibility">
<!-- https://github.com/symfony/polyfill-php54/blob/master/bootstrap.php -->
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.trait_existsFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.class_usesFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.hex2binFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.session_register_shutdownFound"/>

<!-- https://github.com/symfony/polyfill-php54/tree/master/Resources/stubs -->
<exclude name="PHPCompatibility.Classes.NewClasses.callbackfilteriteratorFound"/>
<exclude name="PHPCompatibility.Classes.NewClasses.recursivecallbackfilteriteratorFound"/>
<exclude name="PHPCompatibility.Interfaces.NewInterfaces.sessionhandlerinterfaceFound"/>
</rule>

</ruleset>
16 changes: 16 additions & 0 deletions PHPCompatibilitySymfonyPolyfillPHP55/ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<ruleset name="PHPCompatibilitySymfonyPolyfillPHP55">
<description>PHPCompatibility ruleset for PHP_CodeSniffer which accounts for polyfills provided by the Symfony PHP 5.5 library.</description>

<!-- https://github.com/symfony/polyfill-php55/blob/master/composer.json -->
<rule ref="PHPCompatibilityPasswordCompat"/>

<rule ref="PHPCompatibility">
<!-- https://github.com/symfony/polyfill-php55/blob/master/bootstrap.php -->
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.array_columnFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.boolvalFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.hash_pbkdf2Found"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.json_last_error_msgFound"/>
</rule>

</ruleset>
11 changes: 11 additions & 0 deletions PHPCompatibilitySymfonyPolyfillPHP56/ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0"?>
<ruleset name="PHPCompatibilitySymfonyPolyfillPHP56">
<description>PHPCompatibility ruleset for PHP_CodeSniffer which accounts for polyfills provided by the Symfony PHP 5.6 libary.</description>

<rule ref="PHPCompatibility">
<!-- https://github.com/symfony/polyfill-php56/blob/master/bootstrap.php -->
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.hash_equalsFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.ldap_escapeFound"/>
</rule>

</ruleset>
26 changes: 26 additions & 0 deletions PHPCompatibilitySymfonyPolyfillPHP70/ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0"?>
<ruleset name="PHPCompatibilitySymfonyPolyfillPHP70">
<description>PHPCompatibility ruleset for PHP_CodeSniffer which accounts for polyfills provided by the Symfony PHP 7.0 library.</description>

<!-- https://github.com/symfony/polyfill-php70/blob/master/composer.json -->
<rule ref="PHPCompatibilityParagonieRandomCompat"/>

<rule ref="PHPCompatibility">
<!-- https://github.com/symfony/polyfill-php70/blob/master/bootstrap.php -->
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.intdivFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.preg_replace_callback_arrayFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.error_clear_lastFound"/>
<exclude name="PHPCompatibility.Constants.NewConstants.php_int_minFound"/>

<!-- https://github.com/symfony/polyfill-php70/tree/master/Resources/stubs -->
<exclude name="PHPCompatibility.Classes.NewClasses.errorFound"/>
<exclude name="PHPCompatibility.Classes.NewClasses.arithmeticerrorFound"/>
<exclude name="PHPCompatibility.Classes.NewClasses.assertionerrorFound"/>
<exclude name="PHPCompatibility.Classes.NewClasses.divisionbyzeroerrorFound"/>
<exclude name="PHPCompatibility.Classes.NewClasses.parseerrorFound"/>
<exclude name="PHPCompatibility.Classes.NewClasses.typeerrorFound"/>

<exclude name="PHPCompatibility.Interfaces.NewInterfaces.sessionupdatetimestamphandlerinterfaceFound"/>
</rule>

</ruleset>
10 changes: 10 additions & 0 deletions PHPCompatibilitySymfonyPolyfillPHP71/ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<ruleset name="PHPCompatibilitySymfonyPolyfillPHP71">
<description>PHPCompatibility ruleset for PHP_CodeSniffer which accounts for polyfills provided by the Symfony PHP 7.1 library.</description>

<rule ref="PHPCompatibility">
<!-- https://github.com/symfony/polyfill-php71/blob/master/bootstrap.php -->
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.is_iterableFound"/>
</rule>

</ruleset>
18 changes: 18 additions & 0 deletions PHPCompatibilitySymfonyPolyfillPHP72/ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<ruleset name="PHPCompatibilitySymfonyPolyfillPHP72">
<description>PHPCompatibility ruleset for PHP_CodeSniffer which accounts for polyfills provided by the Symfony PHP 7.2 library.</description>

<rule ref="PHPCompatibility">
<!-- https://github.com/symfony/polyfill-php72/blob/master/bootstrap.php -->
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.sapi_windows_vt100_supportFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.stream_isattyFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.utf8_encodeFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.utf8_decodeFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.spl_object_idFound"/>
<exclude name="PHPCompatibility.Constants.NewConstants.php_os_familyFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.mb_ordFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.mb_chrFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.mb_scrubFound"/>
</rule>

</ruleset>
13 changes: 13 additions & 0 deletions PHPCompatibilitySymfonyPolyfillPHP73/ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0"?>
<ruleset name="PHPCompatibilitySymfonyPolyfillPHP73">
<description>PHPCompatibility ruleset for PHP_CodeSniffer which accounts for polyfills provided by the Symfony PHP 7.3 library.</description>

<rule ref="PHPCompatibility">
<!-- https://github.com/symfony/polyfill-php73/blob/master/bootstrap.php -->
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.array_key_firstFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.array_key_lastFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.hrtimeFound"/>
<exclude name="PHPCompatibility.FunctionUse.NewFunctions.is_countableFound"/>
</rule>

</ruleset>
120 changes: 119 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,120 @@
[![Latest Stable Version](https://poser.pugx.org/phpcompatibility/phpcompatibility-symfony/v/stable.png)](https://packagist.org/packages/phpcompatibility/phpcompatibility-symfony)
[![Latest Unstable Version](https://poser.pugx.org/phpcompatibility/phpcompatibility-symfony/v/unstable.png)](https://packagist.org/packages/phpcompatibility/phpcompatibility-symfony)
[![License](https://poser.pugx.org/phpcompatibility/phpcompatibility-symfony/license.png)](https://github.com/PHPCompatibility/PHPCompatibilitySymfony/blob/master/LICENSE)
[![Build Status](https://travis-ci.org/PHPCompatibility/PHPCompatibilitySymfony.svg?branch=master)](https://travis-ci.org/PHPCompatibility/PHPCompatibilitySymfony)

# PHPCompatibilitySymfony
PHPCompatibility rulesets which can be included in projects using the Symfony polyfill libraries

Using PHPCompatibilitySymfony, you can analyse the codebase of a project using any of the [Symfony polyfill libraries](https://github.com/symfony?utf8=?&q=polyfill), for PHP cross-version compatibility.


## What's in this repo ?

A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Symfony polyfill libraries.

These rulesets prevent false positives from the [PHPCompatibility standard](https://github.com/PHPCompatibility/PHPCompatibility) by excluding back-fills and poly-fills which are provided by those libraries.

Symfony Polyfill Library | Corresponding PHPCompatibility Ruleset | Includes
--- | --- | ---
[`polyfill-php54`](https://github.com/symfony/polyfill-php54) | `PHPCompatibilitySymfonyPolyfillPHP54` |
[`polyfill-php55`](https://github.com/symfony/polyfill-php55) | `PHPCompatibilitySymfonyPolyfillPHP55` | [`PHPCompatibilityPasswordCompat`](https://github.com/PHPCompatibility/PHPCompatibilityPasswordCompat)
[`polyfill-php56`](https://github.com/symfony/polyfill-php56) | `PHPCompatibilitySymfonyPolyfillPHP56` |
[`polyfill-php70`](https://github.com/symfony/polyfill-php70) | `PHPCompatibilitySymfonyPolyfillPHP70` | [`PHPCompatibilityParagonieRandomCompat`](https://github.com/PHPCompatibility/PHPCompatibilityParagonie)
[`polyfill-php71`](https://github.com/symfony/polyfill-php71) | `PHPCompatibilitySymfonyPolyfillPHP71` |
[`polyfill-php72`](https://github.com/symfony/polyfill-php72) | `PHPCompatibilitySymfonyPolyfillPHP72` |
[`polyfill-php73`](https://github.com/symfony/polyfill-php73) | `PHPCompatibilitySymfonyPolyfillPHP73` |

> About "Includes":
> Some polyfills have other polyfills as dependencies. If the PHPCompatibility project offers a dedicated ruleset for the polyfill dependency, that ruleset will be included in the ruleset for the higher level polyfill.
>
> For example:
> As the `polyfill-php70` library declares `random_compat` [as a dependency](https://github.com/symfony/polyfill-php70/blob/master/composer.json), the `PHPCompatibilitySymfonyPolyfillPHP70` ruleset includes the `PHPCompatibilityParagonieRandomCompat` ruleset.
>
> In practice, this means that if your project uses several polyfills, you can use the information in "Includes" to help you decide which rulesets to use.

## Requirements

* [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer).
* PHP 5.3+ for use with [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) 2.3.0+.
* PHP 5.4+ for use with [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) 3.0.2+.

Use the latest stable release of PHP_CodeSniffer for the best results.
The minimum _recommended_ version of PHP_CodeSniffer is version 2.6.0.
* [PHPCompatibility](https://github.com/PHPCompatibility/PHPCompatibility) 9.0.0+.
* [PHPCompatibilityParagonie](https://github.com/PHPCompatibility/PHPCompatibilityParagonie) 1.0.0+.
* [PHPCompatibilityPasswordCompat](https://github.com/PHPCompatibility/PHPCompatibilityPasswordCompat) 1.0.0+.


## Installation instructions

The only supported installation method is via [Composer](https://getcomposer.org/).

If you don't have a Composer plugin installed to manage the `installed_paths` setting for PHP_CodeSniffer, run the following from the command-line:
```bash
composer require --dev dealerdirect/phpcodesniffer-composer-installer:^0.4.4 phpcompatibility/phpcompatibility-symfony:*
composer install
```

If you already have a Composer PHP_CodeSniffer plugin installed, run:
```bash
composer require --dev phpcompatibility/phpcompatibility-symfony:*
composer install
```

Next, run:
```bash
vendor/bin/phpcs -i
```
If all went well, you will now see that the PHPCompatibility and a range of PHPCompatibilitySymfony and other PHPCompatibility standards are installed for PHP_CodeSniffer.


## How to use

Now you can use the following commands to inspect the code in your project for PHP cross-version compatibility:
```bash
./vendor/bin/phpcs -p . --standard=PHPCompatibilitySymfonyPolyfillPHP54
./vendor/bin/phpcs -p . --standard=PHPCompatibilitySymfonyPolyfillPHP55
./vendor/bin/phpcs -p . --standard=PHPCompatibilitySymfonyPolyfillPHP56
./vendor/bin/phpcs -p . --standard=PHPCompatibilitySymfonyPolyfillPHP70
./vendor/bin/phpcs -p . --standard=PHPCompatibilitySymfonyPolyfillPHP71
./vendor/bin/phpcs -p . --standard=PHPCompatibilitySymfonyPolyfillPHP72
./vendor/bin/phpcs -p . --standard=PHPCompatibilitySymfonyPolyfillPHP73

# You can also combine the standards if your project uses several:
./vendor/bin/phpcs -p . --standard=PHPCompatibilitySymfonyPolyfillPHP55,PHPCompatibilitySymfonyPolyfillPHP70,PHPCompatibilitySymfonyPolyfillPHP73
```

By default, you will only receive notifications about deprecated and/or removed PHP features.

To get the most out of the PHPCompatibilitySymfony rulesets, you should specify a `testVersion` to check against. That will enable the checks for both deprecated/removed PHP features as well as the detection of code using new PHP features.

For example:
```bash
# For a project which should be compatible with PHP 5.3 up to and including PHP 7.0:
./vendor/bin/phpcs -p . --standard=PHPCompatibilitySymfonyPolyfillPHP56 --runtime-set testVersion 5.3-7.0

# For a project which should be compatible with PHP 5.4 and higher:
./vendor/bin/phpcs -p . --standard=PHPCompatibilitySymfonyPolyfillPHP73 --runtime-set testVersion 5.4-
```

For more detailed information about setting the `testVersion`, see the README of the generic [PHPCompatibility](https://github.com/PHPCompatibility/PHPCompatibility#sniffing-your-code-for-compatibility-with-specific-php-versions) standard.


### Testing PHP files only

By default PHP_CodeSniffer will analyse PHP, JavaScript and CSS files. As the PHPCompatibility sniffs only target PHP code, you can make the run slightly faster by telling PHP_CodeSniffer to only check PHP files, like so:
```bash
./vendor/bin/phpcs -p . --standard=PHPCompatibilitySymfonyPolyfillPHP71 --extensions=php --runtime-set testVersion 5.3-
```

## License

All code within the PHPCompatibility organisation is released under the GNU Lesser General Public License (LGPL). For more information, visit https://www.gnu.org/copyleft/lesser.html


## Changelog

### 1.0.0 - 2018-10-07

Initial release of PHPCompatibilitySymfony containing rulesets covering the `polyfill-php*` libraries.
14 changes: 14 additions & 0 deletions Test/SymfonyPolyfillPHP54Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
/*
* Test file to run PHP_CodeSniffer against to make sure the polyfills are correctly excluded.
*/
if ( trait_exists( 'MyTrait' ) && class_uses( 'MyTrait' ) ) {
echo hex2bin();
}

session_register_shutdown();

class MyCallback extends CallbackFilterIterator {
public function ABC( RecursiveCallbackFilterIterator $a ) {}
}
class MySession implements SessionHandlerInterface {}
8 changes: 8 additions & 0 deletions Test/SymfonyPolyfillPHP55Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php
/*
* Test file to run PHP_CodeSniffer against to make sure the polyfills are correctly excluded.
*/
$a = array_column();
$a = boolval();
$a = hash_pbkdf2();
$a = json_last_error_msg();
6 changes: 6 additions & 0 deletions Test/SymfonyPolyfillPHP56Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
/*
* Test file to run PHP_CodeSniffer against to make sure the polyfills are correctly excluded.
*/
$a = hash_equals();
$a = ldap_escape();
17 changes: 17 additions & 0 deletions Test/SymfonyPolyfillPHP70Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
/*
* Test file to run PHP_CodeSniffer against to make sure the polyfills are correctly excluded.
*/
$a = intdiv( $b, PHP_INT_MIN );

if (error_clear_last()) {
try {
preg_replace_callback_array();
} catch( ArithmeticError $e ) {
} catch( DivisionByZeroError $e ) {
} catch( Error $e ) {
}

class MyException extends AssertionError implements SessionUpdateTimestampHandlerInterface {
public function something( ParseError $e, TypeError $t ) {}
}
5 changes: 5 additions & 0 deletions Test/SymfonyPolyfillPHP71Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php
/*
* Test file to run PHP_CodeSniffer against to make sure the polyfills are correctly excluded.
*/
$a = is_iterable();
10 changes: 10 additions & 0 deletions Test/SymfonyPolyfillPHP72Test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php
/*
* Test file to run PHP_CodeSniffer against to make sure the polyfills are correctly excluded.
*/
$a = PHP_OS_FAMILY ? utf8_encode($b) : utf_decode($b);

$c = stream_isatty();
$d = sapi_windows_vt100_support();

$e = mb_scrub(mb_ord(mb_chr(spl_object_id())));
Loading

0 comments on commit 83d18e6

Please sign in to comment.