diff --git a/build/.htaccess b/build/.htaccess new file mode 100644 index 0000000..e019832 --- /dev/null +++ b/build/.htaccess @@ -0,0 +1 @@ +deny from all diff --git a/build/build b/build/build new file mode 100644 index 0000000..fff4282 --- /dev/null +++ b/build/build @@ -0,0 +1,20 @@ +#!/usr/bin/env php +run(); diff --git a/build/build.bat b/build/build.bat new file mode 100644 index 0000000..a1ae41f --- /dev/null +++ b/build/build.bat @@ -0,0 +1,23 @@ +@echo off + +rem ------------------------------------------------------------- +rem build script for Windows. +rem +rem This is the bootstrap script for running build on Windows. +rem +rem @author Qiang Xue +rem @link http://www.yiiframework.com/ +rem @copyright 2008 Yii Software LLC +rem @license http://www.yiiframework.com/license/ +rem @version $Id$ +rem ------------------------------------------------------------- + +@setlocal + +set BUILD_PATH=%~dp0 + +if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe + +%PHP_COMMAND% "%BUILD_PATH%build" %* + +@endlocal \ No newline at end of file diff --git a/build/build.xml b/build/build.xml new file mode 100644 index 0000000..18a420d --- /dev/null +++ b/build/build.xml @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Building package ${pkgname}... + Copying files to build directory... + + + + + Changing file permissions... + + + + + + + + Generating source release file... + + + + + + + + + + + + + + + + + + + + + + + + Building documentation... + + Building Guide PDF... + + + + + + + Building Blog PDF... + + + + + + + Building API... + + + + + Generating doc release file... + + + + + + + + + + + + + + + + Building online API... + + + + Copying tutorials... + + + + + + + + Copying release text files... + + + + + + +Finished building Web files. +Please update yiisite/common/data/versions.php file with the following code: + + '1.1'=>array( + 'version'=>'${yii.version}', + 'revision'=>'${yii.revision}', + 'date'=>'${yii.date}', + 'latest'=>true, + ), + + + + + + Synchronizing code changes for ${pkgname}... + + Building autoload map... + + + Building yiilite.php... + + + + + Extracting i18n messages... + + + + + + + Cleaning up the build... + + + + + + + Welcome to use Yii build script! + -------------------------------- + You may use the following command format to build a target: + + phing <target name> + + where <target name> can be one of the following: + + - sync : synchronize yiilite.php and YiiBase.php + - message : extract i18n messages of the framework + - src : build source release + - doc : build documentation release (Windows only) + - clean : clean up the build + + + + diff --git a/build/controllers/LocaleController.php b/build/controllers/LocaleController.php new file mode 100644 index 0000000..51de6a0 --- /dev/null +++ b/build/controllers/LocaleController.php @@ -0,0 +1,103 @@ + + * @since 2.0 + */ +class LocaleController extends Controller +{ + public $defaultAction = 'plural'; + + /** + * Generates the plural rules data. + * + * This command will parse the plural rule XML file from CLDR and convert them + * into appropriate PHP representation to support Yii message translation feature. + * @param string $xmlFile the original plural rule XML file (from CLDR). This file may be found in + * http://www.unicode.org/Public/cldr/latest/core.zip + * Extract the zip file and locate the file "common/supplemental/plurals.xml". + * @throws Exception + */ + public function actionPlural($xmlFile) + { + if (!is_file($xmlFile)) { + throw new Exception("The source plural rule file does not exist: $xmlFile"); + } + + $xml = simplexml_load_file($xmlFile); + + $allRules = array(); + + $patterns = array( + '/n in 0..1/' => '(n==0||n==1)', + '/\s+is\s+not\s+/i' => '!=', //is not + '/\s+is\s+/i' => '==', //is + '/n\s+mod\s+(\d+)/i' => 'fmod(n,$1)', //mod (CLDR's "mod" is "fmod()", not "%") + '/^(.*?)\s+not\s+(?:in|within)\s+(\d+)\.\.(\d+)/i' => '($1<$2||$1>$3)', //not in, not within + '/^(.*?)\s+within\s+(\d+)\.\.(\d+)/i' => '($1>=$2&&$1<=$3)', //within + '/^(.*?)\s+in\s+(\d+)\.\.(\d+)/i' => '($1>=$2&&$1<=$3&&fmod($1,1)==0)', //in + ); + foreach ($xml->plurals->pluralRules as $node) { + $attributes = $node->attributes(); + $locales = explode(' ', $attributes['locales']); + $rules = array(); + + if (!empty($node->pluralRule)) { + foreach ($node->pluralRule as $rule) { + $expr_or = preg_split('/\s+or\s+/i', $rule); + foreach ($expr_or as $key_or => $val_or) { + $expr_and = preg_split('/\s+and\s+/i', $val_or); + $expr_and = preg_replace(array_keys($patterns), array_values($patterns), $expr_and); + $expr_or[$key_or] = implode('&&', $expr_and); + } + $rules[] = preg_replace('/\\bn\\b/', '$n', implode('||', $expr_or)); + } + foreach ($locales as $locale) { + $allRules[$locale] = $rules; + } + } + } + // hard fix for "br": the rule is too complex + $allRules['br'] = array( + 0 => 'fmod($n,10)==1&&!in_array(fmod($n,100),array(11,71,91))', + 1 => 'fmod($n,10)==2&&!in_array(fmod($n,100),array(12,72,92))', + 2 => 'in_array(fmod($n,10),array(3,4,9))&&!in_array(fmod($n,100),array_merge(range(10,19),range(70,79),range(90,99))))', + 3 => 'fmod($n,1000000)==0&&$n!=0', + ); + if (preg_match('/\d+/', $xml->version['number'], $matches)) { + $revision = $matches[0]; + } else { + $revision = -1; + } + + echo " - * * @since 2.0 */ class Controller extends \yii\base\Controller diff --git a/framework/console/controllers/HelpController.php b/framework/console/controllers/HelpController.php index ea7e3d5..74c354b 100644 --- a/framework/console/controllers/HelpController.php +++ b/framework/console/controllers/HelpController.php @@ -9,9 +9,9 @@ namespace yii\console\controllers; use Yii; use yii\base\Application; -use yii\console\Exception; use yii\base\InlineAction; use yii\console\Controller; +use yii\console\Exception; use yii\console\Request; use yii\helpers\StringHelper; @@ -128,7 +128,7 @@ class HelpController extends Controller $files = scandir($module->getControllerPath()); foreach ($files as $file) { - if(strcmp(substr($file,-14),'Controller.php') === 0 && is_file($file)) { + if (strcmp(substr($file, -14), 'Controller.php') === 0) { $commands[] = $prefix . lcfirst(substr(basename($file), 0, -14)); } } diff --git a/framework/i18n/data/plurals.php b/framework/i18n/data/plurals.php new file mode 100644 index 0000000..3ed5619 --- /dev/null +++ b/framework/i18n/data/plurals.php @@ -0,0 +1,627 @@ + + array ( + 0 => '$n==0', + 1 => '$n==1', + 2 => '$n==2', + 3 => '(fmod($n,100)>=3&&fmod($n,100)<=10&&fmod(fmod($n,100),1)==0)', + 4 => '(fmod($n,100)>=11&&fmod($n,100)<=99&&fmod(fmod($n,100),1)==0)', + ), + 'asa' => + array ( + 0 => '$n==1', + ), + 'af' => + array ( + 0 => '$n==1', + ), + 'bem' => + array ( + 0 => '$n==1', + ), + 'bez' => + array ( + 0 => '$n==1', + ), + 'bg' => + array ( + 0 => '$n==1', + ), + 'bn' => + array ( + 0 => '$n==1', + ), + 'brx' => + array ( + 0 => '$n==1', + ), + 'ca' => + array ( + 0 => '$n==1', + ), + 'cgg' => + array ( + 0 => '$n==1', + ), + 'chr' => + array ( + 0 => '$n==1', + ), + 'da' => + array ( + 0 => '$n==1', + ), + 'de' => + array ( + 0 => '$n==1', + ), + 'dv' => + array ( + 0 => '$n==1', + ), + 'ee' => + array ( + 0 => '$n==1', + ), + 'el' => + array ( + 0 => '$n==1', + ), + 'en' => + array ( + 0 => '$n==1', + ), + 'eo' => + array ( + 0 => '$n==1', + ), + 'es' => + array ( + 0 => '$n==1', + ), + 'et' => + array ( + 0 => '$n==1', + ), + 'eu' => + array ( + 0 => '$n==1', + ), + 'fi' => + array ( + 0 => '$n==1', + ), + 'fo' => + array ( + 0 => '$n==1', + ), + 'fur' => + array ( + 0 => '$n==1', + ), + 'fy' => + array ( + 0 => '$n==1', + ), + 'gl' => + array ( + 0 => '$n==1', + ), + 'gsw' => + array ( + 0 => '$n==1', + ), + 'gu' => + array ( + 0 => '$n==1', + ), + 'ha' => + array ( + 0 => '$n==1', + ), + 'haw' => + array ( + 0 => '$n==1', + ), + 'he' => + array ( + 0 => '$n==1', + ), + 'is' => + array ( + 0 => '$n==1', + ), + 'it' => + array ( + 0 => '$n==1', + ), + 'jmc' => + array ( + 0 => '$n==1', + ), + 'kaj' => + array ( + 0 => '$n==1', + ), + 'kcg' => + array ( + 0 => '$n==1', + ), + 'kk' => + array ( + 0 => '$n==1', + ), + 'kl' => + array ( + 0 => '$n==1', + ), + 'ksb' => + array ( + 0 => '$n==1', + ), + 'ku' => + array ( + 0 => '$n==1', + ), + 'lb' => + array ( + 0 => '$n==1', + ), + 'lg' => + array ( + 0 => '$n==1', + ), + 'mas' => + array ( + 0 => '$n==1', + ), + 'ml' => + array ( + 0 => '$n==1', + ), + 'mn' => + array ( + 0 => '$n==1', + ), + 'mr' => + array ( + 0 => '$n==1', + ), + 'nah' => + array ( + 0 => '$n==1', + ), + 'nb' => + array ( + 0 => '$n==1', + ), + 'nd' => + array ( + 0 => '$n==1', + ), + 'ne' => + array ( + 0 => '$n==1', + ), + 'nl' => + array ( + 0 => '$n==1', + ), + 'nn' => + array ( + 0 => '$n==1', + ), + 'no' => + array ( + 0 => '$n==1', + ), + 'nr' => + array ( + 0 => '$n==1', + ), + 'ny' => + array ( + 0 => '$n==1', + ), + 'nyn' => + array ( + 0 => '$n==1', + ), + 'om' => + array ( + 0 => '$n==1', + ), + 'or' => + array ( + 0 => '$n==1', + ), + 'pa' => + array ( + 0 => '$n==1', + ), + 'pap' => + array ( + 0 => '$n==1', + ), + 'ps' => + array ( + 0 => '$n==1', + ), + 'pt' => + array ( + 0 => '$n==1', + ), + 'rof' => + array ( + 0 => '$n==1', + ), + 'rm' => + array ( + 0 => '$n==1', + ), + 'rwk' => + array ( + 0 => '$n==1', + ), + 'saq' => + array ( + 0 => '$n==1', + ), + 'seh' => + array ( + 0 => '$n==1', + ), + 'sn' => + array ( + 0 => '$n==1', + ), + 'so' => + array ( + 0 => '$n==1', + ), + 'sq' => + array ( + 0 => '$n==1', + ), + 'ss' => + array ( + 0 => '$n==1', + ), + 'ssy' => + array ( + 0 => '$n==1', + ), + 'st' => + array ( + 0 => '$n==1', + ), + 'sv' => + array ( + 0 => '$n==1', + ), + 'sw' => + array ( + 0 => '$n==1', + ), + 'syr' => + array ( + 0 => '$n==1', + ), + 'ta' => + array ( + 0 => '$n==1', + ), + 'te' => + array ( + 0 => '$n==1', + ), + 'teo' => + array ( + 0 => '$n==1', + ), + 'tig' => + array ( + 0 => '$n==1', + ), + 'tk' => + array ( + 0 => '$n==1', + ), + 'tn' => + array ( + 0 => '$n==1', + ), + 'ts' => + array ( + 0 => '$n==1', + ), + 'ur' => + array ( + 0 => '$n==1', + ), + 'wae' => + array ( + 0 => '$n==1', + ), + 've' => + array ( + 0 => '$n==1', + ), + 'vun' => + array ( + 0 => '$n==1', + ), + 'xh' => + array ( + 0 => '$n==1', + ), + 'xog' => + array ( + 0 => '$n==1', + ), + 'zu' => + array ( + 0 => '$n==1', + ), + 'ak' => + array ( + 0 => '($n==0||$n==1)', + ), + 'am' => + array ( + 0 => '($n==0||$n==1)', + ), + 'bh' => + array ( + 0 => '($n==0||$n==1)', + ), + 'fil' => + array ( + 0 => '($n==0||$n==1)', + ), + 'tl' => + array ( + 0 => '($n==0||$n==1)', + ), + 'guw' => + array ( + 0 => '($n==0||$n==1)', + ), + 'hi' => + array ( + 0 => '($n==0||$n==1)', + ), + 'ln' => + array ( + 0 => '($n==0||$n==1)', + ), + 'mg' => + array ( + 0 => '($n==0||$n==1)', + ), + 'nso' => + array ( + 0 => '($n==0||$n==1)', + ), + 'ti' => + array ( + 0 => '($n==0||$n==1)', + ), + 'wa' => + array ( + 0 => '($n==0||$n==1)', + ), + 'ff' => + array ( + 0 => '($n>=0&&$n<=2)&&$n!=2', + ), + 'fr' => + array ( + 0 => '($n>=0&&$n<=2)&&$n!=2', + ), + 'kab' => + array ( + 0 => '($n>=0&&$n<=2)&&$n!=2', + ), + 'lv' => + array ( + 0 => '$n==0', + 1 => 'fmod($n,10)==1&&fmod($n,100)!=11', + ), + 'iu' => + array ( + 0 => '$n==1', + 1 => '$n==2', + ), + 'kw' => + array ( + 0 => '$n==1', + 1 => '$n==2', + ), + 'naq' => + array ( + 0 => '$n==1', + 1 => '$n==2', + ), + 'se' => + array ( + 0 => '$n==1', + 1 => '$n==2', + ), + 'sma' => + array ( + 0 => '$n==1', + 1 => '$n==2', + ), + 'smi' => + array ( + 0 => '$n==1', + 1 => '$n==2', + ), + 'smj' => + array ( + 0 => '$n==1', + 1 => '$n==2', + ), + 'smn' => + array ( + 0 => '$n==1', + 1 => '$n==2', + ), + 'sms' => + array ( + 0 => '$n==1', + 1 => '$n==2', + ), + 'ga' => + array ( + 0 => '$n==1', + 1 => '$n==2', + 2 => '($n>=3&&$n<=6&&fmod($n,1)==0)', + 3 => '($n>=7&&$n<=10&&fmod($n,1)==0)', + ), + 'ro' => + array ( + 0 => '$n==1', + 1 => '$n==0||$n!=1&&(fmod($n,100)>=1&&fmod($n,100)<=19&&fmod(fmod($n,100),1)==0)', + ), + 'mo' => + array ( + 0 => '$n==1', + 1 => '$n==0||$n!=1&&(fmod($n,100)>=1&&fmod($n,100)<=19&&fmod(fmod($n,100),1)==0)', + ), + 'lt' => + array ( + 0 => 'fmod($n,10)==1&&(fmod($n,100)<11||fmod($n,100)>19)', + 1 => '(fmod($n,10)>=2&&fmod($n,10)<=9&&fmod(fmod($n,10),1)==0)&&(fmod($n,100)<11||fmod($n,100)>19)', + ), + 'be' => + array ( + 0 => 'fmod($n,10)==1&&fmod($n,100)!=11', + 1 => '(fmod($n,10)>=2&&fmod($n,10)<=4&&fmod(fmod($n,10),1)==0)&&(fmod($n,100)<12||fmod($n,100)>14)', + 2 => 'fmod($n,10)==0||(fmod($n,10)>=5&&fmod($n,10)<=9&&fmod(fmod($n,10),1)==0)||(fmod($n,100)>=11&&fmod($n,100)<=14&&fmod(fmod($n,100),1)==0)', + ), + 'bs' => + array ( + 0 => 'fmod($n,10)==1&&fmod($n,100)!=11', + 1 => '(fmod($n,10)>=2&&fmod($n,10)<=4&&fmod(fmod($n,10),1)==0)&&(fmod($n,100)<12||fmod($n,100)>14)', + 2 => 'fmod($n,10)==0||(fmod($n,10)>=5&&fmod($n,10)<=9&&fmod(fmod($n,10),1)==0)||(fmod($n,100)>=11&&fmod($n,100)<=14&&fmod(fmod($n,100),1)==0)', + ), + 'hr' => + array ( + 0 => 'fmod($n,10)==1&&fmod($n,100)!=11', + 1 => '(fmod($n,10)>=2&&fmod($n,10)<=4&&fmod(fmod($n,10),1)==0)&&(fmod($n,100)<12||fmod($n,100)>14)', + 2 => 'fmod($n,10)==0||(fmod($n,10)>=5&&fmod($n,10)<=9&&fmod(fmod($n,10),1)==0)||(fmod($n,100)>=11&&fmod($n,100)<=14&&fmod(fmod($n,100),1)==0)', + ), + 'ru' => + array ( + 0 => 'fmod($n,10)==1&&fmod($n,100)!=11', + 1 => '(fmod($n,10)>=2&&fmod($n,10)<=4&&fmod(fmod($n,10),1)==0)&&(fmod($n,100)<12||fmod($n,100)>14)', + 2 => 'fmod($n,10)==0||(fmod($n,10)>=5&&fmod($n,10)<=9&&fmod(fmod($n,10),1)==0)||(fmod($n,100)>=11&&fmod($n,100)<=14&&fmod(fmod($n,100),1)==0)', + ), + 'sh' => + array ( + 0 => 'fmod($n,10)==1&&fmod($n,100)!=11', + 1 => '(fmod($n,10)>=2&&fmod($n,10)<=4&&fmod(fmod($n,10),1)==0)&&(fmod($n,100)<12||fmod($n,100)>14)', + 2 => 'fmod($n,10)==0||(fmod($n,10)>=5&&fmod($n,10)<=9&&fmod(fmod($n,10),1)==0)||(fmod($n,100)>=11&&fmod($n,100)<=14&&fmod(fmod($n,100),1)==0)', + ), + 'sr' => + array ( + 0 => 'fmod($n,10)==1&&fmod($n,100)!=11', + 1 => '(fmod($n,10)>=2&&fmod($n,10)<=4&&fmod(fmod($n,10),1)==0)&&(fmod($n,100)<12||fmod($n,100)>14)', + 2 => 'fmod($n,10)==0||(fmod($n,10)>=5&&fmod($n,10)<=9&&fmod(fmod($n,10),1)==0)||(fmod($n,100)>=11&&fmod($n,100)<=14&&fmod(fmod($n,100),1)==0)', + ), + 'uk' => + array ( + 0 => 'fmod($n,10)==1&&fmod($n,100)!=11', + 1 => '(fmod($n,10)>=2&&fmod($n,10)<=4&&fmod(fmod($n,10),1)==0)&&(fmod($n,100)<12||fmod($n,100)>14)', + 2 => 'fmod($n,10)==0||(fmod($n,10)>=5&&fmod($n,10)<=9&&fmod(fmod($n,10),1)==0)||(fmod($n,100)>=11&&fmod($n,100)<=14&&fmod(fmod($n,100),1)==0)', + ), + 'cs' => + array ( + 0 => '$n==1', + 1 => '($n>=2&&$n<=4&&fmod($n,1)==0)', + ), + 'sk' => + array ( + 0 => '$n==1', + 1 => '($n>=2&&$n<=4&&fmod($n,1)==0)', + ), + 'pl' => + array ( + 0 => '$n==1', + 1 => '(fmod($n,10)>=2&&fmod($n,10)<=4&&fmod(fmod($n,10),1)==0)&&(fmod($n,100)<12||fmod($n,100)>14)', + 2 => '$n!=1&&(fmod($n,10)>=0&&fmod($n,10)<=1&&fmod(fmod($n,10),1)==0)||(fmod($n,10)>=5&&fmod($n,10)<=9&&fmod(fmod($n,10),1)==0)||(fmod($n,100)>=12&&fmod($n,100)<=14&&fmod(fmod($n,100),1)==0)', + ), + 'sl' => + array ( + 0 => 'fmod($n,100)==1', + 1 => 'fmod($n,100)==2', + 2 => '(fmod($n,100)>=3&&fmod($n,100)<=4&&fmod(fmod($n,100),1)==0)', + ), + 'mt' => + array ( + 0 => '$n==1', + 1 => '$n==0||(fmod($n,100)>=2&&fmod($n,100)<=10&&fmod(fmod($n,100),1)==0)', + 2 => '(fmod($n,100)>=11&&fmod($n,100)<=19&&fmod(fmod($n,100),1)==0)', + ), + 'mk' => + array ( + 0 => 'fmod($n,10)==1&&$n!=11', + ), + 'cy' => + array ( + 0 => '$n==0', + 1 => '$n==1', + 2 => '$n==2', + 3 => '$n==3', + 4 => '$n==6', + ), + 'lag' => + array ( + 0 => '$n==0', + 1 => '($n>=0&&$n<=2)&&$n!=0&&$n!=2', + ), + 'shi' => + array ( + 0 => '($n>=0&&$n<=1)', + 1 => '($n>=2&&$n<=10&&fmod($n,1)==0)', + ), + 'br' => + array ( + 0 => 'fmod($n,10)==1&&!in_array(fmod($n,100),array(11,71,91))', + 1 => 'fmod($n,10)==2&&!in_array(fmod($n,100),array(12,72,92))', + 2 => 'in_array(fmod($n,10),array(3,4,9))&&!in_array(fmod($n,100),array_merge(range(10,19),range(70,79),range(90,99))))', + 3 => 'fmod($n,1000000)==0&&$n!=0', + ), + 'ksh' => + array ( + 0 => '$n==0', + 1 => '$n==1', + ), + 'tzm' => + array ( + 0 => '($n==0||$n==1)||($n>=11&&$n<=99&&fmod($n,1)==0)', + ), + 'gv' => + array ( + 0 => '(fmod($n,10)>=1&&fmod($n,10)<=2&&fmod(fmod($n,10),1)==0)||fmod($n,20)==0', + ), +); \ No newline at end of file diff --git a/framework/i18n/data/plurals.xml b/framework/i18n/data/plurals.xml new file mode 100644 index 0000000..9227dc6 --- /dev/null +++ b/framework/i18n/data/plurals.xml @@ -0,0 +1,109 @@ + + + + + + + + + + n is 0 + n is 1 + n is 2 + n mod 100 in 3..10 + n mod 100 in 11..99 + + + n is 1 + + + n in 0..1 + + + n within 0..2 and n is not 2 + + + n is 0 + n mod 10 is 1 and n mod 100 is not 11 + + + n is 1 + n is 2 + + + n is 1 + n is 2 + n in 3..6 + n in 7..10 + + + n is 1 + n is 0 OR n is not 1 AND n mod 100 in 1..19 + + + n mod 10 is 1 and n mod 100 not in 11..19 + n mod 10 in 2..9 and n mod 100 not in 11..19 + + + n mod 10 is 1 and n mod 100 is not 11 + n mod 10 in 2..4 and n mod 100 not in 12..14 + n mod 10 is 0 or n mod 10 in 5..9 or n mod 100 in 11..14 + + + + n is 1 + n in 2..4 + + + n is 1 + n mod 10 in 2..4 and n mod 100 not in 12..14 + n is not 1 and n mod 10 in 0..1 or n mod 10 in 5..9 or n mod 100 in 12..14 + + + + + n mod 100 is 1 + n mod 100 is 2 + n mod 100 in 3..4 + + + n is 1 + n is 0 or n mod 100 in 2..10 + n mod 100 in 11..19 + + + n mod 10 is 1 and n is not 11 + + + n is 0 + n is 1 + n is 2 + n is 3 + n is 6 + + + n is 0 + n within 0..2 and n is not 0 and n is not 2 + + + n within 0..1 + n in 2..10 + + + n mod 10 is 1 and n mod 100 not in 11,71,91 + n mod 10 is 2 and n mod 100 not in 12,72,92 + n mod 10 in 3..4,9 and n mod 100 not in 10..19,70..79,90..99 + n mod 1000000 is 0 and n is not 0 + + + n is 0 + n is 1 + + + n in 0..1 or n in 11..99 + + + n mod 10 in 1..2 or n mod 20 is 0 + + +