Commit graph

186 commits

Author SHA1 Message Date
Ammar Abdulhamid
71571191d4 Chain MutableRevisionRecord method calls 2
Change-Id: I86578cfbc892f171a4e433283b86d1b78fe4167d
2020-11-27 05:26:54 +01:00
C. Scott Ananian
c64e71615e Replace $wgDisable{Lang,Title}Conversion with LanguageConverterFactory methods
Replace direct access to $wgDisableLangConversion with
LanguageConverterFactory::isConversionDisabled(), and replace direct
access to $wgDisableTitleConversion with
LanguageConverterFactory::isTitleConversionDisabled().  However, most
places that check ::isTitleConversionDisabled() actually want
::isLinkConversionDisabled(), so add that too (and deprecate
isTitleConversionDisabled()).

Code search:
https://codesearch.wmcloud.org/search/?q=Disable%28Lang|Title%29Conversion&i=nope&files=&repos=

This change removes a number of spurious dependencies on the global
configuration and reduces code duplication (for example, if the logic
for disabling language conversion were ever to change).

Depends-On: I6fa8230ae97b0e34c381003548e61f9b7387d363
Change-Id: Icc4687638ff1815003dd903854efdbd904854f1e
2020-11-25 12:47:26 -05:00
daniel
67d0986211 Introduce ParserOutputAccess
Encapsulate logic for getting rendered page content, for any revision,
with caching and pooling hidden away.

Introducing such a service object will also give us a leverage point for
supporting output transformations. Output transformations are currently
implemented partially in ParserOutput, partially in Parser, and partially
duplicated in Parsoid.

Bug: T267234
Change-Id: I566d7a7936633823ba68b5aecbc8c2d88949b4f8
2020-11-10 15:12:12 +01:00
Thiemo Kreuz
1fc8d79ac6 Remove documentation that literally repeats the code
For example, documenting the method getUser() with "get the User
object" does not add any information that's not already there.
But I have to read the text first to understand that it doesn't
document anything that's not already obvious from the code.

Some of this is from a time when we had a PHPCS sniff that was
complaining when a line like `@param User $user` doesn't end
with some descriptive text. Some users started adding text like
`@param User $user The User` back then. Let's please remove
this.

Change-Id: I0ea8d051bc732466c73940de9259f87ffb86ce7a
2020-10-27 19:20:26 +00:00
C. Scott Ananian
2febd08683 Remove 'tidy' from ParserOptions
Removed the deprecated getter; hard-deprecate the setter.

Remove 'tidy' from ParserOptions::$options in
ParserOptions::getDefaults(), and patch up ParserOptions::matches() to
ignore the 'tidy' option in any existing ParserCache entries.

Bug: T198214
Depends-On: Id03b1b679a9985952dee42c54648603706e9279c
Depends-On: I269e829cf1f33e233bfcf7f95388e041180c2556
Depends-On: I6a5378a42a6cf035296ad549525c25438803970a
Depends-On: I7b84a41c564828792709ce3ff919ac3eeb747bc0
Change-Id: I5c696c6f1efdceef36334c9766cf5606fbe3ba12
2020-08-13 03:44:34 +00:00
Tim Starling
d459add63d Introduce wfDeprecatedMsg()
Deprecating something means to say something nasty about it, or to draw
its character into question. For example, "this function is lazy and good
for nothing". Deprecatory remarks by a developer are generally taken as a
warning that violence will soon be done against the function in question.
Other developers are thus warned to avoid associating with the deprecated
function.

However, since wfDeprecated() was introduced, it has become obvious that
the targets of deprecation are not limited to functions. Developers can
deprecate literally anything: a parameter, a return value, a file
format, Mondays, the concept of being, etc. wfDeprecated() requires
every deprecatory statement to begin with "use of", leading to some
awkward sentences. For example, one might say: "Use of your mouth to
cough without it being covered by your arm is deprecated since 2020."

So, introduce wfDeprecatedMsg(), which allows deprecation messages to be
specified in plain text, with the caller description being optionally
appended. Migrate incorrect or gramatically awkward uses of wfDeprecated()
to wfDeprecatedMsg().

Change-Id: Ib3dd2fe37677d98425d0f3692db5c9e988943ae8
2020-06-22 14:34:39 +10:00
DannyS712
44945be0a5 Hard deprecate calling ParserOptions::newCanonical with no parameters
Falls back to $wgUser
No remaining deployed uses in MW 1.35+

Bug: T246861
Change-Id: If4304de546457fe0a96a6ac8d705a70c480c6fae
2020-06-15 23:11:45 +00:00
jenkins-bot
006ec1b507 Merge "Deprecate external image related configuration in ParserOptions" 2020-06-15 14:10:19 +00:00
Umherirrender
fb184336f6 Call StubObject::unstub directly
No need to check with isRealObject before

Change-Id: Ia060de98e51a7f11ee4a7d2ffa06f3175fddaddf
2020-06-15 09:04:13 +00:00
C. Scott Ananian
ee8759a281 Deprecate external image related configuration in ParserOptions
Per-parser configuration is discouraged; use sitewide configuration instead.

Code search:
https://codesearch.wmflabs.org/search/?q=setEnableImageWhitelist%7CsetAllowExternalImages%7CsetAllowExternalImagesFrom&i=nope&files=&repos=

The ultimate goal here is to refactor the image filtering functionality into
an extension and move it out of core, so that it can be used by both
Parsoid and the legacy parser in the same way.  We may add back per-parser
customization of the filtering, but the API will probably look different.
Deprecate the existing ParserOptions-based mechanism, which code search
indicates almost no one is using.

Bug: T254802
Change-Id: Ib4a59bbae10cfc924c0290948330d93e02de9ed0
2020-06-10 13:05:34 -04:00
DannyS712
a6d16bd03d Remove unneeded creation of revision objects
Clean up some technical debt; use MutableRevisionRecord instead of
manually constructing a Revision from an array, remove last uses of
RevisionStoreDbTestBase::revisionToRow and remove the method.

Each file can be reviewed separately (except that the removal of
revisionToRow depends on replacing its usage)

Bug: T246284
Change-Id: I0bdc069b21a5c41ef8f9e972c5b17ff189d4a741
2020-06-10 09:09:55 +00:00
DannyS712
381d873a8b Replace core uses and hard deprecate Parser(Options) Revision methods
Bug: T249384
Change-Id: Iff10e76120eb8b6b4fbb939182dede83c86d3da2
2020-06-03 05:55:35 +00:00
Tim Starling
68c433bd23 Hooks::run() call site migration
Migrate all callers of Hooks::run() to use the new
HookContainer/HookRunner system.

General principles:
* Use DI if it is already used. We're not changing the way state is
  managed in this patch.
* HookContainer is always injected, not HookRunner. HookContainer
  is a service, it's a more generic interface, it is the only
  thing that provides isRegistered() which is needed in some cases,
  and a HookRunner can be efficiently constructed from it
  (confirmed by benchmark). Because HookContainer is needed
  for object construction, it is also needed by all factories.
* "Ask your friendly local base class". Big hierarchies like
  SpecialPage and ApiBase have getHookContainer() and getHookRunner()
  methods in the base class, and classes that extend that base class
  are not expected to know or care where the base class gets its
  HookContainer from.
* ProtectedHookAccessorTrait provides protected getHookContainer() and
  getHookRunner() methods, getting them from the global service
  container. The point of this is to ease migration to DI by ensuring
  that call sites ask their local friendly base class rather than
  getting a HookRunner from the service container directly.
* Private $this->hookRunner. In some smaller classes where accessor
  methods did not seem warranted, there is a private HookRunner property
  which is accessed directly. Very rarely (two cases), there is a
  protected property, for consistency with code that conventionally
  assumes protected=private, but in cases where the class might actually
  be overridden, a protected accessor is preferred over a protected
  property.
* The last resort: Hooks::runner(). Mostly for static, file-scope and
  global code. In a few cases it was used for objects with broken
  construction schemes, out of horror or laziness.

Constructors with new required arguments:
* AuthManager
* BadFileLookup
* BlockManager
* ClassicInterwikiLookup
* ContentHandlerFactory
* ContentSecurityPolicy
* DefaultOptionsManager
* DerivedPageDataUpdater
* FullSearchResultWidget
* HtmlCacheUpdater
* LanguageFactory
* LanguageNameUtils
* LinkRenderer
* LinkRendererFactory
* LocalisationCache
* MagicWordFactory
* MessageCache
* NamespaceInfo
* PageEditStash
* PageHandlerFactory
* PageUpdater
* ParserFactory
* PermissionManager
* RevisionStore
* RevisionStoreFactory
* SearchEngineConfig
* SearchEngineFactory
* SearchFormWidget
* SearchNearMatcher
* SessionBackend
* SpecialPageFactory
* UserNameUtils
* UserOptionsManager
* WatchedItemQueryService
* WatchedItemStore

Constructors with new optional arguments:
* DefaultPreferencesFactory
* Language
* LinkHolderArray
* MovePage
* Parser
* ParserCache
* PasswordReset
* Router

setHookContainer() now required after construction:
* AuthenticationProvider
* ResourceLoaderModule
* SearchEngine

Change-Id: Id442b0dbe43aba84bd5cf801d86dedc768b082c7
2020-05-30 14:23:28 +00:00
Reedy
78e36ba527 Fix some Squiz.Scope.MethodScope.Missing
Change-Id: Id0351e44482885ee90e047c1ae3a439e484104c6
2020-05-16 22:42:24 +01:00
Reedy
b038d6333a Fix even more PSR12.Properties.ConstantVisibility.NotFound
Change-Id: I6d98efcfac1f1c0ab6a442e0af6d5daa6ef7801a
2020-05-16 00:28:41 +00:00
C. Scott Ananian
aeb2f33cc7 Deprecate a few more tidy-related methods
Hard-deprecate ParserOptions::getTidy(), since it always returns true
and is rarely used.  Code search:
https://codesearch.wmflabs.org/search/?q=getTidy%5C%28&i=nope&files=&repos=

Soft deprecate most methods of MWTidy; folks should use MWTidy::tidy()
as the entry point here.  Code search:
https://codesearch.wmflabs.org/search/?q=MWTidy&i=nope&files=&repos=

Bug: T198214
Change-Id: I3584181070da7ed4888beaaf04e083114aca1eab
2020-05-01 21:08:54 +00:00
C. Scott Ananian
85e1525862 Deprecate ParserOptions::getTidy() and ParserOptions::setTidy()
These options no longer have any effect.

Bug: T198214
Change-Id: Icc3eaed7ab8a3070c4339b272d580328ba40912d
2020-04-19 22:53:39 -07:00
DannyS712
84ef6d8315 Add RevisionRecord alternatives to Parser and ParserOptions methods
The following Parser methods were deprecated in favor of new methods:
- ::fetchCurrentRevisionOfTitle (use fetchCurrentRevisionRecordOfTitle)
- ::statelessFetchRevision (use statelessFetchRevisionRecord)
- ::getRevisionObject (use getRevisionRecordObject)

The following ParserOptions methods were likewise deprecated:
- ::getCurrentRevisionCallback (use getCurrentRevisionRecordCallback)
- ::setCurrentRevisionCallback (use setCurrentRevisionRecordCallback)

To ensure backwards compatibility with calling the ParserOptions
CurrentRevisionCallback methods, while allowing extensions to call
the CurrentRevisionRecordCallback methods without worrying about if
other extensions also deployed have been updated, both
::getCurrentRevisionCallback and ::getCurrentRevisionRecordCallback,
if the respective option is still set to the default, check if the
other option is set and, if it is, convert the other option rather
than returning thed default.

It's not pretty, but it works, and will be hard deprecated shortly
and removed in 1.36.

Bug: T249384
Change-Id: I66cbcb963a96cc49c75ca72faa7e439ae6d6614d
2020-04-17 16:29:09 +00:00
C. Scott Ananian
8c18f2b41c Add a wfDeprecated to an overlooked code path where parser output is not tidy
We formally deprecated running the parser with tidy disabled in 1.33, but
I missed a hard-deprecation on this code path.

Be careful not to spam the logs with deprecation warnings triggered by
(deprecated) API requests, though.

Change-Id: I10f64e76ec0c5aee8b26fc00bc11ebb0e39f961b
2020-04-02 11:53:53 -04:00
Peter Ovchyn
61e0908fa2 languages: Introduce LanguageConverterFactory
Done:
* Replace LanguageConverter::newConverter by LanguageConverterFactory::getLanguageConverter
* Remove LanguageConverter::newConverter from all subclasses
* Add LanguageConverterFactory integration tests which covers all languages by their code.
* Caching of LanguageConverters in factory
* Make all tests running (hope that's would be enough)
* Uncomment  the deprecated functions.
* Rename FakeConverter to TrivialLanguageConverter
* Create ILanguageConverter to have shared ancestor
* Make the LanguageConverter class abstract.
* Create table with mapping between lang code and converter instead of using name convention
* ILanguageConverter @internal
* Clean up code

Change-Id: I0e4d77de0f44e18c19956a1ffd69d30e63cf51bf
Bug: T226833, T243332
2020-02-03 11:38:03 +02:00
C. Scott Ananian
e149a38d4f Remove $wgMaxGeneratedPPNodeCount
This no longer has any effect.  The getter and setter in ParserOptions
aren't used in any public git code, and so have been removed without
deprecation.

Bug: T204945
Followup-To: I727f003f9a42d0c92bcbcce8a8289d5af6cd1298
Change-Id: Id48effcba48d1ae1621a4e17a70e65b73f2473b7
2020-01-28 16:54:53 -05:00
C. Scott Ananian
5cbb64f56a Remove Preprocessor_DOM, deprecated in 1.34
Remove the deprecated Preprocessor_DOM class, which was hard-deprecated
in 1.34.  This begins to simplify parser configuration and reduce redundant
code paths, but I've left two things for cleanup in a future patch:

1. The `preprocessorClass` configuration option to the parser, exposed
in `$wgParserConf`, ServiceWiring, ParserFactory, etc.  There is no reason
for this to be exposed as configurable, but I've left this clean up to a
future patch.

2. The `$wgMaxGeneratedPPNodeCount` configuration, exposed also in
ParserOptions.  Only Preprocessor_DOM calculated this count, and since
we are only using Preprocessor_Hash now, this configuration has no effect.
But since this value was exposed in ParserOptions and elsewhere, I've
deprecated where needed but left this clean up to a future patch.

Bug: T204945
Change-Id: I727f003f9a42d0c92bcbcce8a8289d5af6cd1298
2020-01-25 11:22:45 -05:00
James D. Forrester
0958a0bce4 Coding style: Auto-fix MediaWiki.Usage.IsNull.IsNull
Change-Id: I90cfe8366c0245c9c67e598d17800684897a4e27
2020-01-10 14:17:13 -08:00
Aryeh Gregor
0de9c47b50 Remove Language::factory and getParentLanguage use
Change-Id: I11f8801ef47ec1a1f63d840116e69667e6f3ae3c
2019-10-27 12:34:28 +02:00
Tim Starling
ae116da889 Code cleanup related to initSpeculativePageId()
Change-Id: I5b97c6292a28df6633c573a05c89210b096db5a8
2019-07-26 16:41:00 +10:00
Aaron Schulz
5099ee9f72 parser: add speculative page IDs to use with {{PAGEID}}
This works similarly to speculative rev IDs with {{REVISIONID}}.
Re-parses can be avoided if the page ID is correctly guessed.

Also make the {{PAGEID:X}} parser function set vary-page-id.

Bug: T226785
Change-Id: I0b19be45e6ddd6cde330bfcd09d243e4e5beda01
2019-07-26 16:41:00 +10:00
jenkins-bot
20e65a1915 Merge "parser: inject the time for {{REVISIONTIMESTAMP}} on pre-save parse" 2019-06-23 22:13:48 +00:00
C. Scott Ananian
2a806d0429 Remove OutputPage::enableSectionEditLinks(), ParserOptions::get/setEditSection()
These methods were deprecated in 1.31, and most of the related code
was removed in b4e557f8f8 but these three
methods appear to have been overlooked.

Change-Id: Iea6c8b1b628a7b6acf9b65497966af9fc4ab662e
2019-06-19 15:14:54 -04:00
Aaron Schulz
e85fe191c9 parser: inject the time for {{REVISIONTIMESTAMP}} on pre-save parse
DerivedPageDataUpdater::prepareContent already locks in the revision
timestamp before insertion, so inject that into the parser options
used for any pre-save parse (e.g for edit filters).

This means that a reparse is no longer needed within in the same save
request to get the post-save canonical output. A parse will still be
required if the edit filter output used an edit stash output, since
the revision timestamp is not set at stash time.

Instead of using vary-revision, add a vary-revision-timestamp flag
for the revision timestamp words. The month/day/hour variants retain
their prior optimizations for allowing edit stash output reuse for
the post-save canonical output.

Change-Id: Ic2c13db4d21197c79a89de0de56745ca32918eb6
2019-06-09 13:12:57 +01:00
Aaron Schulz
fdbb64f354 Avoid extra parse/save delay for users with non-canonical parser options
If {{REVISIONID}} results in a re-parse, that re-parse will be post-send
unless the user has canonical parser options and will need the output for
page views anyway (e.g. the refresh after editing).

Also make getPreparedEdit() allow lazy-loading of the parser output via
a callback. A magic __get() method handles objects created the new way
but accessed by other code the old way.

Bug: T216306
Change-Id: I2012437c45dd605a6c0868dea47cf43dc67061d8
2019-04-14 02:00:16 +00:00
Aaron Schulz
ba7645032a Remove deprecated ParserOutput::legacyOptions
Change-Id: I5f32dd741f3ee795ec599aacb687d5cee2c52835
2019-03-11 22:50:47 -07:00
Thiemo Kreuz
c3dfa88966 Add missing empty lines between methods
This might hint at an edge-case in the PHP CodeSniffer sniff that should
detect if methods are separated by a single empty line. Feel free to
investigate. I, personally, can't invest more time in this than
suggesting this quick fix.

Change-Id: Ib3c60eac76f255b4fe929f7933de256222716576
2019-01-15 19:14:35 +00:00
Alangi Derick
19adaa6a4b parser: Fix PHPDoc annotations in parser module
Change-Id: I09680d72516f943051e86655b5fddf9ff2988e4e
2018-12-08 13:07:10 +00:00
Jakub Vrana
3fc3b9e578 Change typehint callback to callable
Found by PHPStan.

Change-Id: I77877a18131bd69996bad07f2ee1c5f3ba3ba2e7
2018-12-01 10:02:48 +01:00
C. Scott Ananian
58abac2d14 Change ParserOptions tidy default to true
We are deprecating the non-tidy modes of the parser.

ParserOptions::getCanonicalOverrides() has always set `tidy` to `true` at
any rate, so this isn't going to invalidate any parser cache entries.

Change-Id: Ib703a041edf8a8d57e94f136965f72d9bbfcf222
2018-10-29 19:37:00 +00:00
daniel
e9f71517f7 [MCR] Introduce RevisionRenderer
RevisionRenderer is the MCR replacement for Content::getParserOutput,
as outlined in <https://www.mediawiki.org/wiki/User:Daniel_Kinzler_(WMDE)/MCR-PageUpdater>.

Note: This change also introduces quite a bit of code for
merging ParserOutput objects.

Bug: T194048
Change-Id: I871978bf79f67c9e7954fb3fc8528d6e365f2cc1
2018-08-30 19:15:12 +02:00
Aryeh Gregor
90d4f56fe4 Mass conversion of $wgContLang to service
Brought to you by vim macros.

Bug: T200246
Change-Id: I79e919f4553e3bd3eb714073fed7a43051b4fb2a
2018-08-11 22:44:29 -06:00
Reedy
a075271157 Update composer/spdx-licenses to 1.4.0 and mediawiki/mediawiki-codesniffer to 21.0.0
https://github.com/composer/spdx-licenses/compare/1.3.0...1.4.0

Change-Id: I39f7a1310455159866bfed5224536e800befec0d
2018-07-26 17:44:28 +00:00
Brad Jorsch
c6810d74d1 Deprecate ContentHandler::makeParserOptions()
Having a different ParserOptions for each content model isn't feasible
in an MCR world. And the only thing using this was Wikibase, which has
been fixed to do what it needs in a different way.

Bug: T194263
Change-Id: I01373b29ee25fa9346c6b0317155be4ccdc8c515
2018-07-13 14:32:59 -04:00
Umherirrender
130ec2523d Fix PhanTypeMismatchDeclaredParam
Auto fix MediaWiki.Commenting.FunctionComment.DefaultNullTypeParam sniff

Change-Id: I865323fd0295aabd06f3e3c75e0e5043fb31069e
2018-07-07 00:34:30 +00:00
Kunal Mehta
c4e5a9dd97 Avoid deprecated LinkCache::singleton()
Change-Id: Ie0e5c4ef0fe6ec896378bb2433af0898655dd907
2018-06-10 23:55:11 -07:00
Brad Jorsch
c3900e06be Resolve used lazy options in ParserOptions::optionsHash()
If a lazy option is passed to ParserOptions::optionsHash(), we should
resolve the option so the hash can incorporate the proper value instead
of omitting it.

Also, completely unrelatedly, refactor the hook overriding in the unit
test because people won't stop whining about it in code review.

Change-Id: I2df78ed90875c229090b503b65f20fbbbba7f237
2018-05-15 06:54:55 +00:00
Thiemo Kreuz
e6b6920cff Fix PHPDoc type hints in CacheTime, ParserOptions, and related
I'm intentionally not touching any code in this patch, only
documentation.

Change-Id: I6975194c218760031789d5335dfbb330017dc6fc
2018-04-18 15:10:31 +00:00
Umherirrender
63d96c15fd build: Updating mediawiki/mediawiki-codesniffer to 16.0.0
Change-Id: I59b59f79bbf3ce4feff3b3a20c1c31bc16370531
2018-02-17 13:29:13 +01:00
Brad Jorsch
2791fb0861 Hard-deprecate ParserOutput stateful transform methods
This also removes all the in-core calls that had been kept for the
benefit of extensions, and causes them to not have any effect since
anything that had been calling them was already either a no-op or will
probably be broken now that nothing in core is setting or checking the
flags.

Change-Id: Id22c1a5a6d6a249debb14063ae3f8838d105b634
2018-02-13 12:28:36 -05:00
Brad Jorsch
8b0e7298ac
Remove wrapclass from parser cache key
This will result in an exception from WikiPage::getParserOutput() if
anything was missed.

This also hard-deprecates ParserOptions::setWrapOutputClass( false )

Bug: T181846
Change-Id: Ica541e1f6b52f5eec6d28cff60ba64bf525258c7
Depends-On: Ie5d6c5ce34c05b8fe2353d3bb36b2a3a4166ec4b
Depends-On: Ibfaefde2f3811151ec712554cbc9cf2415ed017f
Depends-On: I55048bbae5d4d2d0c79c241c1784448b82db3bb4
Depends-On: I23a26ba0dfbe83007cd40e97d71a2139a5ecddc7
Depends-On: Ibc013a41f4a463f4014fbbce7ce27f8690161728
Depends-On: Ie936dff918dc0869503a924298b4580402038b52
2018-02-01 14:26:03 -08:00
Brad Jorsch
d511626236
Add 'unwrap' ParserOutput post-cache transform
And deprecate passing false for ParserOptions::setWrapOutputClass().

There are three cases for the Parser wrapper: the default
mw-parser-output, a custom wrapper, or no wrapper. As things currently
stand, we have to fragment the parser cache on each of these options,
which uses a nontrival amount of storage space (T167784).

Ideally we'd do all the wrapping as a post-cache transform, but
TemplateStyles needs to know the wrapper in use in order to properly
prefix its CSS rules (that's why we added the wrapper in the first
place). So, second best option is to make *un*wrapping be a post-cache
transform and make "custom wrapper" be uncacheable.

This patch does the first bit (unwrapping as a post-cache transform),
and a followup will do the second part once the deprecation process is
satisfied.

Bug: T181846
Change-Id: Iba16e78c41be992467101e7d83e9c3134765b101
2018-02-01 14:24:27 -08:00
Umherirrender
3124a990a2 Use ::class to resolve class names in includes files
This helps to find renamed or misspelled classes earlier.
Phan will check the class names

Change-Id: I07a925c2a9404b0865e8a8703864ded9d14aa769
2018-01-27 20:34:29 +01:00
Brad Jorsch
92cf49df5c ParserOutput: Add stateless transforms to getText()
The stateful transforms are deprecated.

Inspired by Krinkle's If2fb32fc.

Bug: T171797
Change-Id: Ied5fe1a6159c2d4fa48170042b44d735ce7b6f9b
2017-11-30 14:27:46 -05:00
Umherirrender
5f158c7d65 Remove @codingStandardsIgnore after upstream fix
Issue #1604 was fixed -
https://github.com/squizlabs/PHP_CodeSniffer/issues/1604

Change-Id: Id81cb820e42123007ae8696422bebf588e274437
2017-10-22 16:25:00 +02:00