summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathaniel Catchpole2014-05-12 12:57:33 (GMT)
committerNathaniel Catchpole2014-05-12 12:57:33 (GMT)
commite67b313df410a1917648becb27acf60efa57d204 (patch)
tree2a6cd7648b31dfcdc7c675bb860bd860c72ed381
parenta78a106319fb09c9289d23c418133a7447e8aeb4 (diff)
Issue #2068333 by roderik, skipyT, pcambra, plach, Désiré, marcingy, peximo: Convert node SQL queries to the Entity Query API.
-rw-r--r--core/modules/node/lib/Drupal/node/Entity/Node.php1
-rw-r--r--core/modules/node/lib/Drupal/node/NodeStorage.php62
-rw-r--r--core/modules/node/lib/Drupal/node/NodeStorageInterface.php60
-rw-r--r--core/modules/node/node.admin.inc20
-rw-r--r--core/modules/node/node.module127
-rw-r--r--core/modules/node/node.pages.inc74
-rw-r--r--core/modules/quickedit/lib/Drupal/quickedit/Tests/QuickEditLoadingTest.php24
7 files changed, 231 insertions, 137 deletions
diff --git a/core/modules/node/lib/Drupal/node/Entity/Node.php b/core/modules/node/lib/Drupal/node/Entity/Node.php
index 1fc6f03..1d21504 100644
--- a/core/modules/node/lib/Drupal/node/Entity/Node.php
+++ b/core/modules/node/lib/Drupal/node/Entity/Node.php
@@ -24,6 +24,7 @@ use Drupal\user\UserInterface;
* label = @Translation("Content"),
* bundle_label = @Translation("Content type"),
* controllers = {
+ * "storage" = "Drupal\node\NodeStorage",
* "view_builder" = "Drupal\node\NodeViewBuilder",
* "access" = "Drupal\node\NodeAccessController",
* "form" = {
diff --git a/core/modules/node/lib/Drupal/node/NodeStorage.php b/core/modules/node/lib/Drupal/node/NodeStorage.php
new file mode 100644
index 0000000..8bb17fd
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/NodeStorage.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\node\NodeStorageController.
+ */
+
+namespace Drupal\node;
+
+use Drupal\Core\Database\Database;
+use Drupal\Core\Entity\ContentEntityDatabaseStorage;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Language\Language;
+
+/**
+ * Defines the controller class for nodes.
+ *
+ * This extends the base storage class, adding required special handling for
+ * node entities.
+ */
+class NodeStorage extends ContentEntityDatabaseStorage implements NodeStorageInterface {
+
+ /**
+ * {@inheritdoc}
+ */
+ public function revisionIds(NodeInterface $node) {
+ return $this->database->query(
+ 'SELECT vid FROM {node_revision} WHERE nid=:nid ORDER BY vid',
+ array(':nid' => $node->id())
+ )->fetchCol();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function userRevisionIds(AccountInterface $account) {
+ return $this->database->query(
+ 'SELECT vid FROM {node_field_revision} WHERE uid = :uid ORDER BY vid',
+ array(':uid' => $account->id())
+ )->fetchCol();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function updateType($old_type, $new_type) {
+ return $this->database->update('node')
+ ->fields(array('type' => $new_type))
+ ->condition('type', $old_type)
+ ->execute();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clearRevisionsLanguage($language) {
+ return $this->database->update('node_revision')
+ ->fields(array('langcode' => Language::LANGCODE_NOT_SPECIFIED))
+ ->condition('langcode', $language->id)
+ ->execute();
+ }
+}
diff --git a/core/modules/node/lib/Drupal/node/NodeStorageInterface.php b/core/modules/node/lib/Drupal/node/NodeStorageInterface.php
new file mode 100644
index 0000000..db68307
--- /dev/null
+++ b/core/modules/node/lib/Drupal/node/NodeStorageInterface.php
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\node\NodeStorageControllerInterface.
+ */
+
+namespace Drupal\node;
+
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Defines a common interface for node entity controller classes.
+ */
+interface NodeStorageInterface extends EntityStorageInterface {
+
+ /**
+ * Returns a list of node revision IDs for a specific node.
+ *
+ * @param \Drupal\node\NodeInterface
+ * The node entity.
+ *
+ * @return int[]
+ * Node revision IDs (in ascending order).
+ */
+ public function revisionIds(NodeInterface $node);
+
+ /**
+ * Returns a list of revision IDs having a given user as node author.
+ *
+ * @param \Drupal\Core\Session\AccountInterface $account
+ * The user entity.
+ *
+ * @return int[]
+ * Node revision IDs (in ascending order).
+ */
+ public function userRevisionIds(AccountInterface $account);
+
+ /**
+ * Updates all nodes of one type to be of another type.
+ *
+ * @param string $old_type
+ * The current node type of the nodes.
+ * @param string $new_type
+ * The new node type of the nodes.
+ *
+ * @return int
+ * The number of nodes whose node type field was modified.
+ */
+ public function updateType($old_type, $new_type);
+
+ /**
+ * Unsets the language for all nodes with the given language.
+ *
+ * @param $language
+ * The language object.
+ */
+ public function clearRevisionsLanguage($language);
+}
diff --git a/core/modules/node/node.admin.inc b/core/modules/node/node.admin.inc
index a79328e..b0a806d 100644
--- a/core/modules/node/node.admin.inc
+++ b/core/modules/node/node.admin.inc
@@ -26,14 +26,17 @@ use Drupal\node\NodeInterface;
* @param bool $load
* (optional) TRUE if $nodes contains an array of node IDs to be loaded, FALSE
* if it contains fully loaded nodes. Defaults to FALSE.
+ * @param bool $revisions
+ * (optional) TRUE if $nodes contains an array of revision IDs instead of
+ * node IDs. Defaults to FALSE; will be ignored if $load is FALSE.
*/
-function node_mass_update(array $nodes, array $updates, $langcode = NULL, $load = FALSE) {
+function node_mass_update(array $nodes, array $updates, $langcode = NULL, $load = FALSE, $revisions = FALSE) {
// We use batch processing to prevent timeout when updating a large number
// of nodes.
if (count($nodes) > 10) {
$batch = array(
'operations' => array(
- array('_node_mass_update_batch_process', array($nodes, $updates, $langcode, $load))
+ array('_node_mass_update_batch_process', array($nodes, $updates, $langcode, $load, $revisions))
),
'finished' => '_node_mass_update_batch_finished',
'title' => t('Processing'),
@@ -48,10 +51,13 @@ function node_mass_update(array $nodes, array $updates, $langcode = NULL, $load
batch_set($batch);
}
else {
- if ($load) {
+ if ($load && !$revisions) {
$nodes = entity_load_multiple('node', $nodes);
}
foreach ($nodes as $node) {
+ if ($load && $revisions) {
+ $node = entity_revision_load('node', $node);
+ }
_node_mass_update_helper($node, $updates, $langcode);
}
drupal_set_message(t('The update has been performed.'));
@@ -97,10 +103,13 @@ function _node_mass_update_helper(NodeInterface $node, array $updates, $langcode
* @param bool $load
* TRUE if $nodes contains an array of node IDs to be loaded, FALSE if it
* contains fully loaded nodes.
+ * @param bool $revisions
+ * (optional) TRUE if $nodes contains an array of revision IDs instead of
+ * node IDs. Defaults to FALSE; will be ignored if $load is FALSE.
* @param array $context
* An array of contextual key/values.
*/
-function _node_mass_update_batch_process(array $nodes, array $updates, $load, array &$context) {
+function _node_mass_update_batch_process(array $nodes, array $updates, $load, $revisions, array &$context) {
if (!isset($context['sandbox']['progress'])) {
$context['sandbox']['progress'] = 0;
$context['sandbox']['max'] = count($nodes);
@@ -113,7 +122,8 @@ function _node_mass_update_batch_process(array $nodes, array $updates, $load, ar
// For each nid, load the node, reset the values, and save it.
$node = array_shift($context['sandbox']['nodes']);
if ($load) {
- $node = entity_load('node', $node);
+ $node = $revisions ?
+ entity_revision_load('node', $node) : entity_load('node', $node);
}
$node = _node_mass_update_helper($node, $updates);
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index e749f86..25c55e4 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -494,10 +494,7 @@ function node_entity_extra_field_info() {
* The number of nodes whose node type field was modified.
*/
function node_type_update_nodes($old_id, $new_id) {
- return db_update('node')
- ->fields(array('type' => $new_id))
- ->condition('type', $old_id)
- ->execute();
+ return \Drupal::entityManager()->getStorage('node')->updateType($old_id, $new_id);
}
/**
@@ -801,31 +798,18 @@ function node_user_cancel($edit, $account, $method) {
switch ($method) {
case 'user_cancel_block_unpublish':
// Unpublish nodes (current revisions).
- module_load_include('inc', 'node', 'node.admin');
- $nodes = db_select('node_field_data', 'n')
- ->distinct()
- ->fields('n', array('nid'))
+ $nids = \Drupal::entityQuery('node')
->condition('uid', $account->id())
- ->execute()
- ->fetchCol();
- node_mass_update($nodes, array('status' => 0), NULL, TRUE);
+ ->execute();
+ module_load_include('inc', 'node', 'node.admin');
+ node_mass_update($nids, array('status' => 0), NULL, TRUE);
break;
case 'user_cancel_reassign':
- // Anonymize nodes (current revisions).
+ // Anonymize all of the nodes for this old account.
module_load_include('inc', 'node', 'node.admin');
- $nodes = db_select('node_field_data', 'n')
- ->distinct()
- ->fields('n', array('nid'))
- ->condition('uid', $account->id())
- ->execute()
- ->fetchCol();
- node_mass_update($nodes, array('uid' => 0), NULL, TRUE);
- // Anonymize old revisions.
- db_update('node_field_revision')
- ->fields(array('uid' => 0))
- ->condition('uid', $account->id())
- ->execute();
+ $vids = \Drupal::entityManager()->getStorage('node')->userRevisionIds($account);
+ node_mass_update($vids, array('uid' => 0), NULL, TRUE, TRUE);
break;
}
}
@@ -836,15 +820,13 @@ function node_user_cancel($edit, $account, $method) {
function node_user_predelete($account) {
// Delete nodes (current revisions).
// @todo Introduce node_mass_delete() or make node_mass_update() more flexible.
- $nodes = db_select('node_field_data', 'n')
- ->distinct()
- ->fields('n', array('nid'))
+ $nids = \Drupal::entityQuery('node')
->condition('uid', $account->id())
- ->execute()
- ->fetchCol();
- entity_delete_multiple('node', $nodes);
+ ->execute();
+ entity_delete_multiple('node', $nids);
// Delete old revisions.
- $revisions = db_query('SELECT DISTINCT vid FROM {node_field_revision} WHERE uid = :uid', array(':uid' => $account->id()))->fetchCol();
+ $storage_controller = \Drupal::entityManager()->getStorage('node');
+ $revisions = $storage_controller->userRevisionIds($account);
foreach ($revisions as $revision) {
node_revision_delete($revision);
}
@@ -910,34 +892,13 @@ function node_page_title(NodeInterface $node) {
*
* @return string
* A unix timestamp indicating the last time the node was changed.
- */
-function node_last_changed($nid, $langcode = NULL) {
- if (isset($langcode)) {
- $result = db_query('SELECT changed FROM {node_field_data} WHERE nid = :nid AND langcode = :langcode', array(':nid' => $nid, ':langcode' => $langcode))->fetch();
- }
- else {
- $result = db_query('SELECT changed FROM {node_field_data} WHERE nid = :nid AND default_langcode = :default_langcode', array(':nid' => $nid, ':default_langcode' => 1))->fetch();
- }
- return is_object($result) ? $result->changed : FALSE;
-}
-
-/**
- * Returns a list of all the existing revision numbers for the node passed in.
*
- * @param \Drupal\node\NodeInterface $node
- * The node entity.
- *
- * @return
- * An associative array keyed by node revision number.
+ * @todo Remove once https://drupal.org/node/2002180 is resolved. It's only used
+ * for validation, which will be done by EntityChangedConstraintValidator.
*/
-function node_revision_list(NodeInterface $node) {
- $revisions = array();
- $result = db_query('SELECT nr.vid, nfr.title, nr.log, nr.revision_uid AS uid, n.vid AS current_vid, nr.revision_timestamp, u.name FROM {node_field_revision} nfr JOIN {node_revision} nr ON nr.vid = nfr.vid LEFT JOIN {node} n ON n.vid = nfr.vid INNER JOIN {users} u ON u.uid = nr.revision_uid WHERE nfr.nid = :nid AND nfr.default_langcode = 1 ORDER BY nfr.vid DESC', array(':nid' => $node->id()));
- foreach ($result as $revision) {
- $revisions[$revision->vid] = $revision;
- }
-
- return $revisions;
+function node_last_changed($nid, $langcode = NULL) {
+ $changed = \Drupal::entityManager()->getStorage('node')->loadUnchanged($nid)->getChangedTime();
+ return $changed ? $changed : FALSE;
}
/**
@@ -951,31 +912,31 @@ function node_revision_list(NodeInterface $node) {
* visible to the current user.
*/
function node_get_recent($number = 10) {
- $query = db_select('node_field_data', 'n');
+ $account = \Drupal::currentUser();
+ $query = \Drupal::entityQuery('node');
- if (!user_access('bypass node access')) {
+ if (!$account->hasPermission('bypass node access')) {
// If the user is able to view their own unpublished nodes, allow them
// to see these in addition to published nodes. Check that they actually
// have some unpublished nodes to view before adding the condition.
- if (user_access('view own unpublished content') && $own_unpublished = db_query('SELECT DISTINCT nid FROM {node_field_data} WHERE uid = :uid AND status = :status', array(':uid' => \Drupal::currentUser()->id(), ':status' => NODE_NOT_PUBLISHED))->fetchCol()) {
- $query->condition(db_or()
- ->condition('n.status', NODE_PUBLISHED)
- ->condition('n.nid', $own_unpublished, 'IN')
- );
+ $access_query = \Drupal::entityQuery('node')
+ ->condition('uid', $account->id())
+ ->condition('status', NODE_NOT_PUBLISHED);
+ if ($account->hasPermission('view own unpublished content') && ($own_unpublished = $access_query->execute())) {
+ $query->orConditionGroup()
+ ->condition('status', NODE_PUBLISHED)
+ ->condition('nid', $own_unpublished, 'IN');
}
else {
// If not, restrict the query to published nodes.
- $query->condition('n.status', NODE_PUBLISHED);
+ $query->condition('status', NODE_PUBLISHED);
}
- }
+ }
$nids = $query
- ->distinct()
- ->fields('n', array('nid'))
- ->orderBy('n.changed', 'DESC')
+ ->sort('changed', 'DESC')
->range(0, $number)
->addTag('node_access')
- ->execute()
- ->fetchCol();
+ ->execute();
$nodes = node_load_multiple($nids);
@@ -1078,16 +1039,13 @@ function node_feed($nids = FALSE, $channel = array()) {
$rss_config = \Drupal::config('system.rss');
if ($nids === FALSE) {
- $nids = db_select('node_field_data', 'n')
- ->distinct()
- ->fields('n', array('nid'))
- ->condition('n.promote', 1)
- ->condition('n.status', 1)
- ->orderBy('n.created', 'DESC')
+ $nids = \Drupal::entityQuery('node')
+ ->condition('status', 1)
+ ->condition('promote', 1)
+ ->sort('created', 'DESC')
->range(0, $rss_config->get('items.limit'))
->addTag('node_access')
- ->execute()
- ->fetchCol();
+ ->execute();
}
$item_length = $rss_config->get('items.view_mode');
@@ -1272,9 +1230,9 @@ function node_form_system_themes_admin_form_submit($form, &$form_state) {
* the process above is followed except that hook_node_access() is not called on
* each node for performance reasons and for proper functioning of the pager
* system. When adding a node listing to your module, be sure to use a dynamic
- * query created by db_select() and add a tag of "node_access". This will allow
- * modules dealing with node access to ensure only nodes to which the user has
- * access are retrieved, through the use of hook_query_TAG_alter().
+ * entity query and add a tag of "node_access". This will allow modules dealing
+ * with node access to ensure only nodes to which the user has access are
+ * retrieved, through the use of hook_query_TAG_alter().
*
* Note: Even a single module returning NODE_ACCESS_DENY from hook_node_access()
* will block access to the node. Therefore, implementers should take care to
@@ -1749,10 +1707,7 @@ function node_file_download_access($field, EntityInterface $entity, File $file)
*/
function node_language_entity_delete(LanguageEntity $language) {
// On nodes with this language, unset the language.
- db_update('node_revision')
- ->fields(array('langcode' => ''))
- ->condition('langcode', $language->id())
- ->execute();
+ \Drupal::entityManager()->getStorage('node')->clearRevisionsLanguage($language);
}
/**
diff --git a/core/modules/node/node.pages.inc b/core/modules/node/node.pages.inc
index efc88fb..45ff09f 100644
--- a/core/modules/node/node.pages.inc
+++ b/core/modules/node/node.pages.inc
@@ -121,8 +121,6 @@ function node_revision_overview($node) {
$header = array(t('Revision'), t('Operations'));
- $revisions = node_revision_list($node);
-
$rows = array();
$type = $node->getType();
@@ -134,45 +132,49 @@ function node_revision_overview($node) {
if ((user_access("delete $type revisions") || user_access('delete all revisions') || user_access('administer nodes')) && $node->access('delete')) {
$delete_permission = TRUE;
}
- foreach ($revisions as $revision) {
- $row = array();
- if ($revision->current_vid > 0) {
- $username = array(
- '#theme' => 'username',
- '#account' => user_load($revision->uid),
- );
- $row[] = array('data' => t('!date by !username', array('!date' => l(format_date($revision->revision_timestamp, 'short'), 'node/' . $node->id()), '!username' => drupal_render($username)))
- . (($revision->log != '') ? '<p class="revision-log">' . Xss::filter($revision->log) . '</p>' : ''),
- 'class' => array('revision-current'));
- $row[] = array('data' => drupal_placeholder(t('current revision')), 'class' => array('revision-current'));
- }
- else {
- $username = array(
- '#theme' => 'username',
- '#account' => user_load($revision->uid),
- );
- $row[] = t('!date by !username', array('!date' => l(format_date($revision->revision_timestamp, 'short'), "node/" . $node->id() . "/revisions/" . $revision->vid . "/view"), '!username' => drupal_render($username)))
- . (($revision->log != '') ? '<p class="revision-log">' . Xss::filter($revision->log) . '</p>' : '');
- if ($revert_permission) {
- $links['revert'] = array(
- 'title' => t('Revert'),
- 'href' => "node/" . $node->id() . "/revisions/" . $revision->vid . "/revert",
+ $vids = \Drupal::entityManager()->getStorage('node')->revisionIds($node);
+ foreach (array_reverse($vids) as $vid) {
+ if ($revision = node_revision_load($vid)) {
+
+ $row = array();
+ if ($vid == $node->getRevisionId()) {
+ $username = array(
+ '#theme' => 'username',
+ '#account' => $revision->getOwner(),
);
+ $row[] = array('data' => t('!date by !username', array('!date' => l(format_date($revision->getRevisionCreationTime(), 'short'), 'node/' . $node->id()), '!username' => drupal_render($username)))
+ . (($revision->log->value != '') ? '<p class="revision-log">' . Xss::filter($revision->log->value) . '</p>' : ''),
+ 'class' => array('revision-current'));
+ $row[] = array('data' => drupal_placeholder(t('current revision')), 'class' => array('revision-current'));
}
- if ($delete_permission) {
- $links['delete'] = array(
- 'title' => t('Delete'),
- 'href' => "node/" . $node->id() . "/revisions/" . $revision->vid . "/delete",
+ else {
+ $username = array(
+ '#theme' => 'username',
+ '#account' => $revision->getOwner(),
+ );
+ $row[] = t('!date by !username', array('!date' => l(format_date($revision->getRevisionCreationTime(), 'short'), "node/" . $node->id() . "/revisions/" . $vid . "/view"), '!username' => drupal_render($username)))
+ . (($revision->log->value != '') ? '<p class="revision-log">' . Xss::filter($revision->log->value) . '</p>' : '');
+ if ($revert_permission) {
+ $links['revert'] = array(
+ 'title' => t('Revert'),
+ 'href' => "node/" . $node->id() . "/revisions/" . $vid . "/revert",
+ );
+ }
+ if ($delete_permission) {
+ $links['delete'] = array(
+ 'title' => t('Delete'),
+ 'href' => "node/" . $node->id() . "/revisions/" . $vid . "/delete",
+ );
+ }
+ $row[] = array(
+ 'data' => array(
+ '#type' => 'operations',
+ '#links' => $links,
+ ),
);
}
- $row[] = array(
- 'data' => array(
- '#type' => 'operations',
- '#links' => $links,
- ),
- );
+ $rows[] = $row;
}
- $rows[] = $row;
}
$build['node_revisions_table'] = array(
diff --git a/core/modules/quickedit/lib/Drupal/quickedit/Tests/QuickEditLoadingTest.php b/core/modules/quickedit/lib/Drupal/quickedit/Tests/QuickEditLoadingTest.php
index b5122dd..220a14a 100644
--- a/core/modules/quickedit/lib/Drupal/quickedit/Tests/QuickEditLoadingTest.php
+++ b/core/modules/quickedit/lib/Drupal/quickedit/Tests/QuickEditLoadingTest.php
@@ -143,9 +143,10 @@ class QuickEditLoadingTest extends WebTestBase {
$this->assertRaw('data-quickedit-field-id="node/1/body/und/full"');
// There should be only one revision so far.
- $revisions = node_revision_list(node_load(1));
- $this->assertIdentical(1, count($revisions), 'The node has only one revision.');
- $original_log = $revisions[1]->log;
+ $node = node_load(1);
+ $vids = \Drupal::entityManager()->getStorage('node')->revisionIds($node);
+ $this->assertIdentical(1, count($vids), 'The node has only one revision.');
+ $original_log = $node->log->value;
// Retrieving the metadata should result in a 200 JSON response.
$htmlPageDrupalSettings = $this->drupalSettings;
@@ -236,9 +237,10 @@ class QuickEditLoadingTest extends WebTestBase {
$this->assertText('Fine thanks.');
// Ensure no new revision was created and the log message is unchanged.
- $revisions = node_revision_list(node_load(1));
- $this->assertIdentical(1, count($revisions), 'The node has only one revision.');
- $this->assertIdentical($original_log, $revisions[1]->log, 'The revision log message is unchanged.');
+ $node = node_load(1);
+ $vids = \Drupal::entityManager()->getStorage('node')->revisionIds($node);
+ $this->assertIdentical(1, count($vids), 'The node has only one revision.');
+ $this->assertIdentical($original_log, $node->log->value, 'The revision log message is unchanged.');
// Now configure this node type to create new revisions automatically,
// then again retrieve the field form, fill it, submit it (so it ends up
@@ -284,10 +286,12 @@ class QuickEditLoadingTest extends WebTestBase {
$this->assertResponse(200);
// Test that a revision was created with the correct log message.
- $revisions = node_revision_list(node_load(1));
- $this->assertIdentical(2, count($revisions), 'The node has two revisions.');
- $this->assertIdentical($original_log, $revisions[1]->log, 'The first revision log message is unchanged.');
- $this->assertIdentical('Updated the <em class="placeholder">Body</em> field through in-place editing.', $revisions[2]->log, 'The second revision log message was correctly generated by Quick Edit module.');
+ $vids = \Drupal::entityManager()->getStorage('node')->revisionIds(node_load(1));
+ $this->assertIdentical(2, count($vids), 'The node has two revisions.');
+ $revision = node_revision_load($vids[0]);
+ $this->assertIdentical($original_log, $revision->log->value, 'The first revision log message is unchanged.');
+ $revision = node_revision_load($vids[1]);
+ $this->assertIdentical('Updated the <em class="placeholder">Body</em> field through in-place editing.', $revision->log->value, 'The second revision log message was correctly generated by Quick Edit module.');
}
}