Quantcast
Channel: Issues for Drupal core
Viewing all 296542 articles
Browse latest View live

How to use rollback_action in a migration

$
0
0

I am migrating roles from D6 to D8 with Migrate. D6 roles are mapped to existing D8 ones, which should not be removed (see my migration below). At rollback, the Pro+ role is removed. Apparently, Migrate uses a rollback_action which has two possible values, as defined in MigrateIdMapInterface:

  /**
   * Codes reflecting how to handle the destination item on rollback.
   */
  const ROLLBACK_DELETE = 0;
  const ROLLBACK_PRESERVE = 1;

I tried to use this key in my YAML file at different levels, to no avail. Could you help me?

id: myproject_d6_user_role
label: 'User roles'
migration_group: myproject_d6
source:
  plugin: d6_user_role
process:
  id:
    -
      plugin: static_map
      source: name
      bypass: false
      map:
        'Utilisateurs anonymes': 'anonymous''Utilisateurs enregistrés': 'authenticated''Gestionnaire des utilisateurs': 'redacteur''Pro+': 'pro_plus''Utilisateurs professionnels': 'pro_plus'
    -
      plugin: user_update_8002
  permissions:
    -
      plugin: static_map
      source: permissions
      bypass: true
      map:
        'post comments without approval': 'skip comment approval'
    -
      plugin: system_update_7000
    -
      plugin: node_update_7008
    -
      plugin: flatten
    -
      plugin: filter_format_permission
destination:
  plugin: 'entity:user_role'
  rollback_action: 1
rollback_action: 1
migration_dependencies: {  }

Importing images from feed

$
0
0

I am importing staff from a json feed which includes images. The best solution I could find pulls the image down first, creates a media entity and adds it to node which becomes the dependency of the staff node migration. This all works well enough, but one thing I noticed and cannot figure out is that every time the image migration is run with update option every image is downloaded again. I understand that with images change detection may be an issue but I would rather not accumulate so many images on the server. Is this normal or is my migration flawed?

Thank you!

Updating content migration error: entity revision

$
0
0

Hi,

I'm migrating from D6 website content, and to add new content created since I done the first migration, I get this error:

Update existing 'node' entity revision while changing the revision ID is not supported.

This is what I done to get this:

  • drush @vmdevd8lr ms
  • upgrade_d6_node_fiche_formations Idle 25 23 2
  • drush @vmdevd8lr mim --update upgrade_d6_node_fiche_formations
 19/25 [=====================>------]  76% [error]  Drupal\Core\Entity\EntityStorageException: Update existing 'node' entity revision while changing the revision ID is not supported. in Drupal\Core\Entity\ContentEntityStorageBase->doPreSave() (line 711 of /var/www/drupal-8/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php).
 [error]  Update existing 'node' entity revision while changing the revision ID is not supported. (/var/www/drupal-8/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:846)
 [notice] Processed 25 items (2 created, 22 updated, 1 failed, 0 ignored) - done with 'upgrade_d6_node_fiche_formations'
  • drush @vmdevd8lr mim --update upgrade_d6_node_revision_fiche_formations

[notice] Processed 98 items (1 created, 97 updated, 0 failed, 0 ignored) - done with 'upgrade_d6_node_revision_fiche_formations'

  • drush @vmdevd8lr mim --update upgrade_d6_node_fiche_formations_lr
 19/25 [=====================>------]  76% [error]  Drupal\Core\Entity\EntityStorageException: Update existing 'node' entity revision while changing the revision ID is not supported. in Drupal\Core\Entity\ContentEntityStorageBase->doPreSave() (line 711 of /var/www/drupal-8/core/lib/Drupal/Core/Entity/ContentEntityStorageBase.php).
 [error]  Update existing 'node' entity revision while changing the revision ID is not supported. (/var/www/drupal-8/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:846)
 [notice] Processed 25 items (2 created, 22 updated, 1 failed, 0 ignored) - done with 'upgrade_d6_node_fiche_formations_lr'

At the end, I have my new content but whithout images in it and watchdog say:
Impossible d'appliquer le style d'image Vignette (100x100) à public://briwuslenaswouovomefrumirunaswopolajuprafrestochiluspasudruwrihuspidrimusoshoduhacoste car le style n'est pas pris en charge.

The gilt provided by this, but no idea about what to fix:

 drush @vmdevd8lr mmsg  upgrade_d6_node_fiche_formations
 -------------- ------------------- ------- -----------------------------------------------------------------------------------------
  Source ID(s)   Destination ID(s)   Level   Message
 -------------- ------------------- ------- -----------------------------------------------------------------------------------------
  371            371                 1       Update existing 'node' entity revision while changing the revision ID is not supported.
                                             (/var/www/drupal-8/core/lib/Drupal/Core/Entity/Sql/SqlContentEntityStorage.php:846)

Thanks for help.

PRE_IMPORT event detect whether an update or not.

$
0
0

I've created a PRE_IMPORT event function per examples I found. It works as expected, see below. What I would like to do is detect whether the --update option is being used or not. The issue I run into is that I'm managing images via a feed that needs to be checked daily for new and updated images. Unlike entities not updating if nothing changes, files always downloaded whether they have changed or not, thus accumulating an immense # of files on our server. So on update I want to delete the images before downloading new ones. Ideally migrate would not just download new files every time, but I have yet to figure how to make that happen. In the meantime, I want to delete on update. This works fine except when I want to import new images not using the update option I delete all the images without downloading new ones. Thank you.

    public function __construct(array $configuration, $plugin_id, $plugin_definition, \Drupal\migrate\Plugin\MigrationPluginManagerInterface $migration_plugin_manager, \Drupal\migrate\Plugin\MigratePluginManagerInterface $source_plugin_manager, \Drupal\migrate\Plugin\MigratePluginManagerInterface $process_plugin_manager, \Drupal\migrate\Plugin\MigrateDestinationPluginManager $destination_plugin_manager, \Drupal\migrate\Plugin\MigratePluginManagerInterface $idmap_plugin_manager)
    {
        parent::__construct($configuration, $plugin_id, $plugin_definition, $migration_plugin_manager, $source_plugin_manager, $process_plugin_manager, $destination_plugin_manager, $idmap_plugin_manager);

        \Drupal::service('event_dispatcher')->addListener(MigrateEvents::PRE_IMPORT, array($this, 'onPreImport'));
    }

  /**
   * Runs Before an import starts.
   *
   * Used to attach objects to object groups
   */
  public function onPreImport(MigrateImportEvent $event) {
....
}

Multilingual Migrations for Non-Drupal Sources

$
0
0

Motivation

So there's a flurry of activity concerning multilingual Drupal content from D6 & D7 being properly migrated (#2208401: [META] Remaining multilingual migation paths), but I'm not seeing much if anything concerning non-Drupal imports for multilingual content. Point of fact, I'm having trouble coming up with good examples of how multilingual migrations are intended to work, let alone actual working examples using Drupal or other sources.

Proposed resolution

I'd like to use this thread to compile migration solutions or examples that successfully implement multilingual content. Ultimately, that would become a documentation page, or depending on how things go a feature request or module.

Groundwork

So since I had an immediate need and was looking for solutions I ended up finding #2313265: How import Multilingual Content with Migrate Module. While it originated Pre-D8, @digitaldonkey had a good solution for a POST_ROW_SAVE event in D8. I liked it, but it wasn't flexible enough for me to I took it and made it a little more broadly based. I updated the 'updateTranslations' function of the original:

/**
   * MigrateEvents::POST_ROW_SAVE event handler.
   *
   * @param MigratePostRowSaveEvent $event
   *   Instance of Drupal\migrate\Event\MigratePostRowSaveEvent.
   */
  public function updateTranslations(MigratePostRowSaveEvent $event) {

    $row =  $event->getRow();

    if ($row->hasSourceProperty('constants/available_languages')) {

      // These are defined in migration.yml.
      $available_languages = $row->getSource()['constants']['available_languages'];
      $default_language = $row->getDestination()['langcode'];

      // Unset default language from available languages.
      unset($available_languages[$default_language]);

      $migrated_entity = $event->destinationIdValues[0];
      $dest_config = $event->getMigration()->getDestinationConfiguration();
      $dest_plugin = explode(':', $dest_config['plugin']);

      if ($dest_plugin[0] == 'entity') {
        $entity = \Drupal::entityTypeManager()
          ->getStorage($dest_plugin[1])
          ->load($migrated_entity);

        foreach ($available_languages as $key => $lang_map) {

          $translated_entity = $entity->addTranslation($key);
          foreach ($lang_map as $field => $source) {
            $translated_entity->$field = $row->getSourceProperty($source);
          }
          $translated_entity->save();

        }

        $map = $event->getMigration()->getIdMap();
        $map->saveIdMapping($event->getRow(), array($migrated_entity));
      }
    }
  }

What this allows you to do is declare translations in your YAML file by adding available translations as constants. So your source would look something like

source:
  ...
  constants:
    available_languages:
      en:
      es:
        title: title_spanish

Where title is the name of the field you're entering and title_spanish would be the field coming in from the source. This is perfect for a lightweight translation of content from the same source. Note that it only works on entities and that the main langcode MUST be set in the process.

For bulkier translations that need processing or those coming from a different source, I put together a custom destination. This takes a separate migration and appends identically ID'd translations to it.


namespace Drupal\custom_migrate\Plugin\migrate\destination;

use Drupal\Component\Plugin\DependentPluginInterface;
use Drupal\Core\Entity\DependencyTrait;
use Drupal\migrate\Plugin\MigratePluginManager;
use Drupal\migrate\Plugin\MigrationPluginManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate\Row;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\migrate\Plugin\migrate\destination\DestinationBase;

/**
 * Provides Configuration Management destination plugin.
 *
 * Persist data to the config system.
 *
 * When a property is NULL, the default is used unless the configuration option
 * 'store null' is set to TRUE.
 *
 * @MigrateDestination(
 *   id = "entity_translation"
 * )
 */
class EntityTranslation extends DestinationBase implements ContainerFactoryPluginInterface, DependentPluginInterface {

  use DependencyTrait;

  /**
   * The config object.
   *
   * @var \Drupal\migrate\Plugin\MigrationInterface
   */
  protected $old_migration;

  /**
   * The language manager.
   *
   * @var \Drupal\Core\Language\LanguageManagerInterface
   */
  protected $language_manager;

  /**
   * The process plugin manager.
   *
   * @var \Drupal\migrate\Plugin\MigratePluginManager
   */
  protected $processPluginManager;

  /**
   * The migration plugin manager.
   *
   * @var \Drupal\migrate\Plugin\MigrationPluginManagerInterface
   */
  protected $migrationPluginManager;

  /**
   * Constructs a Config destination object.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin ID for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\migrate\Plugin\MigrationInterface $migration
   *   The migration entity.
   * @param \Drupal\Core\Language\ConfigurableLanguageManagerInterface $language_manager
   *   The language manager.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, MigrationPluginManagerInterface $migration_plugin_manager, MigratePluginManager $process_plugin_manager, LanguageManagerInterface $language_manager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
    $this->migrationPluginManager = $migration_plugin_manager;
    $this->migration = $migration;
    $this->processPluginManager = $process_plugin_manager;
    $this->language_manager = $language_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration = NULL) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $migration,
      $container->get('plugin.manager.migration'),
      $container->get('plugin.manager.migrate.process'),
      $container->get('language_manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function import(Row $row, array $old_destination_id_values = array()) {
    
    $migration_id = $this->configuration['migration'];
    $migration = $this->migrationPluginManager->createInstance($migration_id);

    // TODO: I think this only works right now if the keys and key labels match, so I'll need to expand later
    $source_id_values = $row->getSourceIdValues();

    $destination_ids = $migration->getIdMap()->lookupDestinationID($source_id_values);

    $dest_config = $migration->getDestinationConfiguration();
    $dest_plugin = explode(':', $dest_config['plugin']);

    $entity = \Drupal::entityTypeManager()
      ->getStorage($dest_plugin[1])
      ->load($destination_ids[0]);

    $lang = $row->getDestinationProperty('langcode');

    // TODO: Validate langcode against list of site languages

    $translated_entity = $entity->addTranslation($lang, $row->getDestination());
    $translated_entity->save();

    return $destination_ids;

  }

  /**
   * {@inheritdoc}
   */
  public function fields(MigrationInterface $migration = NULL) {
    // @todo Dynamically fetch fields using Config Schema API.
  }

  /**
   * {@inheritdoc}
   */
  public function getIds() {
    $ids['config_name']['type'] = 'string';
    return $ids;
  }

  /**
   * {@inheritdoc}
   */
  public function calculateDependencies() {
    $provider = explode('.', $this->config->getName(), 2)[0];
    $this->addDependency('module', $provider);
    return $this->dependencies;
  }

}

It's still very rough, but once it's in place you can use it to translate entities by adding this destination:

destination:
  plugin: entity_translation
  migration: original_content

Where original_content is the targeted migration. Note that it's still very rough, but is certainly a step in the right direction. Once again, it will only work for entities and the langcode needs to be set in the process.

Make every migrate process plugin that provides 'default_value' be able to correctly handle 'NULL' default values

$
0
0

Problem/Motivation

Right now, it is impossible to set NULL as default value for at least the extract migrate process plugin.

If one needs NULL as default value at the extract process plugin, the only workaround I've found is setting it to '' (empty string)|0 (zero integer)|FALSE etc and add a 'default_value' process plugin without 'strict' (or with strict set to FALSE, with NULL default value.

So, this does not work:

[...]
process:
  property:
    plugin: extract
    source: source_property
    index:
      - 0
      - value
    default_value: null
[...]

Workaround for the above:

[...]
process:
  property:
    -
      plugin: extract
      source: source_property
      index:
        - 0
        - value
      default_value: ''
    -
      plugin: default_value
      default_value: null
[...]

Proposed resolution

From discussion on Slack the way to go is to use array_key_exists.

These are the plugins with a default_value or default configuration property and all but Extract allow NULL to be a default value. This issue has a patch for Extract.

  1. /migrate/src/Plugin/migrate/process/DefaultValue.php
  2. migrate/src/Plugin/migrate/process/Extract.php
  3. migrate/src/Plugin/migrate/process/FormatDate.php
  4. migrate/src/Plugin/migrate/process/NullCoalesce.php
  5. migrate/src/Plugin/migrate/process/StaticMap.php
  • Create a change record.
  • Remaining tasks

    • Decide whether this is a bug, or a feature request. I'm unsure.
    • Assess BC implications.

    User interface changes

    API changes

    @tbd

    Data model changes

    Nothing.

    Moving modules breaks system

    $
    0
    0

    Problem/Motivation

    Moving modules into contrib/custom after install doesn't seem to work. According to the documentation, all one has to do if one wants to move modules into a custom or contrib directory structure is mv the directory, and clear the cache. This does not work. In fact uninstalling a module, and installing it in one of these directories doesn't work.

    Proposed resolution

    Ultimately fix this if it can be fixed, but presently updating the documentation would help alleviate the 'oh crap' feeling of a broken site.

    Remaining tasks

    User interface changes

    API changes

    Data model changes

    [PHP 8] Parameter order fixes


    The table used for filtering and sorting in comment_ces_last_updated is incorrect

    $
    0
    0

    SQLSTATE[42S22]: Column not found: 1054 Unknown column 'node.changed' in 'field list':

    node_field_data.created should be set in the field, but because it uses node.created, it will become column not found in Views.

    When using fields, use node_field_data.changed correctly.

    Migrating more than 1 entity reference field instance fails

    $
    0
    0

    Problem/Motivation

    In Drupal 7, the entityreference module allowed to create multiple field instances of the same field. The migration here "works" but then any time an entity without any data attempts to set an entity reference value an InvalidArgumentException is thrown in ContentEntityBase.

    InvalidArgumentException: Field <field name> is unknown.

    A comparison between getting field definitions directly from entity_field.manager reveals that the field does in fact exist on the bundle, but getting the field definition on the entity itself fails. I found that if I reset the field definitions before the exception, then it tries to go further, but runs into a similar exception in typed_data_manager.

    Furthermore this is only an issue for one of the bundles. The other bundle works fine.

    Steps to reproduce (as detailed in a test-only patch):

    1. Add field_reference_3 field_config
    2. Add field_reference_3 field_config_instance to both article and forum node bundles.
    3. Run the appropriate migrations.
    4. Load node 2 (an article node) e.g. $node = Node::load(2);
    5. Attempt to set an initial reference e.g. $node->set('field_reference_3', [5]); or $node->get('field_reference_3')->appendItem()->set('field_reference_3', [5]); or $node->field_reference_3 = ['target_id' => 5];
    6. An exception is thrown and we can see that the field definition doesn't exist on the node, but does exist on field manager.

    This might be why #2814963: Support Drupal 7 entity reference fields is still open/postponed even though plugins exist for it?

    Proposed resolution

    Reset the entity cache of the entity type that a field instance is attached to after the field instance is migrated.

    Remaining tasks

    1. Review proposed resolution
    2. Reword test comments to accurately describe the issue and problem

    User interface changes

    Unknown

    API changes

    Unknown

    Data model changes

    Unknown

    How to make nicer comments?

    $
    0
    0

    I attached my comments to my node type......

    I would like to make them nicer....like in Wordpress for example....

    When a user publishes the comment and press save....you can't reply to his comment.....no way....
    also, his email is visible to everybody.....
    I would also like to change SAVE button to something else.....

    In the picture I attached you can see how strange it looks....I would like to just have short date....

    date 3.11.2018
    name george
    comment coment here.....

    Why it needs to look so bad

    Multiple Values Numeric Views Argument 'AND' Does Nothing

    $
    0
    0

    When I add a numeric contextual filter in Views there is an option to Allow Multiple Values with the description 'If selected, users can enter multiple values in the form of 1+2+3 (for OR) or 1,2,3 (for AND).'

    However, regardless of whether I use ',' or '+' I get the same result (OR).

    Taking a look at NumericArgument.php:

    public function query($group_by = FALSE) {
        $this->ensureMyTable();
    
        if (!empty($this->options['break_phrase'])) {
          $break = static::breakString($this->argument, FALSE);
          $this->value = $break->value;
          $this->operator = $break->operator;
        }
        else {
          $this->value = [$this->argument];
        }
    
        $placeholder = $this->placeholder();
        $null_check = empty($this->options['not']) ? '' : " OR $this->tableAlias.$this->realField IS NULL";
    
        if (count($this->value) > 1) {
          $operator = empty($this->options['not']) ? 'IN' : 'NOT IN';
          $placeholder .= '[]';
          $this->query->addWhereExpression(0, "$this->tableAlias.$this->realField $operator($placeholder)" . $null_check, [$placeholder => $this->value]);
        }
    

    I see that we check for the 'break string' and set $this->operator correctly to 'and' or 'or'. But then we never again do anything with $this->operator. We just set the $operator to either IN or NOT IN, ignoring the break string.

    The URL for each item within a book tree should be an instance of \Drupal\Core\Url but is not

    $
    0
    0

    In the available variables section of core/modules/book/templates/book-tree.html.twig within items we have (amongst others):

    * - url: The book link URL, instance of \Drupal\Core\Url.

    However this is no longer true. In https://www.drupal.org/project/drupal/issues/3010378 it was changed from a Url object to a string in the format entity:node/12345. We found this after updating Drupal Core and finding some of our custom code was no longer working.

    Proposed resolution:
    * Either revert the change, so that url continues to be a Url object
    or
    * Update the book-tree.html.twig documentation and publish a change record so anyone relying on the current/previous behaviour is able to update their code accordingly

    Add visibility control conditions to blocks within Layout Builder

    $
    0
    0

    Problem/Motivation

    Layout Builder introduces a new paradigm shift in page building and block placement for content entities without introducing a block visibility mechanism.

    Proposed resolution

    Introduce a block visibility mechanism that includes individual condition configuration on a per block basis.

    Remaining tasks

    Upload, review and ready a block visibility patch.

    User interface changes

    Add a "configure visibility" link to to attached actions of a placed block within the LB user interface.

    API changes

    No changes, just the addition of an optional "visibility" key in the block configuration. Block configuration itself is already separated into a parallel key in preparation for this change, so the existing code anticipates this.

    Data model changes

    See API changes.

    Implement the dropdown menu component styling into the autocomplete widget

    $
    0
    0

    Problem/Motivation

    The Seven style guide defines a reasonable component for a dropdown menu that can be reused in multiple places:

    Proposed resolution

    Implement the dropdown menu as a separate reusable component and then add the classes to the autocomplete widget

    Remaining tasks

    User interface changes

    A nicer, more consistent looking dropdown popup for autocomplete

    API changes

    A new reusable CSS component


    Missing files logged from upgrade from D7 to D8

    $
    0
    0

    Problem/Motivation

    I was following the upgrade process, cleanup all the modules in d7, enable few modules in d8 that needs to be upgrade, and then I process the upgrade on the page www.myd8.com/upgrade . after 1 hours in 24%, I got the error message below, the whole things breaks, so the upgrade failure, in fact, after clean up all the date, I only have one content type that has about 10k nodes, structurally is not complicated. I am looking for the advise for how should I re-do this, I believe I will get the same problem next time.

    I remember when I rebuild the sitemap or rebuilding whatever in the site like permission in my D7, I always getting this same problem for "......Path: /batch?id=2&....."

    so please suggest what I need to do to get over this. Thank you.

    An error has occurred.
    Please continue to the error page

    An AJAX HTTP error occurred.
    HTTP Result Code: 503
    Debugging information follows.
    Path: /batch?id=2&op=do_nojs&op=do
    StatusText: Service Unavailable
    ResponseText:
    503 Service Unavailable
    Service Unavailable
    The server is temporarily unable to service your
    request due to maintenance downtime or capacity
    problems. Please try again later.
    Additionally, a 503 Service Unavailable
    error was encountered while trying to use an ErrorDocument to handle the request.

    Added from #5 The logs contain many errors
    Message Source ID 29504: File '/home/mysite/public_html//sites/default/files/xxcustom/LOGO-POPUP-f123s.jpg' does not exist

    Proposed resolution

    Check that the files are accessible to the web server on the new site and that the correct directory path is entered on the credential form.

    Filter migration cannot be extended

    $
    0
    0

    It doesn't seem possible to extend the filter module migration and add support for filters provided by other modules.
    On example is pathologic module #2693695: Provide migration support
    No matter what i do, i can't get it to pickup the new yml file

    Unused local variables in testCheckNamedRouteWithUpcastedValues() and testCheckNamedRouteWithDefaultValue()

    $
    0
    0

    In /core core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php file test method testCheckNamedRouteWithUpcastedValues() and testCheckNamedRouteWithDefaultValue() found unused variables.

    I removed the following variable from both method.

    $map = [];
    

    Image upload causing issue on migrated site

    $
    0
    0

    I have migrated a site from drupal 7 to 8 using migrate ui module.

    So everything looks good.
    But whenever i am trying to upload a image on image field or ckeditor image field its throwing the following error.

    upload

    Anyone faced same issue?

    Concurrent editing of layouts is very confusing

    $
    0
    0

    Problem/Motivation

    If two users attempt to edit the same layout, they will both see the changes the other is making.

    Proposed resolution

    Mimic the Views UI (which also uses tempstore.shared) and lock the Layout Builder UI when another user is editing the layout.

    Remaining tasks

    N/A

    User interface changes

    The LB UI will now show a message when there is a lock of another user. Breaking the lock will bring you back to the LB UI to make your own changes.

    API changes

    N/A

    Data model changes

    N/A

    Release notes snippet

    N/A

    Viewing all 296542 articles
    Browse latest View live


    <script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>