Commit 94e0188a authored by webchick's avatar webchick

Issue #2294129 by xjm, tim.plunkett: Switch hook_help() to use RouteMatch instead of Request.

parent a36a116d
......@@ -5,12 +5,12 @@
* This is the Actions module for executing stored actions.
*/
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function action_help($route_name, Request $request) {
function action_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.action':
$output = '';
......
......@@ -8,7 +8,7 @@
use Drupal\aggregator\Entity\Feed;
use Drupal\aggregator\FeedInterface;
use Drupal\Component\Utility\Xss;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Denotes that a feed's items should never expire.
......@@ -18,7 +18,7 @@
/**
* Implements hook_help().
*/
function aggregator_help($route_name, Request $request) {
function aggregator_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.aggregator':
$output = '';
......
......@@ -5,12 +5,12 @@
* Allows to ban individual IP addresses.
*/
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function ban_help($route_name, Request $request) {
function ban_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.ban':
$output = '';
......
......@@ -5,12 +5,12 @@
* Provides an HTTP Basic authentication provider.
*/
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function basic_auth_help($route_name, Request $request) {
function basic_auth_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.basic_auth':
$output = '';
......
......@@ -6,14 +6,14 @@
*/
use Drupal\block\BlockInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\language\Entity\Language;
use Drupal\system\Entity\Menu;
use Symfony\Component\HttpFoundation\Request;
/**
* Implements hook_help().
*/
function block_help($route_name, Request $request) {
function block_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.block':
$output = '';
......@@ -37,7 +37,7 @@ function block_help($route_name, Request $request) {
return $output;
}
if ($route_name == 'block.admin_display' || $route_name == 'block.admin_display_theme') {
$demo_theme = $request->attributes->get('theme', \Drupal::config('system.theme')->get('default'));
$demo_theme = $route_match->getParameter('theme') ?: \Drupal::config('system.theme')->get('default');
$themes = list_themes();
$output = '<p>' . t('This page provides a drag-and-drop interface for adding a block to a region, and for controlling the order of blocks within regions. To add a block to a region, or to configure its specific title and visibility settings, click the block title under <em>Place blocks</em>. Since not all themes implement the same regions, or display regions in the same way, blocks are positioned on a per-theme basis. Remember that your changes will not be saved until you click the <em>Save blocks</em> button at the bottom of the page.') . '</p>';
$output .= '<p>' . l(t('Demonstrate block regions (!theme)', array('!theme' => $themes[$demo_theme]->info['name'])), 'admin/structure/block/demo/' . $demo_theme) . '</p>';
......
......@@ -5,14 +5,14 @@
* Allows the creation of custom blocks through the user interface.
*/
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldInstanceConfig;
/**
* Implements hook_help().
*/
function block_content_help($route_name, Request $request) {
function block_content_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.block_content':
$output = '';
......
......@@ -9,17 +9,17 @@
use Drupal\Component\Utility\String;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\node\NodeInterface;
use Drupal\node\NodeTypeInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Template\Attribute;
use Symfony\Component\HttpFoundation\Request;
/**
* Implements hook_help().
*/
function book_help($route_name, Request $request) {
function book_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.book':
$output = '<h3>' . t('About') . '</h3>';
......
......@@ -8,12 +8,12 @@
use Drupal\breakpoint\Entity\Breakpoint;
use Drupal\breakpoint\Entity\BreakpointGroup;
use Drupal\Core\Config\Entity\ConfigEntityStorage;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function breakpoint_help($route_name, Request $request) {
function breakpoint_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.breakpoint':
$output = '';
......
......@@ -5,13 +5,13 @@
* Provides integration with the CKEditor WYSIWYG editor.
*/
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\editor\Entity\Editor;
use Symfony\Component\HttpFoundation\Request;
/**
* Implements hook_help().
*/
function ckeditor_help($route_name, Request $request) {
function ckeditor_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.ckeditor':
$output = '';
......
......@@ -8,12 +8,12 @@
use Drupal\Component\Utility\Bytes;
use Drupal\Component\Utility\Environment;
use Drupal\Component\Utility\String;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function color_help($route_name, Request $request) {
function color_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.color':
$output = '<h3>' . t('About') . '</h3>';
......
......@@ -17,6 +17,7 @@
use Drupal\Component\Utility\String;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\entity\Entity\EntityViewDisplay;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
......@@ -28,7 +29,6 @@
use Drupal\file\FileInterface;
use Drupal\user\EntityOwnerInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Comments are displayed in a flat list - expanded.
......@@ -79,7 +79,7 @@
/**
* Implements hook_help().
*/
function comment_help($route_name, Request $request) {
function comment_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.comment':
$output = '<h3>' . t('About') . '</h3>';
......
......@@ -5,12 +5,12 @@
* Allows site administrators to modify configuration.
*/
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function config_help($route_name, Request $request) {
function config_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.config':
$output = '';
......
......@@ -7,13 +7,13 @@
use Drupal\config_translation\Plugin\Derivative\ConfigTranslationLocalTasks;
use Drupal\Core\Entity\EntityInterface;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
/**
* Implements hook_help().
*/
function config_translation_help($route_name, Request $request) {
function config_translation_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.config_translation':
$output = '';
......
<?php
use Symfony\Component\HttpFoundation\Request;
/**
* @file
* Enables the use of personal and site-wide contact forms.
*/
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function contact_help($route_name, Request $request) {
function contact_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.contact':
$output = '';
......
......@@ -10,15 +10,15 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\field\Entity\FieldInstanceConfig;
use Drupal\field\FieldInstanceConfigInterface;
use Drupal\node\NodeInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Implements hook_help().
*/
function content_translation_help($route_name, Request $request) {
function content_translation_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.content_translation':
$output = '';
......
......@@ -7,8 +7,8 @@
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Template\Attribute;
use Symfony\Component\HttpFoundation\Request;
/**
* Implements hook_toolbar().
......@@ -64,7 +64,7 @@ function contextual_page_build(&$page) {
/**
* Implements hook_help().
*/
function contextual_help($route_name, Request $request) {
function contextual_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.contextual':
$output = '';
......
......@@ -7,6 +7,7 @@
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Template\Attribute;
use Drupal\datetime\DateHelper;
use Drupal\node\NodeInterface;
......@@ -29,8 +30,8 @@
/**
* Implements hook_help().
*/
function datetime_help($path, $arg) {
switch ($path) {
function datetime_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.datetime':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
......
......@@ -11,12 +11,12 @@
* @see watchdog()
*/
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function dblog_help($route_name, Request $request) {
function dblog_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.dblog':
$output = '';
......
......@@ -8,17 +8,17 @@
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\editor\Entity\Editor;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Entity\EntityInterface;
use Drupal\filter\FilterFormatInterface;
use Drupal\filter\Plugin\FilterInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Implements hook_help().
*/
function editor_help($route_name, Request $request) {
function editor_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.editor':
$output = '';
......
......@@ -9,12 +9,12 @@
*/
use Drupal\Core\Config\Entity\ConfigEntityStorage;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function entity_help($route_name, Request $request) {
function entity_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.entity':
$output = '';
......
......@@ -10,15 +10,15 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldInstanceConfig;
use Drupal\field\FieldConfigInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Implements hook_help().
*/
function entity_reference_help($route_name, Request $request) {
function entity_reference_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.entity_reference':
$output = '';
......
......@@ -9,7 +9,7 @@
use Drupal\Core\Config\ConfigImporter;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Extension\Extension;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/*
* Load all public Field API functions. Drupal currently has no
......@@ -59,7 +59,7 @@
/**
* Implements hook_help().
*/
function field_help($route_name, Request $request) {
function field_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.field':
$output = '';
......
......@@ -7,15 +7,15 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\entity\EntityViewModeInterface;
use Drupal\field_ui\FieldUI;
use Drupal\field_ui\Plugin\Derivative\FieldUiLocalTask;
use Symfony\Component\HttpFoundation\Request;
/**
* Implements hook_help().
*/
function field_ui_help($route_name, Request $request) {
function field_ui_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.field_ui':
$output = '';
......
......@@ -8,13 +8,13 @@
use Drupal\Component\Utility\String;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\file\Entity\File;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\Unicode;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Template\Attribute;
use Drupal\file\FileUsage\FileUsageInterface;
use Symfony\Component\HttpFoundation\Request;
// Load all Field module hooks for File.
require_once __DIR__ . '/file.field.inc';
......@@ -22,7 +22,7 @@
/**
* Implements hook_help().
*/
function file_help($route_name, Request $request) {
function file_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.file':
$output = '';
......
......@@ -12,16 +12,16 @@
use Drupal\Component\Utility\Xss;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Template\Attribute;
use Drupal\filter\FilterFormatInterface;
use Drupal\filter\Plugin\FilterInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Implements hook_help().
*/
function filter_help($route_name, Request $request) {
function filter_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.filter':
$output = '';
......
......@@ -10,12 +10,12 @@
use Drupal\Component\Utility\Xss;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Component\Utility\String;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function forum_help($route_name, Request $request) {
function forum_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.forum':
$output = '';
......
......@@ -5,12 +5,12 @@
* Adds support for serializing entities to Hypertext Application Language.
*/
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function hal_help($route_name, Request $request) {
function hal_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.hal':
$output = '';
......
......@@ -5,12 +5,12 @@
* Manages displaying online help.
*/
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function help_help($route_name, Request $request) {
function help_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.main':
$output = '<h2>' . t('Getting Started') . '</h2>';
......
......@@ -8,7 +8,8 @@
namespace Drupal\help\Controller;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Drupal\Component\Utility\String;
......@@ -18,20 +19,43 @@
class HelpController extends ControllerBase {
/**
* Prints a page listing a glossary of Drupal terminology.
* The current route match.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;
/**
* Creates a new HelpController.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request.
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The current route match.
*/
public function __construct(RouteMatchInterface $route_match) {
$this->routeMatch = $route_match;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container) {
return new static(
$container->get('current_route_match')
);
}
/**
* Prints a page listing a glossary of Drupal terminology.
*
* @return string
* An HTML string representing the contents of help page.
*/
public function helpMain(Request $request) {
public function helpMain() {
$output = array(
'#attached' => array(
'css' => array(drupal_get_path('module', 'help') . '/css/help.module.css'),
),
'#markup' => '<h2>' . $this->t('Help topics') . '</h2><p>' . $this->t('Help is available on the following items:') . '</p>' . $this->helpLinksAsList($request),
'#markup' => '<h2>' . $this->t('Help topics') . '</h2><p>' . $this->t('Help is available on the following items:') . '</p>' . $this->helpLinksAsList(),
);
return $output;
}
......@@ -39,18 +63,15 @@ public function helpMain(Request $request) {
/**
* Provides a formatted list of available help topics.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request.
*
* @return string
* A string containing the formatted list.
*/
protected function helpLinksAsList(Request $request) {
protected function helpLinksAsList() {
$module_info = system_rebuild_module_data();
$modules = array();
foreach ($this->moduleHandler()->getImplementations('help') as $module) {
if ($this->moduleHandler()->invoke($module, 'help', array("help.page.$module", $request))) {
if ($this->moduleHandler()->invoke($module, 'help', array("help.page.$module", $this->routeMatch))) {
$modules[$module] = $module_info[$module]->info['name'];
}
}
......@@ -78,21 +99,19 @@ protected function helpLinksAsList(Request $request) {
*
* @param string $name
* A module name to display a help page for.
* @param \Symfony\Component\HttpFoundation\Request $request
* The current request.
*
* @return array
* A render array as expected by drupal_render().
*
* @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
public function helpPage($name, Request $request) {
public function helpPage($name) {
$build = array();
if ($this->moduleHandler()->implementsHook($name, 'help')) {
$info = system_get_info('module');
$build['#title'] = String::checkPlain($info[$name]['name']);
$temp = $this->moduleHandler()->invoke($name, 'help', array("help.page.$name", $request));
$temp = $this->moduleHandler()->invoke($name, 'help', array("help.page.$name", $this->routeMatch));
if (empty($temp)) {
$build['top']['#markup'] = $this->t('No help is available for module %module.', array('%module' => $info[$name]['name']));
}
......
......@@ -11,7 +11,7 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Entities changed before this time are always shown as read.
......@@ -24,7 +24,7 @@
/**
* Implements hook_help().
*/
function history_help($route_name, Request $request) {
function history_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.history':
$output = '<h3>' . t('About') . '</h3>';
......
......@@ -7,10 +7,10 @@
use Drupal\Core\Entity\EntityInterface;
use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\file\Entity\File;
use Drupal\field\FieldConfigInterface;
use Drupal\field\FieldInstanceConfigInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Image style constant for user presets in the database.
......@@ -48,7 +48,7 @@
/**
* Implements hook_help().
*/
function image_help($route_name, Request $request) {
function image_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.image':
$output = '';
......@@ -70,11 +70,11 @@ function image_help($route_name, Request $request) {
return '<p>' . t('Image styles commonly provide thumbnail sizes by scaling and cropping images, but can also add various effects before an image is displayed. When an image is displayed with a style, a new file is created and the original image is left unchanged.') . '</p>';
case 'image.effect_add_form':
$effect = \Drupal::service('plugin.manager.image.effect')->getDefinition($request->attributes->get('image_effect'));
$effect = \Drupal::service('plugin.manager.image.effect')->getDefinition($route_match->getParameter('image_effect'));
return isset($effect['description']) ? ('<p>' . $effect['description'] . '</p>') : NULL;
case 'image.effect_edit_form':
$effect = $request->attributes->get('image_style')->getEffect($request->attributes->get('image_effect'));
$effect = $route_match->getParameter('image_style')->getEffect($route_match->getParameter('image_effect'));
$effect_definition = $effect->getPluginDefinition();
return isset($effect_definition['description']) ? ('<p>' . $effect_definition['description'] . '</p>') : NULL;
}
......
......@@ -7,6 +7,7 @@
use Drupal\Core\PhpStorage\PhpStorageFactory;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\language\ConfigurableLanguageManager;
use Drupal\language\ConfigurableLanguageManagerInterface;
use Drupal\language\Entity\Language as LanguageEntity;
......@@ -14,12 +15,11 @@
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrlFallback;
use Drupal\node\NodeTypeInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Implements hook_help().
*/
function language_help($route_name, Request $request) {
function language_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.language':
$output = '';
......@@ -73,13 +73,13 @@ function language_help($route_name, Request $request) {
return $output;
case 'block.admin_edit':
if (($block = $request->attributes->get('block')) && $block->get('plugin') == 'language_block:language_interface') {
if (($block = $route_match->getParameter('block')) && $block->get('plugin') == 'language_block:language_interface') {
return '<p>' . t('With multiple languages added, registered users can select their preferred language and authors can assign a specific language to content.') . '</p>';
}
break;
case 'block.admin_add':
if ($request->attributes->get('plugin_id') == 'language_block:language_interface') {
if ($route_match->getParameter('plugin_id') == 'language_block:language_interface') {
return '<p>' . t('With multiple languages added, registered users can select their preferred language and authors can assign a specific language to content.') . '</p>';
}
break;
......
......@@ -6,12 +6,12 @@
*/
use Drupal\Component\Utility\String;