Commit graph

69 commits

Author SHA1 Message Date
Jon Robson a80d2b1f56 Add additional debugging closest bug
Use the topic "error.web-team" - error prefix necessary
for it to be treated as an error, and 'web-team' moves
it off main channel.

Error logs tagName and nodeType which should be sufficient
for us to understand this issue. Can expand with other
information later if need be. Cannot add to stack trace
as any non-standard stack trace would be dropped by the intake
code.

Bug: T340081
Change-Id: Ia011aaf9f8b5b932695da3311f849682c0105cfe
2023-07-17 14:54:12 -07:00
bwang 6b659443b5 Update popups to use codex buttons over mediawiki.ui.buttons
- Provides missing accessible label for the settings button

Bug: T340256
Change-Id: I86972322ae34f1d1df8d79c66daa9e34091f9dd3
2023-07-10 16:03:36 -05:00
Moh'd Khier Abualruz 67a718a5be TypeError: n.closest is not a function
- check if the element has the function in it before using it
- implementing a native code to get the same result based on polyfill examples
- fix Coverage Block

Bug: T340081
Change-Id: I1c2ce46a88cde6323ab862964062dd722ff5edcb
2023-07-10 11:48:40 -07:00
Jon Robson 049729626c IP masked users use localStorage for settings
Bug: T330517
Change-Id: Ib283e37f379e8cccc7f49ab0ce9aadd6535ea668
2023-06-14 08:16:50 -07:00
Jon Robson 7c592bc790 Prefer native JavaScript to jQuery
Bug: T315929
Change-Id: I949fd9551269a3cb9d9df7744149510949d3076c
2023-05-21 16:53:50 +00:00
Jon Robson 428c32d027 Switch to native Promises and fetch
For fetch and AbortController we provide native polyfills (see
resources/src/skip-web2017-polyfills.js) so safe to use this here.
This will be empty for modern browsers.

Change-Id: Ic0f55eb0a0276be3587a4b866834bddff1124ad2
2023-05-12 21:34:42 +00:00
WMDE-Fisch cb7fd4e4f8 Update entrypoint- and bundle-size limits
These numbers haven't been updated for some time now due to the many
recent changes in the code. Since we're wrapping things up I guess
it makes sense to have them accurate again.

Change-Id: I73c202a65192e8011acefd664bea7b62b1b556da
2021-05-10 10:00:39 +02:00
Thiemo Kreuz 275a67c730 Make checkboxes use upstream mediawiki.ui.… styles
This does not fully solve the ticket, as these are not the
actual OOUI styles. But it's already much better than the
unstyled checkboxes before.

Bug: T281227
Change-Id: I9a5023482774c09aa73845ca6dfd1c4926f088e1
2021-04-28 10:37:07 +02:00
Thiemo Kreuz d0872e3025 Clean up popup type settings related code
* Change more places to not hard-code the popup types, but use
  loops and such.
* Change many `function ()` headers to use the more streamlined
  ES6 sytnax.

Bug: T277639
Bug: T277640
Change-Id: Ifece87d51012e0e069286453b27f5c9ae273710e
2021-04-23 15:38:38 +02:00
Svantje Lilienthal 09c2c52945 Added popup types handling
We added reference preview as a checkbox the the
anonymous user settings. To handle both popup types
(pages and references), we changed the usage of
preview.enabled. We pass on all types as a map
inside preview.enabled. The footer link to edit the
settings will appear for anonymous users if at least
one type is disabled.

Bug: T277639
Change-Id: I860a1b35ac7749d8d0884575f6acb7186ad8e4d0
2021-04-23 12:14:23 +02:00
Thiemo Kreuz c281bb9302 Clean up code enabling individual popup types
We still have 2 different mechanisms in place, maybe even 3:
* We simplify the CSS selector when we know a popup type is
  disabled, and it's impossible an anonymous user can enable it
  at run-time.
* We create that "initiallyEnabled" map that allows anonymous
  users to toggle the individual popup types at run-time.
* This map is also used to check if the footer link should be
  shown.
* There is also a wgPopupsReferencePreviews global that acts as
  a "kill switch". However, this is not a pure feature flag,
  but incorporates the user setting for registered users. This
  is currently partly redundant (checking
  `mw.user.options.get( 'popupsreferencepreviews' )` does the
  same) and can be removed later when the feature flag is not
  needed any more.

The footer link currently acts odd because anonymous users are
unable to enable ReferencePreviews, but get the footer link.

This patch introduces a 3-state model:
* `true` acts as before.
* `false` means a popup type is disabled, but anonymous users
  can enable it (i.e. this is the opt-out behavior for anonymous
  users).
* `null` means a popup type is not available at run-time, for
  nobody. Anonymous users can't do anything about this.
  Registered users must leave the page and change a setting.

Bug: T277640
Change-Id: Id8d1396c09cf0f706034a66f9cd3c880a8b33df8
2021-04-21 19:38:25 +02:00
WMDE-Fisch 190962cc5b Remove dead code around cog wheel dialogue
An "advanced" option was first introduced in 2014 via patch I374805e
(originally named "monitor-or-edit", renamed via patch I7b4f6d2).

The isNavPopupsEnabled() function was added in 2016 via patch
Ic660f48.

The code that disables the extension entirely the moment the NavPopups
gadget is enabled was added in 2017 via patch Ia474b1b (T151058) and
patch Ia837816 (T160081).

As of now, the "advanced" option can only be seen in an extreme edge
case:
* Only for anonymous users.
* Only if NavPopups is enabled by default for anonymous users.
* Only if the $wgPopupsConflictingNavPopupsGadgetName setting is
  misconfigured.
* … or if NavPopups is not a gadget in the first place, but e.g.
  loaded via Common.js.

In this situation the settings dialog opens with all *3* options. This
is broken for several reasons:
* The "simple" option enables the extension, but doesn't disable
  NavPopups. Both trigger, resulting in both popups being displayed
  the same time.
* Since "simple" is the default, this bogus behavior is the default
  for anonymous users.
* The "off" option doesn't stick. Every time the settings dialog opens
  "advanced" is checked instead.
* "Off" can't work anyway. There is no code to disable the gadget.
* Only the "advanced" option "works", but more by accident.

It's unclear how to fix this:
* There is no code that does anything with the "advanced" option. It's
  not even stored. The behavior of the option is identical to "off".
* The code appears as if "advanced" was meant to be shown instead of
  "off". I.e. anonymous users can only choose one of the popups, but
  not disable both. But there is no code to hide the "off" option.
* The bug when both popups are displayed was fixed in 2017 via an
  entirely different mechanism. Re-introducing "advanced" does not
  only mean duplication, it's unclear how the 2 mechanisms are meant
  to work together.

It really, really feels like this was just forgotten.

Bug: T278949
Change-Id: Iab21f3a649a5b2f19ebb0d0dbb45ce1450c65678
2021-04-15 15:29:16 +02:00
Andrew Kostka 398565b1d6 Track anonymous enables/disables of reference previews
Bug: T277641
Change-Id: I89ee3ff280e79f560bf613a110a1c9e0b3ba6648
2021-04-15 14:21:32 +02:00
Thiemo Kreuz 622fb6c5e8 Allow to disable/enable popup types individually
Bug: T277639
Change-Id: I0742b8ab1c5ed0b374d4f9447bebc46a35207339
2021-04-15 11:30:36 +02:00
Thiemo Kreuz a35e35e3b3 Expand userSettings module for reference previews
Bug: T277639
Change-Id: I13acfb8bcc6e95fc28969072ec5420fd075d5096
2021-04-13 12:19:49 +02:00
Thiemo Kreuz ddf574afa3 Remove not needed userSettings.hasIsEnabled()
Note how getIsEnabled() is documented: "if the user hasn't
previously enabled or disabled Page Previews […] then they
are treated as if they have enabled them."

In other words: The idea that the default should be true is
encoded twice in this code. This is just not necessary. We can
remove one without loosing anything.

Motivtion: Simplifying the code and reducing the package size.

Since the code fundamentally depends on this default value
anyway, we can clear the users localStorage when they decide
to go back to the default – instead of storing a "1" which
does the same as the default.

Change-Id: I2814a1e9269979918609162a508eeee6944d9e52
2021-04-08 11:57:52 +02:00
Thiemo Kreuz c5accc0300 Rename many functions and files for clarity
The main motivation here is to dramatically reduce the number
of places that use the same property name "enabled" for values
on different objects (e.g. "state", "actions", and "updates"
are all different things) with slightly different meanings. I
tried hard to come up with names that reflect better what each
meaning is.

Bug: T277639
Change-Id: Ie766259793f716262e3d4622ca55156d11f4842c
2021-04-08 11:04:02 +02:00
Clare Ming 4908f82c01 Add title attribute to settings gear icon
Add message, description, extension for title. Update createPagePreview, renderPagePreview methods to add title attribute to settings gear icon. Add test for title attribute. Increase maxSize, maxAssetSize, maxEntrypointSize. Add compiled js files.

Bug: T274887
Change-Id: Ibb29deb3418569d8283b954b4b22074423e78bda
2021-04-02 13:30:07 -06:00
WMDE-Fisch 58f820009e Use flags to represent settings
To reduce size of code added to the <head> and increase performance.
The increased bundlesize is still less than the size spared bytes in
ResourceLoaderGetConfigVars. - But nevertheless the main gain is loading
less in the <head> anyways.

To avoid further complexity in the code, the bitmask is converted to
the according config setting early on instead of adding checks on the
bitmask all over the place.

Tests will be added in follow ups.

Bug: T276716
Change-Id: Ib4f82bed58295b25f0a41cb37e36244e45f16317
2021-03-11 13:38:06 +01:00
Noam Rosenthal 7b0937c5a8 Use CSS clip-path instead of SVG when supported.
This reduces a lot of churn in creating the SVG
element and related helpers.

When IE11 is dropped, the SVG code-path can also be dropped.

Bug: T269336
Change-Id: I7f91192dedc2a78f1c7c84179cff1687593177c0
2021-01-05 19:26:24 +00:00
Bartosz Dziewoński c8b8ba7f5f Revert "Remove title attributes at init"
This reverts commit 6bc2077ed5.

The change causes issues with various popular gadgets on Wikimedia
wikis. The 'title' attributes have been the easiest way to determine
the target pages of links, and many gadgets have come to rely on that.

Bug: T269297
Bug: T269873
Change-Id: I49d315a13c327a1c5af51d3de887c0c17642e9fe
2020-12-11 16:53:17 +00:00
Noam Rosenthal 497eb631d1 Parse template HTML only once, as HTML parsing is expensive
When creating a popup, clone the previously created DOM element
and populate the attributes and content.

Ideally this would be done with a template element, but since IE11
is still supported this is not possible.

Change-Id: I347615cf1f613d97d767d60627b13b6b3ff9c762
Bug: T269338
2020-12-07 23:01:26 +00:00
Svantje Lilienthal 0b6c859a2b hide reference previews when reference tooltip gadget is active
Change-Id: I5f43270bfeba944c05dc09adf771ed07057237c7
2020-11-16 18:36:04 +01:00
Thiemo Kreuz c6ea149d34 Wrap long words in reference preview popups
Bug: T266859
Change-Id: I874d60246a0337577c0f411d0d24f237c1ceebf2
2020-10-30 20:14:39 +01:00
Adam Wight 877c2f3e12 Clicking on a reference should behave normally
We no longer intercept reference clicks, now clicking on a reference
label will scroll to the reference definition in the same way as when
reference previews is disabled.

Metrics about clicking on the label are collected by the Cite
extension, are are unaffected by this change.

Bug: T265482
Change-Id: I2929a86b6a09f3b72e5e2f4151cb13f52446897d
2020-10-30 10:57:41 +01:00
Thiemo Kreuz f4d696e6bf Add (i) info icon to collapsible replacement message
This avoids pulling in the entirety of OOjs, with the disadvantage
that we have to copy a little bit of CSS. I copied parts of this
patch from I2a28666.

There might be a better way to do this, with less code. E.g. is
there a better way to construct these HTML elements?

Bug: T220208
Change-Id: I024155f3ff0f57de1d68bbaf37bfb9e81e692bd0
2020-10-30 10:53:30 +01:00
Thiemo Kreuz 1cf721e2a2 Handle collapsible & sortable elements in reference popups
Elements that are marked as collapsible (often tables, but can
actually be anything) are most certainly marked as such because
they are big and don't fit in a popup.

Another plugin makes tables sortable.

In both cases non-functional UI elements appear in the popup.
We decided:
* Hide collapsible elements (no matter if currently collapsed
  or not), and show a placeholder text instead.
* Remove sortable arrows.

This is a baseline patch that solves everything, except the
(i) icon is missing. This will be added in the next patch.

Bug: T220208
Change-Id: I58f3036bf4988d0ebe5716b0a54506446fca10c3
2020-10-28 17:23:12 +01:00
Ed Sanders 536470c01d build: Update eslint-config-wikimedia to 0.16.2
Change-Id: Icb65074fe64993314bbb28f690ce3ce0f89fb57c
2020-06-26 17:05:56 +01:00
Ed Sanders 85fc18d38d eslint: Cleanup linting of /dist
* Move eslintrc.es5.json to /dist to avoid extra Grunt config
* Upgrade clean-webpack-plugin and exclude dist/.eslintrc.js
  from cleaning
* Set root:true and just enable wikimedia/language/not-es5 instead
  of disabling dozens of rules
* Remove getOwnPropertySymbols rule as webpack uses this.

Change-Id: I802138a8a591dd4c3cb0cc637112e383570286df
2020-04-27 20:45:42 +01:00
Thiemo Kreuz a63a1cf91c Split user preferences for Page and Reference previews
Bug: T233813
Change-Id: I89205658c561961b90abaa133a004e54beebfab5
2019-10-17 11:21:21 +02:00
Thiemo Kreuz 95c80dcb3e Fix code detecting horizontal scrollbar in reference previews
Bug: T234602
Change-Id: I5994b6e8cb15374bb2c0a31dd4e4549005a619cf
2019-10-09 15:38:35 +02:00
Adam Wight 76a34618c3 Tracking for Reference Previews interactions
Logs events to the ReferencePreviewsPopups EventLogging schema, in
order to understand whether Reference Previews is helpful for
end-users.

This will be removed along with the older tracking, as soon as our analysis
phase is finished.

Incidentally disables a lint rule for the generated JS, it's about
readability so irrelevant to the minified code.

Bug: T214493
Change-Id: I2638611ba67b785338f7e98a1c4b08a5e829812d
2019-10-07 11:22:00 +02:00
WMDE-Fisch 1879a4d59e Show referencePreviews on click
Introducing the REFERENCE_CLICK action that will fetch and show the
preview for the clicked reference right away without any delay.

The main goal of the new chain of events introduced with the reference
click is showing the reference preview right away. The actions triggered
by the dwelling include delays in multiple parts of the process.

If there's a dwell action-chain in progress when the click action is
executed, the related promise ( that might still include steps with
delays ) and the reference preview is retrieved and shown right away
re-using the token. 

In the case where there's no dwell action running ( e.g. when the click
was triggered via touch ) we create a new token and start from scratch.

In either case we want to avoid, that multiple clicks trigger multiple
actions and abort early when there's already a click action in progress.

Bug: T218765
Change-Id: I073a93be2d17a21178aebe12267765f60a2811b9
2019-04-29 17:46:49 +00:00
WMDE-Fisch 35aa05afee Use title and namespace id to check if link is current page
Bug: T220097
Change-Id: Ieffd6a02b4126f6713610e968d662516499d4998
2019-04-23 15:17:06 +02:00
Andrew Kostka 522829c43a Add a fade out to reference content
This will only be applied when the height of the content exceeds four
lines of text.

Bug: T217139
Change-Id: If15952c9886c23827873812bb63e8e3127776709
2019-03-25 13:30:52 +01:00
WMDE-Fisch 4803a717ad Change delay for ReferencePreviews to 150ms
Bug: T215420
Change-Id: Id1fa7dad59d8fe80bc60c1e2d7c3fb4087e52d1f
2019-03-11 16:37:53 -06:00
Stephen Niedzielski b3dd38c8aa Build: synchronize Webpack config with MobileFrontend
Minimize the difference between MobileFrontend and Popup's
configuration where possible. No build delta was generated so the change
is expected to be nonfunctional.

- Set the Webpack configuration file's ESLint environment to Node.js
  instead of manually specifying Node.js globals.

- Directly export the configuration as a function instead of persisting
  a local and assigning it to module.exports at the end.

- Export the configuration as a function and replace Node.js variables
  with Shell compatible parameters. This required inlining a couple
  single-use variables. See
  I83e507fad1ee2f477bb95c2987d0b24f082b2165.

- Reorder configuration and update comments to match MobileFrontend.

Change-Id: I24545da2d029d08b0ea0e1330b6bb71ce423e6b7
2019-03-07 13:37:59 -07:00
Thiemo Kreuz 6d29d08de3 Unify /* global … */ annotations for ESLint
These are annotations for ESLint as described at:
https://eslint.org/docs/user-guide/configuring#specifying-globals

I'm not sure where the `…: false` comes from. I assume it is a mistake
and does not have an effect.

I tried to move these annotations closer to the line they are about in
case there is only one line. And move it to the top when there is more
than one line using the global.

Change-Id: I4bd112c5fddd8a97d829a9b91707b8eb7cd7a332
2019-02-20 14:29:24 -07:00
Stephen Niedzielski dcbbefe2fc Hygiene: report when Webpack builds complete
Output a timestamp whenever a Webpack build completes. This is useful
for verifying development builds generated by the `npm start` watcher
are up-to-date.

If you merge this patch, merge the corresponding patch to the
MobileFrontend Webpack config.

Change-Id: Ifeb96506475bacc2b97a24d218a28daa55dea137
2019-01-17 17:21:23 +00:00
Stephen Niedzielski c8c93d0859 Hygiene: replace deprecated Webpack plugin
Replace NamedModulesPlugin with `optimisations.namedModules = true`. Not
to be confused with `optimization.namedModules` which is deprecated.

https://github.com/webpack/webpack/releases/tag/v4.0.0
https://github.com/webpack/webpack/releases/tag/v4.16.0

Bug: T212527
Change-Id: Ie5c7b74e294b012f270de8a6ebc660bf5e75d478
2019-01-07 19:00:01 +00:00
Stephen Niedzielski a922331d36 Hygiene: remove unused Webpack plugins
Remove the LoaderOptionsPlugin and DefinePlugin from the Webpack
configuration. These plugins *do not* alter production or development
build products or appear to impact Redux interaction.

Bug: T212527
Change-Id: I4ca2bde2346011167f86f7f4a331048a2e92263b
2019-01-03 20:02:45 +00:00
Stephen Niedzielski 81a2f4acb0 Hygiene: copy MobileFrontend Webpack learnings
Copy learnings from MobileFrontend's Webpack configuration. If nothing
else, the files are more consistent and easier to diff. When the change
to rename source maps is excluded, the build products are identical.

The following changes were copied:

- DRY up the output directory and source map extension as variables. For
  the latter, rename the source map from ".json" to ".map.json". Without
  renaming, the build products are unchanged.
- Reduce verbosity. Only report warnings and errors.
- Fail to build when an error occurs.
- Update ordering and add comments for easier reasoning and diffing with
  MobileFrontend.

Bug: T212527
Change-Id: Icf11dff91358ad021932aa209c65ed8aac77d12b
2019-01-02 21:30:12 +00:00
Shreyas Minocha 22226f3367
Switch from babel-preset-env to @babel/preset-env
Replace:
    - babel-preset-env@1.6.0 with @babel/preset-env@7.2.0
    - babel-register@6.24.1 with @babel/register@7.0.0
    - babel-loader@7.1.4 with babel-loader@8.0.4

Add:
    - @babel/core@7.2.0

---

- babel-preset-env, @babel/preset-env
  babel-preset-env moved to @babel/preset-env in the Babel monorepo.
  This appears to have incremented the version from v1.6.0[0] to 7.x to
  match the rest of the Babel packages but appears to otherwise be
  undocumented.[1,3]

  [0] https://github.com/babel/babel-preset-env/blob/24b99ec/README.md
  [1] https://github.com/babel/babel/blob/efa571a/CHANGELOG.md

- @babel/preset-env, @babel/register
  *Many* changes as identified by package [2] and summarized [3].

  Node.js v6 or above now required.

  New dependency on @babel/core.

  Support for ES2018 and browserslist v4.

  `modules: false` is now the default for preset-env + babel-loader. The
  .babelrc has been updated.

  New babel-upgrade tool.

  babel.config.js can replace .babelrc. Popups doesn't seem to need it.

  TypeScript and JSX fragment support.

  [2] https://github.com/babel/babel/blob/efa571a/CHANGELOG.md
  [3] https://babeljs.io/blog/2018/08/27/7.0.0

- babel-loader
  Support for Babel 7.x.

  The following warning is printed when building but perhaps this is due
  to another dependency:

    (node:14559) DeprecationWarning: loaderUtils.parseQuery() received a
    non-string value which can be problematic, see
    https://github.com/webpack/loader-utils/issues/56 parseQuery() will
    be replaced with getOptions() in the next major version of
    loader-utils.

  https://github.com/webpack/loader-utils/issues/56#issuecomment-286117000
  https://github.com/babel/babel-loader/releases/tag/v7.1.5
  https://github.com/babel/babel-loader/releases/tag/v8.0.0-beta.0
  https://github.com/babel/babel-loader/releases/tag/v8.0.0-beta.1
  https://github.com/babel/babel-loader/releases/tag/v8.0.0-beta.2
  https://github.com/babel/babel-loader/releases/tag/v8.0.0-beta.3
  https://github.com/babel/babel-loader/releases/tag/v8.0.0-beta.4
  (v8.0.0-beta.5 was erroneous.)
  https://github.com/babel/babel-loader/releases/tag/v8.0.0-beta.6
  https://github.com/babel/babel-loader/releases/tag/v8.0.0
  https://github.com/babel/babel-loader/releases/tag/v8.0.1
  https://github.com/babel/babel-loader/releases/tag/v8.0.2
  https://github.com/babel/babel-loader/releases/tag/v8.0.3
  https://github.com/babel/babel-loader/releases/tag/v8.0.4

Bug: T197883
Change-Id: Ie3a5404630fde87ea7fe618a842950ed8c0c6494
2018-12-11 13:09:45 +05:30
Stephen Niedzielski fe2c3b23ee Hygiene: replace call to rm with clean-webpack-plugin
The invocation of `rm -rf resources/dist` in package.json
(`check-built-assets`) is replaced with clean-webpack-plugin.
The benefit of this change is that calling `npm run build` now works the
same as the `check-built-assets` script.

Bug: T193522
Change-Id: I64f048855ddceb7159279671b2174a7937e169ff
2018-06-18 09:09:28 -05:00
Stephen Niedzielski 367b12a278 Hygiene: bump ESLint to ES6 and lint more files
- Bump the ESLint configuration ECMAScript 2015 given that we use Babel
  and have a safeguard to verify build products are ES5.

- Lint more files including all tests and the Webpack and Grunt configs.

Change-Id: I099cbe009eda2349ddc051976ace0d9f6c55fa30
2018-05-01 14:47:51 -05:00
jdlrobson bb2ad2ed38 Up the max asset and entry point sizes
40kb seems a good time to pause and reflect on the total size.
The current maximum is impossible to meet without no further
changes to the code.

12kb is also more flexible than 11.5

Change-Id: I5ee8c236d90542afacc0e8de513a45a15ccd529b
2018-03-27 12:57:17 -07:00
Stephen Niedzielski c4b50b04ac Hygiene: remove unused resources
In I7395e3438836149becdd576942bdaf6f21b4163f the settings templates
were rewritten so that they no longer displayed an image.

descriptionText and images were dropped from the template but not from
the template provider. These are artifacts from relating to that patch
and are no longer used.

Change-Id: I1be7ef288d37f338e83dab3cf041e628a06608d2
2018-03-21 17:07:18 -05:00
Stephen Niedzielski 0bee0906d4 Hygiene: replace var with let and const
eslint \
    --cache \
    --max-warnings 0 \
    --report-unused-disable-directives \
    --fix \
    src tests

Change-Id: I051275126ae7fa9affd16c2504017c0584f2d9c7
2018-03-20 14:14:02 -05:00
Stephen Niedzielski 42816702eb Hygiene: replace Mustache templates w/ ES6 strings
Replace Mustache.js templates with template literals. An effort was made
to minimize additional refactoring, so feel free to ask for more but it
ain't coming in this PS.

Bug: T165036
Change-Id: I4a6a1d93a2922c3a9ef3ae93c47da17a35c644f0
2018-03-20 08:06:02 -05:00
Stephen Niedzielski e5df865d51 Hygiene: enable Babel transpilation
Enable the Babel transpiler so that ES6 template literals,
destructuring, and arrow functions can be used in production.
"last n versions" syntax was not used so that builds are more
reproducible.

Bug: T165036
Change-Id: I553b6d14cc368c7b4366f68d13038c3d505f5429
2018-03-20 07:59:14 -05:00