Problem/Motivation
Hard-coding to an SQL backend is bad mk
Proposed resolution
Use the entity API
Remaining tasks
Reviews
User interface changes
None
API changes
None
Data model changes
None
Hard-coding to an SQL backend is bad mk
Use the entity API
Reviews
None
None
None
Currently, only the key of a List (Text) (or List (Integer) or List (Float)) field is available as a field property. This issue seeks to make an option's label available, as well, as a computed property.
Look at Drupal\text\TextProcessed
as an example.
Create a 'option_label' field property for the three field types provided by the Options module. Because of by-design limitation of JSON API, the property will need to be marked as 'internal', which means it won't be available to REST, JSON API, etc.
None.
For 'list_string', 'list_integer', and 'list_float', field types a new 'label' property will be added.
For 'list_string', 'list_integer', and 'list_float', field types a new 'label' property will be added.
TBD
So I'm not 100% sure if this will be considered a bug or a bad environment (: ...but if I have XDEBUG_CONFIG
set to the empty string then this upsets \Drupal\Tests\XdebugRequestTrait
(Notice: Undefined offset: 1 in /var/www/html/docroot/core/tests/Drupal/Tests/XdebugRequestTrait.php on line 38
) which prevents tests from passing. I appreciate it could be argued I should just not have var set at all! (FWIW I'm working with Docker from a base image that has it set and it seems hard to fully remove it.)
XDEBUG_CONFIG
to the empty string.Consider the empty string the same as an unset variable.
When you implement hook_views_invalidate_cache()
, this hook is not invoked when a view is deleted.
In views.api.php you can find the following example hook that states that this hook is invoked when a view is enabled, disabled, created, updated or deleted. Which is not the case.
/**
* Allow modules to respond to the invalidation of the Views cache.
*
* This hook will fire whenever a view is enabled, disabled, created,
* updated, or deleted.
*
* @see views_invalidate_cache()
*/
function hook_views_invalidate_cache() {
\Drupal\Core\Cache\Cache::invalidateTags(['views']);
}
Invoke the hook when a view is deleted.
\Drupal\file\Entity\File doesn't honor some type hints in \Drupal\file\FileInterface e.g the file size could be null because "the file itself might not exist or be available right now" but getSize() is supposed to return a string. Meanwhile setSize() accepts an integer, so the type for getSize() changes between string and integer depending on if you're getting from the database or from an entity object that is being built/modified. Likewise, the MIME type could be null if the MIME type guesser was unable to find a MIME type.
You can create a file programmatically to play around with its methods:
$file = \Drupal\file\Entity\File::create(['created' => NULL]);
$file->getCreatedTime();
$file->getFileUri();
$file->setFileUri('lol');
$file->save();
$file = \Drupal\file\Entity\File::load($file->id());
Fix \Drupal\file\FileInterface type hints to also accept or return null where null is accepted and saved to the database:
Fix \Drupal\file\FileInterface type hint to allow returning null where null cannot be saved to the database, but may be the current value because it hasn't been saved yet:
Fix \Drupal\file\Entity\File method to ensure it returns an integer (or null) rather than a string, which is already documented to return an integer:
Fix \Drupal\file\Entity\File method to ensure it returns an integer (or null) rather than a string, which previously was documented to return a string, while its setter accepts integer:
In a followup issue targeting a future major version, the phpdoc type hints could be "upgraded" to actual type declarations for function arguments and return types.
File::getCreatedTime() and File::getSize() now return an integer (or null) rather than a string, which is useful if you want to use them with PHP functions that expect integers (you will still have to check if they are null, however). FileInterface::getCreatedTime() was already documented to return an integer anyways.
None.
The constant \DateTime::RFC3339 was removed in PHP 7.2 and should be replaced with \DateTimeInterface::RFC3339
Drupal 9+ requires PHP 7.3+ as per https://www.drupal.org/docs/system-requirements/php-requirements
Find/replace \DateTime::RFC3339 with \DateTimeInterface::RFC3339
Operations are not aligning up for display modes / view modes. Not limited to Seven theme.
TBD.
TBD.
Operations will align.
None.
None.
Found this bug while review #2318875-20: Redo CommentStatisticsInterface
This broken at least from #2101183: Move {comment_entity_statistics} to proper service
Fix and cover with tests
Write tests, probably unittest because:
1) entity without owner interface - will always get 0 as author now (bug)
2) needs test if owner on entity is not set
both cases could mock the current user service with [0-1-2] permutations
no
no
Issue category | Bug because broken |
---|---|
Issue priority | no Major because ... data will regenerate on next comment |
Disruption | No |
Unfrozen/prioritized changes | The issue fixes a bug in 8.x new code |
Target | Given above, should be good for 8.0..x |
TaxonomyTestTrait has two methods that are directly related to generating entities. They are inconsistent from the perspective of "I want to create an entity, potentially with some values".
function createVocabulary() {
function createTerm(Vocabulary $vocabulary, $values = []) {
The question came up on #3041317: Allow raw vid to be sorted in views about whether I was breaking BC by adding a $values
to createVocabulary()
. At the moment it is true that someone in a project could extend TaxonomyTestTrait, they could override createVocabulary()
with createVocabulary($some_string);
and thus if I added $values
to the core method I might break their tests.
First, I want to suggest that ENTITYTestTraits should be marked @internal (see below). But if we want to improve re-usability of such traits, and avoid BC issues, we should define some standards right now. So i"m just throwing this out there to see what sticks...
Wait, what? They're just test helpers, and test classes/methods are not in scope for BC... (I'm assuming, but hey we don't actually *test* them.)
So maybe these traits should be marked as @internal
? Since they are explicitly only for testing - only for re-usability of code in testing - should they be excluded from the API? Let's say I subclassed a core test and started using it's methods, does that mean the core tests need to maintain their own internal method interfaces?
Fix references to the deprecated Entity class. It was renamed to EntityBase.
During the search for references I've found some more inconsistencies, which I hope could be fixed together.
Return type of \Drupal\Core\Entity\EntityChangedTrait::getChangedTime
is annotated as integer.
However, content entities (ie. obtained via Node::load($id)
) have value of "changed" as string.
$node = Node::load(1);
$time = $node->getChangedTime();
assert(is_int($time));
Cast string value to int (but only if it is set, to allow nullable changed field?).
Possibly adjust type hint for getChangedTime() and setChangedTime() to int|null
?
Note there is a generally broader issue behind this problem, as all implementations of getChangedTime
and getCreatedTime
are affected.
The former is limited to 1 line of code, thanks to EntityChangedTrait
.
The latter would require either a new EntityCreatedTrait or several changes (Media, Node, User, File, ...)
Figure out how to address nullable changed fields (e.g. user and comment).
None.
Previously the getChangedTime() method returned a string when retrieving values from the database, but now returns an integer.
None.
None.
The use of HTML5 "required" attribute in D8 has resulted in an accessibility regression. Basic client-side validation now occurs *before* hitting the server and running FAPI validation functions, so the browser jumps in and provides an error as you attempt to submit the form.
In Drupal 7, the FAPI error messages include a) an icon + alt tag to indicate their relative importance (e.g. warning/notice), b) an error message which included the name of the field for reference, c) a red outline on the field.
But in D8, those enhanced error messages are never displayed, in favor of the default browser response to a required field, which in Chrome's case is "Please fill out this field," without any mention of which field is referred to.
The accessibility team's goal for form validation is #1493324: Inline form errors for accessibility and UX. HTML5 best practices are:
Implementing Javascript validation before the HTML5 validation would restore accessibility for most users. A proposed patch changing the error message to "SomeFormField is required" would improve accessibility for those without Javascript.
#1696648: [META] Untie content entity validation from form validation
#742344: Allow forms to set custom validation error messages on required fields
#1845546: Implement validation for the TypedData API
I was very surprised to see that in D8 that we've lost some accessibility in the current release as far as how error messages are presented.
They were much better in D7. In D8 they just say "Please fill out this field.", where in D7 there was a red box describing the problem at the top of the page. The error also had an image and text which identified what exactly the problem was.
Ultimately we need this in core #742344: Allow forms to set custom validation error messages on required fields
But the defaults for D8 should be at least as good as they were in D7.
When creating a view with a relationship to an entity reference field (to join the referred-to entity in the query), duplicates will be produced if the entity reference field is multi-valued (i.e. cardinality > 1). Users assume that checking the box at Advanced -> Query settings -> Distinct will solve this problem, but it doesn't.
This is because from a database perspective, the records actually aren't duplicates. Each different entity reference in the multi-valued field will produce a different row as the target IDs are different, even though this isn't necessarily reflected in the view itself if not all fields are included. Said another way, the view results may look the same on the front-end, even though they're not on the back-end.
It should be noted that this affects all entity types, whether it be taxonomy terms, nodes, paragraphs, custom entities, etc. There are several duplicates of this issue in various other queues that should be marked as such, with all efforts directed here.
If the Distinct box is checked in the view configuration, after the query has executed, remove results whose entity IDs are already in the list.
If you have a content type with a multivalue taxonomy term field and add a relationship based on that field in a view (in my case I want to use the term name as an argument) the resulting views result has duplicates if one or more of the nodes has multiple terms in that field.
The DISTINCT keyword does not help, since the tid is added as a field in the SELECT part of the query.
I have the following query:
SELECT DISTINCT node_field_data.sticky AS node_field_data_sticky, node_field_data.created AS node_field_data_created, node_field_data.nid AS nid, taxonomy_term_field_data_node_field_data.tid AS taxonomy_term_field_data_node_field_data_tid
FROM
{node_field_data} node_field_data
LEFT JOIN {taxonomy_index} taxonomy_index ON node_field_data.nid = taxonomy_index.nid
LEFT JOIN {taxonomy_term_field_data} taxonomy_term_field_data_node_field_data ON taxonomy_index.tid = taxonomy_term_field_data_node_field_data.tid
WHERE (node_field_data.promote = '1') AND (node_field_data.status = '1')
ORDER BY node_field_data_sticky DESC, node_field_data_created DESC
.. which produces duplicates, even though the DISTINCT keyword is present, because the taxonomy_term_field_data_node_field_data.tid makes the duplicate nodes in the results 'distinct'.
Ideally the query should just exclude the field from the SELECT part like this:
SELECT DISTINCT node_field_data.sticky AS node_field_data_sticky, node_field_data.created AS node_field_data_created, node_field_data.nid AS nid
FROM
{node_field_data} node_field_data
LEFT JOIN {taxonomy_index} taxonomy_index ON node_field_data.nid = taxonomy_index.nid
LEFT JOIN {taxonomy_term_field_data} taxonomy_term_field_data_node_field_data ON taxonomy_index.tid = taxonomy_term_field_data_node_field_data.tid
WHERE (node_field_data.promote = '1') AND (node_field_data.status = '1')
ORDER BY node_field_data_sticky DESC, node_field_data_created DESC
which works an nodes with multiple terms in the field are now only appearing once.
I have couldn't find a way to actually omit the field in the SELECT part of the query, and I'm also not sure, if it could create other issues if removed. But the tid in the select the DISTINCT keyword is useless..
Steps to reproduce.
1. add multivalue taxonomy term field to node type, and add a node with multiple terms selected
2. add a view which uses that field to add a relationship to the term (needed to use the term name as argument)
3. make the view results DISTINCT
4. optionally add the argument (contextual filter) that uses the relationship to filter the views result on the term name.
5. if no argument is given, the node with multiple terms in the field will appear multiple times
I was working on #2834889: Replace documentation and string references to drupal_render() and searched for drupal_render
in code. That resulted in one instance, common_test_drupal_render_printing_pre_render
. Further research and found that use of that function was removed in #2378883: Convert existing drupal_render() KernelTestBase tests to PHPUnit tests. That makes it dead code and can be removed. Unless, I am wrong, I don't know the render system.
I searched for duplicates and didn't find one.
git grep drupal_render
Remove common_test_drupal_render_printing_pre_render.
Confirm my findings
Patch
Review
Commit
N/A
N/A
N/A
N/A
@xjm, from #2486177-132: Deleting an entity translation from the UI deletes the whole entity:
I'm in the process of reviewing this and I must admit the sorta-crazy around
EntityDeleteFormTrait
is snarling my brain. I read over #1728804: Introduce (Content)EntityDeleteForm and children to handle entity deletions for some background on why things are the way they are, but I'm still unclear on why, for example,ContentEntityConfirmFormBase
is a thing (it seems only used for deletions), and why we don't just do away withEntityDeleteFormTrait
at this point (when we're overriding it so much) and just put the respective versions of the methods inContentEntityDeleteForm
andEntityDeleteForm
(which are the only usages). (For others' reference,ContentEntityDeleteForm
does not extendEntityDeleteForm
; andEntityDeleteForm
has only config-specific stuff, which also confused me quite a bit.) Is there a reason to keep the trait other than for BC? Because then we could do away with the trait overriding cleverness.
Fold ContentEntityConfirmFormBase
into EntityConfirmFormBase
and move all the methods from EntityDeleteFormTrait
to EntityDeleteForm
.
Nope.
Drupal\Core\Entity\ContentEntityConfirmFormBase
and Drupal\Core\Entity\EntityDeleteFormTrait
will be removed.
Issue category | Task because we're just removing duplicated code. |
---|---|
Issue priority | Not critical because the current duplicated code works, but the class hierarchy is very hard to understand. |
Prioritized changes | Followup to a critical (#2486177: Deleting an entity translation from the UI deletes the whole entity). |
Disruption | Small disruption for contributed and custom modules because it will require an internal refactoring to not use ContentEntityConfirmFormBase anymore. |
I get an PHP error in my error_log with the CommentManager::getCountNewComments() function, on user activity view /user/activity/uid and recent content view /activity.
This error come up on a Drupal 8.2.0 version that is actualy in use in production with many modules installed (Nginx server) :
2016/10/24 11:47:37 [error] 15222#15222: *281253 FastCGI sent in stderr: "PHP message: TypeError: Argument 1 passed to Drupal\comment\CommentManager::getCountNewComments() must implement interface Drupal\Core\Entity\EntityInterface, null given, called in /var/www/html/drupal/core/modules/comment/src/Controller/CommentController.php on line 330 in /var/www/html/drupal/core/modules/comment/src/CommentManager.php on line 190 #0 /var/www/html/drupal/core/modules/comment/src/Controller/CommentController.php(330): Drupal\comment\CommentManager->getCountNewComments(NULL)
#1 [internal function]: Drupal\comment\Controller\CommentController->renderNewCommentsNodeLinks(Object(Symfony\Component\HttpFoundation\Request))
#2 /var/www/html/drupal/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)
#3 /var/www/html/drupal/core/lib/Drupal/Core/Render/Renderer.php(574): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#4 /var/www/html/drupal/core/lib/Dr" while reading response header from upstream, client: 55.137.231.152, server: website.fr, request: "POST /comments/render_new_comments_node_links HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "website.fr", referrer: "http://website.fr/activity"
So trying to reproduce this on a fresh new basic installation and get similar error on a Drupal 8.2.1 version (apache server) :
Recoverable fatal error: Argument 1 passed to Drupal\\comment\\CommentManager::getCountNewComments() must implement interface Drupal\\Core\\Entity\\EntityInterface, null given, called in /var/www/html/drupal/core/modules/comment/src/Controller/CommentController.php on line 330 and defined in /var/www/html/drupal/core/modules/comment/src/CommentManager.php on line 190 #0 /var/www/html/drupal/core/includes/bootstrap.inc(548): _drupal_error_handler_real(4096, 'Argument 1 pass...', '/var/www/html/d...', 190, Array)
#1 /var/www/html/drupal/core/modules/comment/src/CommentManager.php(190): _drupal_error_handler(4096, 'Argument 1 pass...', '/var/www/html/d...', 190, Array)
#2 /var/www/html/drupal/core/modules/comment/src/Controller/CommentController.php(330): Drupal\\comment\\CommentManager->getCountNewComments(NULL)#3 [internal function]: Drupal\\comment\\Controller\\CommentController->renderNewCommentsNodeLinks(Object(Symfony\\Component\\HttpFoundation\\Request))#4 /var/www/html/drupal/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)
#5 /var/www/html/drupal/core/lib/Drupal/Core/Render/Renderer.php(574): Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->Drupal\\Core\\EventSubscriber\\{closure}()
#6 /var/www/html/drupal/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\\Core\\Render\\Renderer->executeInRenderContext(Object(Drupal\\Core\\Render\\RenderContext), Object(Closure))
#7 /var/www/html/drupal/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)
#8 [internal function]: Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->Drupal\\Core\\EventSubscriber\\{closure}()
#9 /var/www/html/drupal/vendor/symfony/http-kernel/HttpKernel.php(139): call_user_func_array(Object(Closure), Array)
#10 /var/www/html/drupal/vendor/symfony/http-kernel/HttpKernel.php(62): Symfony\\Component\\HttpKernel\\HttpKernel->handleRaw(Object(Symfony\\Component\\HttpFoundation\\Request), 1)
#11 /var/www/html/d8_sandbox/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\\Component\\HttpKernel\\HttpKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)
#12 /var/www/html/drupal/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\\Core\\StackMiddleware\\Session->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)
#13 /var/www/html/drupal/core/modules/page_cache/src/StackMiddleware/PageCache.php(99): Drupal\\Core\\StackMiddleware\\KernelPreHandle->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)
#14 /var/www/html/drupal/core/modules/page_cache/src/StackMiddleware/PageCache.php(78): Drupal\\page_cache\\StackMiddleware\\PageCache->pass(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)
#15 /var/www/html/drupal/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\\page_cache\\StackMiddleware\\PageCache->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)
#16 /var/www/html/drupal/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(50): Drupal\\Core\\StackMiddleware\\ReverseProxyMiddleware->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)
#17 /var/www/html/drupal/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\\Core\\StackMiddleware\\NegotiationMiddleware->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)
#18 /var/www/html/drupal/core/lib/Drupal/Core/DrupalKernel.php(652): Stack\\StackedHttpKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)
#19 /var/www/html/drupal/index.php(19): Drupal\\Core\\DrupalKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request))
#20 {main}, referer: http://devdruplocal:8004/activity/1
In #3052002: [meta] Replace JQuery with vanilla Javascript in core we want to move away from jQuery in favour of vanilla JS.
We decided we'd like to scope a small issue and see what it looks like.
This is said issue.
Please do not take this as a signal to create N Remove jQuery from {foo}.module issues. We want to see whether this is a reasonable approach before we have a proliferation of such issues.
Use vanilla JS instead of jQuery in path module
While playing with a view, i may have clicked multiple times on the remove button for a "representative node" fields. The view modification page was not working anymore and i reloaded the page.
At reload, the page showed multiple error, and i can not edit the view anymore.
First warning:
Warning : Undefined array key "tid_representative" dans Drupal\views\Plugin\views\HandlerBase->getEntityType() (ligne 709 de web/core/modules/views/src/Plugin/views/HandlerBase.php).
Second warning:
Warning : Trying to access array offset on value of type null dans Drupal\views\Plugin\views\HandlerBase->getEntityType() (ligne 710 de /app/web/core/modules/views/src/Plugin/views/HandlerBase.php).
Error:
InvalidArgumentException: A valid cache entry key is required. Use getAll() to get all table data. in Drupal\views\ViewsData->get() (line 140 of core/modules/views/src/ViewsData.php).
1. In a view, add a "Taxonomy term: Representative node" relationship (like described by View Taxonomy Term and hide empty terms.
2. In the same view, add filters on the representative node content.
3. Remove the representative node relationship without removing the filters.
In HandlerBase.php, rewrite the getEntityType() method like this:
/** * {@inheritdoc} */ public function getEntityType() { // If the user has configured a relationship on the handler take that into // account. if (!empty($this->options['relationship']) && $this->options['relationship'] != 'none') { $relationships = $this->displayHandler->getOption('relationships'); if(isset($relationships[$this->options['relationship']])) { $relationship = $relationships[$this->options['relationship']]; $table_data = $this->getViewsData()->get($relationship['table']); $views_data = $this->getViewsData()->get($table_data[$relationship['field']]['relationship']['base']); } else { $views_data = $this->getViewsData()->get($this->view->storage->get('base_table')); } } else { $views_data = $this->getViewsData()->get($this->view->storage->get('base_table')); } if (isset($views_data['table']['entity type'])) { return $views_data['table']['entity type']; } else { throw new \Exception("No entity type for field {$this->options['id']} on view {$this->view->storage->id()}"); } }
Make a better rewrite of getEntityType(), to have only one $views_data failsafe instead of the two introduce by the given solution.
None.
None.
None.
Fix error when editing view with filters from a missing representative node relationship.
Issue summary updated as of comment #17
Image field formatter URL of image needs option Absolute URL.
Usage:
- Display full image URL on page.
- Image field URL in Views data export (XML, CSV).
Add Image field to content.
Alter field options to enable Use absolute URL.
quietone | Hi |
lendude | Morning |
smustgrave | Hello |
darvanen | @Bevan W I've heard you talking about using postgreSQL a fair bit... have you come across this or do you have any insight? (3081144) |
Bevan W | I haven't experienced either of those particular issues that I recall.. |
Bevan W | looks awful.... Is good to know for the current project.. I've been adding a few logs in the project he last few sprints.. and using postgres. |
Bevan W | we could potentially run into the issue. |
larowlan | taking a stab at this |
larowlan | @quietone worked on this recently, I wonder if you can provide an update on what is remaining |
quietone | I'll look in a minute |
quietone | chx raised a point that needs to be resolved, in #63 and #77. |
quietone | catch has tested the patch on a 'decent sized' db in #74 with satisfactory results. |
larowlan | and we need update path tests |
quietone | And chx made a followup patch and that just needs tests to. |
quietone | I though I wrote update tests.... Maybe it was only on the other y2038 issue. |
larowlan | ah I'm getting confused with that one too |
lendude | As always: https://www.drupal.org/project/drupal/issues/1349080 which in now postponed on https://www.drupal.org/project/drupal/issues/3277602 which got zero traction :disappointed: |
darvanen | I like that we're doing it, I'm finding it pretty difficult to be useful (partly because split attention) |
acbramley | I missed something I guess... what's new? |
larowlen | Focus on hard problems instead every second meeting |
smustgrave | I like it. These harder ones tend to stick around so knocking a few seems good |
quietone |
Priority (goal): actual Critical (50): 59 Major (1000): 910 Normal (6000): 4685 Minor (300): 340 Total: 5994 |
quietone | Added the total because it is < 6000! |
quetone |
Today: 2022-12-06
From: 2022-11-22 to 2022-12-06 All bugs Status Count Approximately 285 yr reduction in total number of years of all open bugs. Only bugs tagged Bug Smash Initiative Status Count Approximately 185 yr reduction in total number of years of all open bugs. |
quietone | Not as big a reduction as previous when a lot of PMNMI were able to be closed. |
darvanen | Still a downward trajectory though! |