aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--phpBB/.htaccess56
-rw-r--r--phpBB/docs/events.md16
-rw-r--r--phpBB/includes/ucp/ucp_register.php23
-rw-r--r--phpBB/memberlist.php2
-rw-r--r--phpBB/phpbb/console/command/db/migrate.php1
-rw-r--r--phpBB/phpbb/controller/provider.php2
-rw-r--r--phpBB/phpbb/session.php5
-rw-r--r--phpBB/phpbb/template/twig/lexer.php15
-rw-r--r--phpBB/phpbb/user.php24
-rw-r--r--phpBB/styles/prosilver/template/ucp_agreement.html1
-rw-r--r--phpBB/styles/prosilver/template/ucp_pm_viewmessage.html3
-rw-r--r--phpBB/styles/prosilver/template/ucp_register.html1
-rw-r--r--phpBB/styles/prosilver/template/viewtopic_body.html2
-rw-r--r--phpBB/styles/subsilver2/template/ucp_agreement.html1
-rw-r--r--phpBB/styles/subsilver2/template/ucp_register.html1
-rw-r--r--phpBB/viewtopic.php6
-rw-r--r--tests/controller/controller_test.php4
-rw-r--r--tests/controller/ext/vendor2/foo/subfolder/config/routing.yml3
-rw-r--r--tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event/test_event_subloop.html4
-rw-r--r--tests/template/template_events_test.php1
-rw-r--r--tests/template/template_test.php1
-rw-r--r--tests/template/templates/loop_nested_include1.html4
22 files changed, 135 insertions, 41 deletions
diff --git a/phpBB/.htaccess b/phpBB/.htaccess
index 6f33916775..1ae74ed825 100644
--- a/phpBB/.htaccess
+++ b/phpBB/.htaccess
@@ -26,12 +26,50 @@ RewriteRule ^(.*)$ app.php [QSA,L]
#Options +FollowSymLinks
</IfModule>
-<Files "config.php">
-Order Allow,Deny
-Deny from All
-</Files>
-
-<Files "common.php">
-Order Allow,Deny
-Deny from All
-</Files>
+# With Apache 2.4 the "Order, Deny" syntax has been deprecated and moved from
+# module mod_authz_host to a new module called mod_access_compat (which may be
+# disabled) and a new "Require" syntax has been introduced to mod_authz_host.
+# We could just conditionally provide both versions, but unfortunately Apache
+# does not explicitly tell us its version if the module mod_version is not
+# available. In this case, we check for the availability of module
+# mod_authz_core (which should be on 2.4 or higher only) as a best guess.
+<IfModule mod_version.c>
+ <IfVersion < 2.4>
+ <Files "config.php">
+ Order Allow,Deny
+ Deny from All
+ </Files>
+ <Files "common.php">
+ Order Allow,Deny
+ Deny from All
+ </Files>
+ </IfVersion>
+ <IfVersion >= 2.4>
+ <Files "config.php">
+ Require all denied
+ </Files>
+ <Files "common.php">
+ Require all denied
+ </Files>
+ </IfVersion>
+</IfModule>
+<IfModule !mod_version.c>
+ <IfModule !mod_authz_core.c>
+ <Files "config.php">
+ Order Allow,Deny
+ Deny from All
+ </Files>
+ <Files "common.php">
+ Order Allow,Deny
+ Deny from All
+ </Files>
+ </IfModule>
+ <IfModule mod_authz_core.c>
+ <Files "config.php">
+ Require all denied
+ </Files>
+ <Files "common.php">
+ Require all denied
+ </Files>
+ </IfModule>
+</IfModule>
diff --git a/phpBB/docs/events.md b/phpBB/docs/events.md
index 67fa96ffbc..1cc1300c05 100644
--- a/phpBB/docs/events.md
+++ b/phpBB/docs/events.md
@@ -667,6 +667,22 @@ viewtopic_print_head_append
* Since: 3.1.0-a1
* Purpose: Add asset calls directly before the `</head>` tag of the Print Topic screen
+viewtopic_body_contact_fields_after
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+* Since: 3.1.0-b3
+* Purpose: Add data after the contact fields on the user profile when viewing
+a post
+
+viewtopic_body_contact_fields_before
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+* Since: 3.1.0-b3
+* Purpose: Add data before the contact fields on the user profile when viewing
+a post
+
viewtopic_body_footer_before
===
* Locations:
diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php
index ff51ca7b3c..8660a06dcf 100644
--- a/phpBB/includes/ucp/ucp_register.php
+++ b/phpBB/includes/ucp/ucp_register.php
@@ -64,10 +64,7 @@ class ucp_register
$agreed = false;
}
- $user->lang_name = $user_lang = $use_lang;
- $user->lang = array();
- $user->data['user_lang'] = $user->lang_name;
- $user->add_lang(array('common', 'ucp'));
+ $user_lang = $use_lang;
}
else
{
@@ -101,7 +98,6 @@ class ucp_register
if (!$agreed || ($coppa === false && $config['coppa_enable']) || ($coppa && !$config['coppa_enable']))
{
- $add_lang = ($change_lang) ? '&amp;change_lang=' . urlencode($change_lang) : '';
$add_coppa = ($coppa !== false) ? '&amp;coppa=' . $coppa : '';
$s_hidden_fields = array_merge($s_hidden_fields, array(
@@ -147,12 +143,15 @@ class ucp_register
'L_COPPA_NO' => sprintf($user->lang['UCP_COPPA_BEFORE'], $coppa_birthday),
'L_COPPA_YES' => sprintf($user->lang['UCP_COPPA_ON_AFTER'], $coppa_birthday),
- 'U_COPPA_NO' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&amp;coppa=0' . $add_lang),
- 'U_COPPA_YES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&amp;coppa=1' . $add_lang),
+ 'U_COPPA_NO' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&amp;coppa=0'),
+ 'U_COPPA_YES' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register&amp;coppa=1'),
'S_SHOW_COPPA' => true,
'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields),
- 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_lang),
+ 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'),
+
+ 'COOKIE_NAME' => $config['cookie_name'],
+ 'COOKIE_PATH' => $config['cookie_path'],
));
}
else
@@ -164,7 +163,10 @@ class ucp_register
'S_SHOW_COPPA' => false,
'S_REGISTRATION' => true,
'S_HIDDEN_FIELDS' => build_hidden_fields($s_hidden_fields),
- 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_lang . $add_coppa),
+ 'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register' . $add_coppa),
+
+ 'COOKIE_NAME' => $config['cookie_name'],
+ 'COOKIE_PATH' => $config['cookie_path'],
)
);
}
@@ -469,6 +471,9 @@ class ucp_register
'S_COPPA' => $coppa,
'S_HIDDEN_FIELDS' => $s_hidden_fields,
'S_UCP_ACTION' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'mode=register'),
+
+ 'COOKIE_NAME' => $config['cookie_name'],
+ 'COOKIE_PATH' => $config['cookie_path'],
));
//
diff --git a/phpBB/memberlist.php b/phpBB/memberlist.php
index 9c6b3d278f..82143d44cb 100644
--- a/phpBB/memberlist.php
+++ b/phpBB/memberlist.php
@@ -1731,7 +1731,7 @@ function show_profile($data, $user_notes_enabled = false, $warn_user_enabled = f
$data['user_type'] != USER_IGNORE &&
// They must not be deactivated by the administrator
- ($data['user_type'] != USER_INACTIVE && $data['user_inactive_reason'] == INACTIVE_MANUAL) &&
+ ($data['user_type'] != USER_INACTIVE || $data['user_inactive_reason'] != INACTIVE_MANUAL) &&
// They must be able to read PMs
sizeof($auth->acl_get_list($user_id, 'u_readpm')) &&
diff --git a/phpBB/phpbb/console/command/db/migrate.php b/phpBB/phpbb/console/command/db/migrate.php
index c7ccd4646e..16a09af6fc 100644
--- a/phpBB/phpbb/console/command/db/migrate.php
+++ b/phpBB/phpbb/console/command/db/migrate.php
@@ -115,6 +115,7 @@ class migrate extends \phpbb\console\command\command
$migrations = $this->extension_manager
->get_finder()
->core_path('phpbb/db/migration/data/')
+ ->extension_directory('/migrations')
->get_classes();
$this->migrator->set_migrations($migrations);
}
diff --git a/phpBB/phpbb/controller/provider.php b/phpBB/phpbb/controller/provider.php
index 9df8130210..2c7493f64c 100644
--- a/phpBB/phpbb/controller/provider.php
+++ b/phpBB/phpbb/controller/provider.php
@@ -46,7 +46,7 @@ class provider
// We hardcode the path to the core config directory
// because the finder cannot find it
$this->routing_files = array_merge($this->routing_files, array('config/routing.yml'), array_keys($finder
- ->directory('config')
+ ->directory('/config')
->suffix('routing.yml')
->find()
));
diff --git a/phpBB/phpbb/session.php b/phpBB/phpbb/session.php
index f530d30f1f..c9e04e1401 100644
--- a/phpBB/phpbb/session.php
+++ b/phpBB/phpbb/session.php
@@ -1045,8 +1045,9 @@ class session
* @param string $name Name of the cookie, will be automatically prefixed with the phpBB cookie name. track becomes [cookie_name]_track then.
* @param string $cookiedata The data to hold within the cookie
* @param int $cookietime The expiration time as UNIX timestamp. If 0 is provided, a session cookie is set.
+ * @param int $httponly Use HttpOnly. Defaults to true. Use false to make cookie accessible by client-side scripts.
*/
- function set_cookie($name, $cookiedata, $cookietime)
+ function set_cookie($name, $cookiedata, $cookietime, $httponly = true)
{
global $config;
@@ -1054,7 +1055,7 @@ class session
$expire = gmdate('D, d-M-Y H:i:s \\G\\M\\T', $cookietime);
$domain = (!$config['cookie_domain'] || $config['cookie_domain'] == 'localhost' || $config['cookie_domain'] == '127.0.0.1') ? '' : '; domain=' . $config['cookie_domain'];
- header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . '; HttpOnly', false);
+ header('Set-Cookie: ' . $name_data . (($cookietime) ? '; expires=' . $expire : '') . '; path=' . $config['cookie_path'] . $domain . ((!$config['cookie_secure']) ? '' : '; secure') . ';' . (($httponly) ? ' HttpOnly' : ''), false);
}
/**
diff --git a/phpBB/phpbb/template/twig/lexer.php b/phpBB/phpbb/template/twig/lexer.php
index f4efc58540..49577f6e95 100644
--- a/phpBB/phpbb/template/twig/lexer.php
+++ b/phpBB/phpbb/template/twig/lexer.php
@@ -191,9 +191,16 @@ class lexer extends \Twig_Lexer
$parent_class = $this;
$callback = function ($matches) use ($parent_class, $parent_nodes)
{
- $name = $matches[1];
- $subset = trim(substr($matches[2], 1, -1)); // Remove parenthesis
- $body = $matches[3];
+ $hard_parents = explode('.', $matches[1]);
+ array_pop($hard_parents); // ends with .
+ if ($hard_parents)
+ {
+ $parent_nodes = array_merge($hard_parents, $parent_nodes);
+ }
+
+ $name = $matches[2];
+ $subset = trim(substr($matches[3], 1, -1)); // Remove parenthesis
+ $body = $matches[4];
// Replace <!-- BEGINELSE -->
$body = str_replace('<!-- BEGINELSE -->', '{% else %}', $body);
@@ -242,7 +249,7 @@ class lexer extends \Twig_Lexer
return "{% for {$name} in {$parent}{$name}{$subset} %}{$body}{% endfor %}";
};
- return preg_replace_callback('#<!-- BEGIN ([!a-zA-Z0-9_]+)(\([0-9,\-]+\))? -->(.+?)<!-- END \1 -->#s', $callback, $code);
+ return preg_replace_callback('#<!-- BEGIN ((?:[a-zA-Z0-9_]+\.)*)([!a-zA-Z0-9_]+)(\([0-9,\-]+\))? -->(.+?)<!-- END \1\2 -->#s', $callback, $code);
}
/**
diff --git a/phpBB/phpbb/user.php b/phpBB/phpbb/user.php
index 18b7a3d096..f8e473dcad 100644
--- a/phpBB/phpbb/user.php
+++ b/phpBB/phpbb/user.php
@@ -69,7 +69,7 @@ class user extends \phpbb\session
*/
function setup($lang_set = false, $style_id = false)
{
- global $db, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache;
+ global $db, $request, $template, $config, $auth, $phpEx, $phpbb_root_path, $cache;
global $phpbb_dispatcher;
if ($this->data['user_id'] != ANONYMOUS)
@@ -80,7 +80,25 @@ class user extends \phpbb\session
}
else
{
- $user_lang_name = basename($config['default_lang']);
+ $lang_override = $request->variable('language', '');
+ if ($lang_override)
+ {
+ $this->set_cookie('lang', $lang_override, 0, false);
+ }
+ else
+ {
+ $lang_override = $request->variable($config['cookie_name'] . '_lang', '', true, \phpbb\request\request_interface::COOKIE);
+ }
+ if ($lang_override)
+ {
+ $use_lang = basename($lang_override);
+ $user_lang_name = (file_exists($this->lang_path . $use_lang . "/common.$phpEx")) ? $use_lang : basename($config['default_lang']);
+ $this->data['user_lang'] = $user_lang_name;
+ }
+ else
+ {
+ $user_lang_name = basename($config['default_lang']);
+ }
$user_date_format = $config['default_dateformat'];
$user_timezone = $config['board_timezone'];
@@ -190,7 +208,7 @@ class user extends \phpbb\session
}
unset($lang_set_ext);
- $style_request = request_var('style', 0);
+ $style_request = $request->variable('style', 0);
if ($style_request && (!$config['override_user_style'] || $auth->acl_get('a_styles')) && !defined('ADMIN_START'))
{
global $SID, $_EXTRA_URL;
diff --git a/phpBB/styles/prosilver/template/ucp_agreement.html b/phpBB/styles/prosilver/template/ucp_agreement.html
index b52acdd955..bc4f23cee7 100644
--- a/phpBB/styles/prosilver/template/ucp_agreement.html
+++ b/phpBB/styles/prosilver/template/ucp_agreement.html
@@ -10,6 +10,7 @@
*/
function change_language(lang_iso)
{
+ document.cookie = '{COOKIE_NAME}_lang=' + lang_iso + '; path={COOKIE_PATH}';
document.forms['register'].change_lang.value = lang_iso;
document.forms['register'].submit();
}
diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html
index 627b5aa6ed..81171e97b2 100644
--- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html
+++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html
@@ -33,7 +33,7 @@
<!-- END custom_fields -->
<!-- EVENT ucp_pm_viewmessage_custom_fields_after -->
-
+ <!-- EVENT ucp_pm_viewmessage_contact_fields_before -->
<!-- IF .contact -->
<dd class="profile-contact">
<strong>{L_CONTACT_USER}{L_COLON}</strong>
@@ -59,6 +59,7 @@
</div>
</dd>
<!-- ENDIF -->
+ <!-- EVENT ucp_pm_viewmessage_contact_fields_after -->
</dl>
<div class="postbody">
diff --git a/phpBB/styles/prosilver/template/ucp_register.html b/phpBB/styles/prosilver/template/ucp_register.html
index fc469eff36..b27003faab 100644
--- a/phpBB/styles/prosilver/template/ucp_register.html
+++ b/phpBB/styles/prosilver/template/ucp_register.html
@@ -7,6 +7,7 @@
*/
function change_language(lang_iso)
{
+ document.cookie = '{COOKIE_NAME}_lang=' + lang_iso + '; path={COOKIE_PATH}';
document.forms['register'].change_lang.value = lang_iso;
document.forms['register'].submit.click();
}
diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html
index 485083a2ba..8912382c48 100644
--- a/phpBB/styles/prosilver/template/viewtopic_body.html
+++ b/phpBB/styles/prosilver/template/viewtopic_body.html
@@ -143,6 +143,7 @@
<!-- END custom_fields -->
<!-- EVENT viewtopic_body_postrow_custom_fields_after -->
+ <!-- EVENT viewtopic_body_contact_fields_before -->
<!-- IF not S_IS_BOT and .postrow.contact -->
<dd class="profile-contact">
<strong>{L_CONTACT_USER}{L_COLON}</strong>
@@ -169,6 +170,7 @@
</div>
</dd>
<!-- ENDIF -->
+ <!-- EVENT viewtopic_body_contact_fields_after -->
</dl>
diff --git a/phpBB/styles/subsilver2/template/ucp_agreement.html b/phpBB/styles/subsilver2/template/ucp_agreement.html
index 054d25282f..3afe6e89a0 100644
--- a/phpBB/styles/subsilver2/template/ucp_agreement.html
+++ b/phpBB/styles/subsilver2/template/ucp_agreement.html
@@ -10,6 +10,7 @@
*/
function change_language(lang_iso)
{
+ document.cookie = '{COOKIE_NAME}_lang=' + lang_iso + '; path={COOKIE_PATH}';
document.forms['register'].change_lang.value = lang_iso;
document.forms['register'].submit();
}
diff --git a/phpBB/styles/subsilver2/template/ucp_register.html b/phpBB/styles/subsilver2/template/ucp_register.html
index 3392c557a2..1d55b952e5 100644
--- a/phpBB/styles/subsilver2/template/ucp_register.html
+++ b/phpBB/styles/subsilver2/template/ucp_register.html
@@ -7,6 +7,7 @@
*/
function change_language(lang_iso)
{
+ document.cookie = '{COOKIE_NAME}_lang=' + lang_iso + '; path={COOKIE_PATH}';
document.forms['register'].change_lang.value = lang_iso;
document.forms['register'].submit.click();
}
diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php
index 0691355563..1f59019245 100644
--- a/phpBB/viewtopic.php
+++ b/phpBB/viewtopic.php
@@ -1609,7 +1609,7 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
$user_cache[$poster_id]['user_type'] != USER_IGNORE &&
// They must not be deactivated by the administrator
- ($user_cache[$poster_id]['user_type'] != USER_INACTIVE && $user_cache[$poster_id]['user_inactive_reason'] == INACTIVE_MANUAL) &&
+ ($user_cache[$poster_id]['user_type'] != USER_INACTIVE || $user_cache[$poster_id]['user_inactive_reason'] != INACTIVE_MANUAL) &&
// They must be able to read PMs
in_array($poster_id, $can_receive_pm_list) &&
@@ -1618,10 +1618,10 @@ for ($i = 0, $end = sizeof($post_list); $i < $end; ++$i)
!in_array($poster_id, $permanently_banned_users) &&
// They must allow users to contact via PM
- (($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $data['user_allow_pm'])
+ (($auth->acl_gets('a_', 'm_') || $auth->acl_getf_global('m_')) || $user_cache[$poster_id]['allow_pm'])
);
- $u_pm = '';
+ $u_pm = '';
if ($config['allow_privmsg'] && $auth->acl_get('u_sendpm') && $can_receive_pm)
{
diff --git a/tests/controller/controller_test.php b/tests/controller/controller_test.php
index 550679ff07..7d9fe652eb 100644
--- a/tests/controller/controller_test.php
+++ b/tests/controller/controller_test.php
@@ -8,8 +8,6 @@
*/
use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\Routing\Route;
-use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
@@ -43,6 +41,8 @@ class phpbb_controller_controller_test extends phpbb_test_case
$this->assertInstanceOf('Symfony\Component\Routing\Route', $routes->get('controller2'));
$this->assertEquals('/foo/bar', $routes->get('controller2')->getPath());
+
+ $this->assertNull($routes->get('controller_noroute'));
}
public function test_controller_resolver()
diff --git a/tests/controller/ext/vendor2/foo/subfolder/config/routing.yml b/tests/controller/ext/vendor2/foo/subfolder/config/routing.yml
new file mode 100644
index 0000000000..b4d8d19107
--- /dev/null
+++ b/tests/controller/ext/vendor2/foo/subfolder/config/routing.yml
@@ -0,0 +1,3 @@
+controller_noroute:
+ pattern: /donotfindthis
+ defaults: { _controller: foo.controller:handle }
diff --git a/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event/test_event_subloop.html b/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event/test_event_subloop.html
index 4fdba859f3..98fa1770ba 100644
--- a/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event/test_event_subloop.html
+++ b/tests/template/datasets/ext_trivial/ext/trivial/styles/all/template/event/test_event_subloop.html
@@ -1,2 +1,2 @@
-[{event_loop.S_ROW_COUNT}<!-- BEGIN subloop -->[subloop:{event_loop.subloop.S_ROW_COUNT}]
-<!-- END subloop -->]
+[{event_loop.S_ROW_COUNT}<!-- BEGIN event_loop.subloop -->[subloop:{event_loop.subloop.S_ROW_COUNT}]
+<!-- END event_loop.subloop -->]
diff --git a/tests/template/template_events_test.php b/tests/template/template_events_test.php
index d09f22944f..866d42d831 100644
--- a/tests/template/template_events_test.php
+++ b/tests/template/template_events_test.php
@@ -102,7 +102,6 @@ Zeta test event in all',
),
array(),
'event_loop[0[subloop:0]]',
- 'Event files are missing opened parent loops: PHPBB3-12382',
),
);
}
diff --git a/tests/template/template_test.php b/tests/template/template_test.php
index 49804c26c5..0d19e7afd1 100644
--- a/tests/template/template_test.php
+++ b/tests/template/template_test.php
@@ -330,7 +330,6 @@ class phpbb_template_template_test extends phpbb_template_template_test_case
array(),
"[bar|[bar|]][bar1|[bar1|[bar1|works]]]",
array(),
- 'Included files are missing opened parent loops: PHPBB3-12382',
),
/* Does not pass with the current implementation.
array(
diff --git a/tests/template/templates/loop_nested_include1.html b/tests/template/templates/loop_nested_include1.html
index 0f1a180b4d..88efffc99c 100644
--- a/tests/template/templates/loop_nested_include1.html
+++ b/tests/template/templates/loop_nested_include1.html
@@ -1,5 +1,5 @@
[{test_loop.foo}|
-<!-- BEGIN inner -->
+<!-- BEGIN test_loop.inner -->
[{test_loop.foo}|
{test_loop.inner.myinner}]
-<!-- END inner -->]
+<!-- END test_loop.inner -->]