# [VOTE] Expectations

- Thread: https://externals.io/message/83160
- Original archive: https://news-web.php.net/php.internals/83160
- Started by Joe Watkins on 2015-02-19T09:09:08+00:00
- Messages: 44
- Page 1 of 2: messages 1 to 25 (25 per page, add `?page=N` to the URL)
- Next page: https://externals.io/message/83160.md?page=2
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #83160 — Joe Watkins — 2015-02-19T09:09:08+00:00

URL: https://externals.io/message/83160#83160

Morning internals,

    The expectations RFC is now in voting phase:
https://wiki.php.net/rfc/expectations#vote

Cheers
Joe

---

## #83193 — Markus Fischer — 2015-02-19T14:47:25+00:00

URL: https://externals.io/message/83160#83193 · In reply to: #83160

Hi,


> Morning internals,
> 
>     The expectations RFC is now in voting phase:
> https://wiki.php.net/rfc/expectations#vote

- I somehow miss information what the exact differences are to the
current implementation, to better judge the impact.

- how does zend.assertions and assert.exceptions work with
"assert_options()" , i.e. isn't the exception behavior meant to be an
addition to `assert_options()` too ?

- the RFC says: "enabled (zend.assertions=1) on development machines,
and disabled (zend.assertions=0) in production"; a few paragraphs above
it says "-1 - don't generate any code (zero-cost, production mode)".
Shouldn't be -1 the default value for production then?

- the RFC says: "A call to `assert()`, without a fully qualified namespace
will call assert in the current namespace, if the function exists. An
unqualified call to assert is subject to the same optimization
configured by zend.assertions. ". Does this mean I can control whether a
function in a namespace is being optimized-away with when zend.assertion
equals -1 and otherwise do my own stuff in there and need to raise an
AssertException on my own to signal assertion fails?

thank you,
- Markus

---

## #83195 — Pierre Joye — 2015-02-19T15:00:21+00:00

URL: https://externals.io/message/83160#83195 · In reply to: #83160

> Morning internals,
>
>     The expectations RFC is now in voting phase:
> https://wiki.php.net/rfc/expectations#vote

I totally miss the Expectation RFC announcement. Where the RFC was
actually proposed for discussions.

I have been following up the DbC thread, seeing some mentions but
that's it. The RFC itself popped up 3 days ago.

Also the RFC itself only point to various discussions, there is no
summary, details, docs, examples, etc in the RFC.

I am sorry but as much I like (for what I think it does) as I like the
concept, this RFC does not have, by far, the quality I would expect
for a RFC being voted on.

Cheers,
-- 
Pierre

@pierrejoye | http://www.libgd.org

---

## #83201 — Dmitry Stogov — 2015-02-19T15:16:25+00:00

URL: https://externals.io/message/83160#83201 · In reply to: #83195

> On Thu, Feb 19, 2015 at 1:09 AM, Joe Watkins <pthreads@pthreads.org>
> wrote:
> > […]
>
> I totally miss the Expectation RFC announcement. Where the RFC was
> actually proposed for discussions.
>
> I have been following up the DbC thread, seeing some mentions but
> that's it. The RFC itself popped up 3 days ago.
>

It's from 2013 and it was discussed actively during last week.

Thanks. Dmitry.


>
> Also the RFC itself only point to various discussions, there is no
> summary, details, docs, examples, etc in the RFC.
>
> I am sorry but as much I like (for what I think it does) as I like the
> concept, this RFC does not have, by far, the quality I would expect
> for a RFC being voted on.
>
> Cheers,
> --
> Pierre
>
> @pierrejoye | http://www.libgd.org

---

## #83204 — Dmitry Stogov — 2015-02-19T15:23:53+00:00

URL: https://externals.io/message/83160#83204 · In reply to: #83193

> Hi,
>
> 
> > […]
>
> - I somehow miss information what the exact differences are to the
> current implementation, to better judge the impact.
>

The implementation introduces ZEND_ASSERT_CHECK instruction that will jump
around calls to `assert()` depending on zend.assertions ini option. (call and
constraint evaluation may be expensive).

It's also possible to avoid compilation of `asset()` at all (setting
zend.assertions=-1)

This will allow using `assert()` for program testing, without performance
degradation in production.


>
> - how does zend.assertions and assert.exceptions work with
> "assert_options()" , i.e. isn't the exception behavior meant to be an
> addition to `assert_options()` too ?
>

zend.assertions control `assert()` compilation and execution

zend.assertions=-1 zero-cost, `assert()` won't be compiled at all (including
inner code)
zend.assertions=0  low-cost, `assert()` will be compiled but won't be
executes (including inner code)
zend.assertions=1  `assert()` wiil be compiled and executed as now


> - the RFC says: "enabled (zend.assertions=1) on development machines,
> and disabled (zend.assertions=0) in production"; a few paragraphs above
> it says "-1 - don't generate any code (zero-cost, production mode)".
> Shouldn't be -1 the default value for production then?
>

With zend.assertions=0 in production, you'll able to switch to
zend.assertions=0 at any time.
With zend.assertions=-1 of course not.


> - the RFC says: "A call to `assert()`, without a fully qualified namespace
> will call assert in the current namespace, if the function exists. An
> unqualified call to assert is subject to the same optimization
> configured by zend.assertions. ". Does this mean I can control whether a
> function in a namespace is being optimized-away with when zend.assertion
> equals -1 and otherwise do my own stuff in there and need to raise an
> AssertException on my own to signal assertion fails?
>

Yes. you are able to eliminate your own `assert()` functions in namespaces.

Thanks. Dmitry.


>
> thank you,
> - Markus

---

## #83211 — Pierre Joye — 2015-02-19T15:45:58+00:00

URL: https://externals.io/message/83160#83211 · In reply to: #83201

>
>
> 
> > […]
>
>
> It's from 2013

Yes, but....

> and it was discussed actively during last week.

Still, no announce for a discussion about this specific RFC. And
really, the content of the RFC is almost empty, pointing to the ML
archive is really not the right way :)

---

## #83216 — Pierre Joye — 2015-02-19T16:06:24+00:00

URL: https://externals.io/message/83160#83216 · In reply to: #83211

> 
> > […]
>
> Yes, but....
>
> > […]
>
> Still, no announce for a discussion about this specific RFC. And
> really, the content of the RFC is almost empty, pointing to the ML
> archive is really not the right way :)

So, back to more useful feedback.

I like the concept and idea but still not sure about the custom
exception vs AssertException.

My gut feeling tells me that it could be better to solve that prior
this vote, which actually asks to choose something we did not define
yet. It could be in the same RFC (and making it more complete while
being at it).

-- 
Pierre

@pierrejoye | http://www.libgd.org

---

## #83226 — Leigh — 2015-02-19T17:13:04+00:00

URL: https://externals.io/message/83160#83226 · In reply to: #83216

> Still, no announce for a discussion about this specific RFC. And
> really, the content of the RFC is almost empty, pointing to the ML
> archive is really not the right way :)

There was an RFC announce thread 3 days ago. I agree 3 days is a short
period of time, but the announce thread existed. Maybe it was a reply
to DbC with a changed subject and your mail client didn't show it as
new? I don't know, there was definitely a thread though.


> I like the concept and idea but still not sure about the custom
> exception vs AssertException.

Looking at the implementation, it seems that the custom exception
still has to descend from AssertException

https://github.com/php/php-src/pull/1088/files#diff-232f2dffbb06c0b6004724d8a498e7e7R248

That seems like a good restriction to me. You can still catch
everything with AssertException but you can make it more specific if
you want.

---

## #83229 — Pierre Joye — 2015-02-19T17:34:57+00:00

URL: https://externals.io/message/83160#83229 · In reply to: #83226

> 
> > […]
>
> There was an RFC announce thread 3 days ago. I agree 3 days is a short
> period of time, but the announce thread existed. Maybe it was a reply
> to DbC with a changed subject and your mail client didn't show it as
> new? I don't know, there was definitely a thread though.

I mentioned that thread in my comment. It is still way behind what
should be done when creating a new RFC,  let alone pushing it to the
vote phase.

> 
> > […]
>
> Looking at the implementation, it seems that the custom exception
> still has to descend from AssertException
>
> https://github.com/php/php-src/pull/1088/files#diff-232f2dffbb06c0b6004724d8a498e7e7R248
>
> That seems like a good restriction to me. You can still catch
> everything with AssertException but you can make it more specific if
> you want.

I did not comment on what should be done, while I do consider this
open question as a blocker to actually take a good decision for this
RFC. I do think it should be discussed, answered and voted either at
the same time or before this RFC.

-- 
Pierre

@pierrejoye | http://www.libgd.org

---

## #83237 — Joe Watkins — 2015-02-19T20:18:11+00:00

URL: https://externals.io/message/83160#83237 · In reply to: #83229

There isn't legitimate technical justification for or against using custom
exceptions.

Since it's entirely based on preference, and the kind of utilitarian
argument you can make for their use,
it's acceptable that this is resolved as part of the vote.

It's not a huge deal.

Cheers
Joe



> 
> > […]
>
> I mentioned that thread in my comment. It is still way behind what
> should be done when creating a new RFC,  let alone pushing it to the
> vote phase.
>
> > […]
> https://github.com/php/php-src/pull/1088/files#diff-232f2dffbb06c0b6004724d8a498e7e7R248
> > […]
>
> I did not comment on what should be done, while I do consider this
> open question as a blocker to actually take a good decision for this
> RFC. I do think it should be discussed, answered and voted either at
> the same time or before this RFC.
>
> --
> Pierre
>
> @pierrejoye | http://www.libgd.org

---

## #83274 — Xinchen Hui — 2015-02-20T08:28:53+00:00

URL: https://externals.io/message/83160#83274 · In reply to: #83160

Hey:




> Morning internals,
>
>     The expectations RFC is now in voting phase:
> https://wiki.php.net/rfc/expectations#vote

sorry, the thread is too long to read.. I am not sure whether there
was some similar opinion before..

I voted without custom exception, that  is because.

if all assertion exception is AssertException, then we can simply
optimized them away while zend.assert is disabled..

like:

   try  {
          foo();
          bar();
          `assert()`;
    } catch (AssertException $e) {
         //these statements can be optimized away.
    }

 but with custom exception..

    try {

         sqllitefunc();   // no threw
         sqllitefunc1(); //no threw
         assert("", new SqlLiteException());
     } catch (SqlliteException $e) {
          //we are not sure maybe sqllitefunc can throw SqliteException.
         // thus we can not optimized these statements ayway
     }

thanks
>
> Cheers
> Joe



-- 
Xinchen Hui
@Laruence
http://www.laruence.com/

---

## #83275 — Joe Watkins — 2015-02-20T08:38:04+00:00

URL: https://externals.io/message/83160#83275 · In reply to: #83274

The custom exception must derive from AssertionException, so the same
optimization is possible.

Cheers
Joe



> Hey:
>
>
>
> On Thu, Feb 19, 2015 at 5:09 PM, Joe Watkins <pthreads@pthreads.org>
> wrote:
> > […]
>
> sorry, the thread is too long to read.. I am not sure whether there
> was some similar opinion before..
>
> I voted without custom exception, that  is because.
>
> if all assertion exception is AssertException, then we can simply
> optimized them away while zend.assert is disabled..
>
> like:
>
>    try  {
>           foo();
>           bar();
>           `assert()`;
>     } catch (AssertException $e) {
>          //these statements can be optimized away.
>     }
>
>  but with custom exception..
>
>     try {
>
>          sqllitefunc();   // no threw
>          sqllitefunc1(); //no threw
>          assert("", new SqlLiteException());
>      } catch (SqlliteException $e) {
>           //we are not sure maybe sqllitefunc can throw SqliteException.
>          // thus we can not optimized these statements ayway
>      }
>
> thanks
> > […]
>
>
>
> --
> Xinchen Hui
> @Laruence
> http://www.laruence.com/

---

## #83277 — Joe Watkins — 2015-02-20T08:46:50+00:00

URL: https://externals.io/message/83160#83277 · In reply to: #83275

Also, we don't optimize those away, it would not be sensible, because it's
not sensible to deploy those catch blocks in the first place.

Cheers
Joe



> The custom exception must derive from AssertionException, so the same
> optimization is possible.
>
> Cheers
> Joe
>
> 
>
> > […]

---

## #83278 — Markus Fischer — 2015-02-20T08:47:06+00:00

URL: https://externals.io/message/83160#83278 · In reply to: #83204

> > […]
> 
> zend.assertions control `assert()` compilation and execution
> 
> zend.assertions=-1 zero-cost, `assert()` won't be compiled at all (including
> inner code)
> zend.assertions=0  low-cost, `assert()` will be compiled but won't be
> executes (including inner code)
> zend.assertions=1  `assert()` wiil be compiled and executed as now

Pardon me, but it doesn't explain what the role of the existing
"assert_options()" function will or does play?


> > […]
> 
> With zend.assertions=0 in production, you'll able to switch to
> zend.assertions=0 at any time.
> With zend.assertions=-1 of course not.

I don't understand this. "With 'foo' in production, you will be able to
switch to 'foo' at any time. With 'bar' of course not" ?

Maybe I was unclear. What I meant:
- a few paragraphs above it says that "-1 doesn't generate any code
(zero cost)"
- so why isn't THAT '-1' promoted to be the default in production
php.ini instead of '0' setting?


> > […]
> 
> Yes. you are able to eliminate your own `assert()` functions in namespaces.

Wow. The RFC doesn't explain this very well but I wrote this based on
assumption and guesswork.

This sounds two-folded to me: "very cool" (albeit I can't see a use-case
right now) on one hand and "utter magic" on the other.

With utter magic I mean: suddenly a function named 'assert' in a
namespace is eligible to rules before ever only applied to a global
existing function.

I'm not saying it's bad. It's just very magic, sounds cool but could be
a real PITA. Maybe just a documentation problem after all.



As Pierre already mentioned, the RFC really lacks some more details. But
in general, it looks good.

thank you,
- Markus

---

## #83280 — Patrick Schaaf — 2015-02-20T08:51:09+00:00

URL: https://externals.io/message/83160#83280 · In reply to: #83277

Am 20.02.2015 09:47 schrieb "Joe Watkins" <pthreads@pthreads.org>:
>
> Also, we don't optimize those away, it would not be sensible, because it's
> not sensible to deploy those catch blocks in the first place.

So, do they become FATAL with production settings? Ideally a parse error
(ideally, because then my ordinary syntax check run before deployment,
could catch them :) ???

best regards
  Patrick

---

## #83286 — Leigh — 2015-02-20T11:06:23+00:00

URL: https://externals.io/message/83160#83286 · In reply to: #83278

> This sounds two-folded to me: "very cool" (albeit I can't see a use-case
> right now) on one hand and "utter magic" on the other.

Inclined to agree.

@Joe what use-case prompted this feature?

---

## #83289 — Joe Watkins — 2015-02-20T11:27:08+00:00

URL: https://externals.io/message/83160#83289 · In reply to: #83286

I work on a massive codebase, 3m loc, the ability to document that we throw
SomeAssertionException in *insert circumstance* is extremely appealing. It
would allow us to structure the documentation and the code in a way that
really makes sense especially for new developers. The alternatives are not
nice, in my opinion. It's not about runtime, and the ability to catch
specific exceptions by name, at all, there shouldn't be any catch blocks
for AssertionExceptions in deployed code.

Cheers
Joe



> 
> > […]
>
> Inclined to agree.
>
> @Joe what use-case prompted this feature?

---

## #83294 — Crypto Compress — 2015-02-20T13:00:23+00:00

URL: https://externals.io/message/83160#83294 · In reply to: #83289

Am 20.02.2015 um 12:27 schrieb Joe Watkins:
> I work on a massive codebase, 3m loc, the ability to document that we throw
> SomeAssertionException in *insert circumstance* is extremely appealing. It
> would allow us to structure the documentation and the code in a way that
> really makes sense especially for new developers. The alternatives are not
> nice, in my opinion. It's not about runtime, and the ability to catch
> specific exceptions by name, at all,

> there shouldn't be any catch blocks for AssertionExceptions in deployed code

Hello Joe,

can you please explain a bit more how you would achieve this in 3m loc?

Thanks!

---

## #83295 — Crypto Compress — 2015-02-20T13:05:49+00:00

URL: https://externals.io/message/83160#83295 · In reply to: #83294

> The alternatives are not nice, in my opinion.

What are this alternatives? What are the drawbacks of "warning" in 
production code?

---

## #83297 — Joe Watkins — 2015-02-20T13:31:59+00:00

URL: https://externals.io/message/83160#83297 · In reply to: #83295

> can you please explain a bit more how you would achieve this in 3m loc?

AssertionExceptions are not intended to be caught, they are intended to be
seen, in a specific environment.

It doesn't really make sense to commit/deploy code that catches
AssertionExceptions knowing that the code is actually dead in production.

So you just don't deploy catch blocks for AssertionException, you might
write one while debugging locally, but deploying them doesn't make sense.

Cheers
Joe

On Fri, Feb 20, 2015 at 1:05 PM, Crypto Compress <
cryptocompress@googlemail.com> wrote:

>
>  The alternatives are not nice, in my opinion.
> > […]
>
> What are this alternatives? What are the drawbacks of "warning" in
> production code?

---

## #83299 — Crypto Compress — 2015-02-20T14:02:24+00:00

URL: https://externals.io/message/83160#83299 · In reply to: #83297

> AssertionExceptions are not intended to be caught, they are intended 
> to be seen, in a specific environment.

Joe, your argumentation is around how (not) to use exceptions. I can see 
your point and it's valid.
My point is about not to implement exceptions at all.

If exceptions are not intended to be caught, they don't need to be 
thrown (even if the context is different).
If exceptions are not thrown and not caught, we can use "error" in dev 
and some easing severity (warning, zero cost nothing) in prod.

Freely adapted from Murphy: If assertion exception can be catched, it 
will be even in production.

---

## #83301 — Nikita Popov — 2015-02-20T14:09:32+00:00

URL: https://externals.io/message/83160#83301 · In reply to: #83299

On Fri, Feb 20, 2015 at 3:02 PM, Crypto Compress <
cryptocompress@googlemail.com> wrote:

>
>  AssertionExceptions are not intended to be caught, they are intended to
> > […]
>
> Joe, your argumentation is around how (not) to use exceptions. I can see
> your point and it's valid.
> My point is about not to implement exceptions at all.
>
> If exceptions are not intended to be caught, they don't need to be thrown
> (even if the context is different).
> If exceptions are not thrown and not caught, we can use "error" in dev and
> some easing severity (warning, zero cost nothing) in prod.
>
> Freely adapted from Murphy: If assertion exception can be catched, it will
> be even in production.
>

The point behind AssertionException is that
a) It will leave the scope where with the failed assertion immediately. A
warning would continue running the code, even though some precondition is
violated, which doesn't make sense.
b) It can still be gracefully handled (unlike a fatal error). E.g. the unit
testing framework can catch it, so you can continue running all your tests
even if one causes an assertion failure.

When Joe says "not intended to be caught" this is referring to "normal"
code. Catching them at the top-level still makes sense, e.g. for the unit
testing case mentioned or even just to print a nice error message with
extra information. Using an exception instead of a fatal error also means
that things like "finally" will still run, so your code can still release
locks etc even if an assertion failure occurred.

Nikita

---

## #83302 — Pierre Joye — 2015-02-20T14:22:02+00:00

URL: https://externals.io/message/83160#83302 · In reply to: #83195

> 
> > […]
>
> I totally miss the Expectation RFC announcement. Where the RFC was
> actually proposed for discussions.
>
> I have been following up the DbC thread, seeing some mentions but
> that's it. The RFC itself popped up 3 days ago.
>
> Also the RFC itself only point to various discussions, there is no
> summary, details, docs, examples, etc in the RFC.
>
> I am sorry but as much I like (for what I think it does) as I like the
> concept, this RFC does not have, by far, the quality I would expect
> for a RFC being voted on.


Coming back to this point.

I very much like what is presented here. However I think it is pre
mature to vote on as there was (sorry) not explicit discussions about
it.

A couple of things are unclear. See the numerous questions in this thread.

I also do not like other things.

zend.assertions:

I understand we need to be able to disable them. Is production vs
development/debug mode specific to assertion? I do not think so, we
should have a more general setting for that so other areas can be used
for it.
 `INI_SYSTEM` may also reduce the usage of this feature to local
development or dedicated hosts. Any shared hoster (those not allowing
to change php.ini) won't be able to test in similar tests environment.
It is not critical but it is something you may reconsider.

assert.exceptions:

Let solve the exception usages in the engine first and see how to deal
with them more globally, including naming, NS or where and how they
can be used. This is in my eyes a pre requise to this RFC.
 `INI_ALL` is used here. That means that just like error_reporting (which
is actually very painful), calling some random codes may makes my code
(caller) raised exceptions when I do not want to, or the other way
round? I am not too keen on that idea.


Cheers,
-- 
Pierre

@pierrejoye | http://www.libgd.org

---

## #83307 — Crypto Compress — 2015-02-20T14:55:27+00:00

URL: https://externals.io/message/83160#83307 · In reply to: #83301

Am 20.02.2015 um 15:09 schrieb Nikita Popov:
> On Fri, Feb 20, 2015 at 3:02 PM, Crypto Compress 
> <cryptocompress@googlemail.com <mailto:cryptocompress@googlemail.com>> 
> wrote:
>
>
>         AssertionExceptions are not intended to be caught, they are
>         intended to be seen, in a specific environment.
>
>
>     Joe, your argumentation is around how (not) to use exceptions. I
>     can see your point and it's valid.
>     My point is about not to implement exceptions at all.
>
>     If exceptions are not intended to be caught, they don't need to be
>     thrown (even if the context is different).
>     If exceptions are not thrown and not caught, we can use "error" in
>     dev and some easing severity (warning, zero cost nothing) in prod.
>
>     Freely adapted from Murphy: If assertion exception can be catched,
>     it will be even in production.
>
>
> The point behind AssertionException is that
> a) It will leave the scope where with the failed assertion 
> immediately. A warning would continue running the code, even though 
> some precondition is violated, which doesn't make sense.

Assumed context is wrong here.
- exception in development: error
- no exception in production: warning, zero cost nothing

Rephrased: A zero-cost non-existing exception would continue running the 
code, ...

In a previous email you brought up the point if or not derive 
AssertionEx from Exception. I argue that all child exception MUST BE 
derived from Exception. Any exception to this is not an Exception. (my 
english is too limited to explain this, sorry)


> b) It can still be gracefully handled (unlike a fatal error). E.g. the 
> unit testing framework can catch it, so you can continue running all 
> your tests even if one causes an assertion failure.

Unit test frameworks do this already. No change here.


> When Joe says "not intended to be caught" this is referring to 
> "normal" code. Catching them at the top-level still makes sense, e.g. 
> for the unit testing case mentioned or even just to print a nice error 
> message with extra information. Using an exception instead of a fatal 
> error also means that things like "finally" will still run, so your 
> code can still release locks etc even if an assertion failure occurred.

In production this will never happen. We go round in circles here. I am 
aware of you preference on "exceptions everywhere".


>
> Nikita

---

## #83311 — Joe Watkins — 2015-02-20T15:29:42+00:00

URL: https://externals.io/message/83160#83311 · In reply to: #83307

> However I think it is pre
mature to vote on as there was (sorry) not explicit discussions about
it.

I haven't heard that from anyone else, the RFC is plenty old.

> A couple of things are unclear. See the numerous questions in this thread.
> I also do not like other things.

These don't seem like valid reasons to hold off progress.

> zend.assertions:

Having a more general debug setting might be a good idea, but is outside of
the scope of this RFC.

> assert.exceptions:

Delay isn't necessary, exceptions are not used by default, and there is
plenty of time for Engine Exceptions to make necessary changes.

Cheers
Joe

On Fri, Feb 20, 2015 at 2:55 PM, Crypto Compress <
cryptocompress@googlemail.com> wrote:

> Am 20.02.2015 um 15:09 schrieb Nikita Popov:
>
> > […]
>
> Assumed context is wrong here.
> - exception in development: error
> - no exception in production: warning, zero cost nothing
>
> Rephrased: A zero-cost non-existing exception would continue running the
> code, ...
>
> In a previous email you brought up the point if or not derive AssertionEx
> from Exception. I argue that all child exception MUST BE derived from
> Exception. Any exception to this is not an Exception. (my english is too
> limited to explain this, sorry)
>
>
>  b) It can still be gracefully handled (unlike a fatal error). E.g. the
> > […]
>
> Unit test frameworks do this already. No change here.
>
>
>  When Joe says "not intended to be caught" this is referring to "normal"
> > […]
>
> In production this will never happen. We go round in circles here. I am
> aware of you preference on "exceptions everywhere".
>
>
>
> > […]

---

Next page: https://externals.io/message/83160.md?page=2
