-
Notifications
You must be signed in to change notification settings - Fork 127
/
Copy pathradio-browser.html
293 lines (291 loc) · 24.4 KB
/
radio-browser.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>PyRadio RadioBrowser Implementation</title>
<style>
body {padding: 2em;}
@media screen and (max-width: 770px) {
body {padding: 10px;}
}
body {max-width: 750px; margin: auto;}
h2 {margin-top: 2.5em; border-bottom:1px solid SaddleBrown; color: SaddleBrown;}
h3 {margin-top: 2em; color: SaddleBrown; text-decoration: underline SaddleBrown}
h4 {margin: 2em 0 1em 0; color: SaddleBrown; font-size: 1em;}
h4:before {content: "# "; font-weight: bold; vertical-align: middle;}
h5 {margin: 2em 0 1em 0; color: SaddleBrown; font-size: 1em;;}
h5:before {content: "## "; font-weight: bold; vertical-align: middle;}
p, table, ol, ul {margin-left: .8em;}
STRONG {color: SaddleBrown;}
dl {margin: 2em;}
dd {margin: 1em;}
dt {font-weight: bold;}
TABLE {border: 1px solid SaddleBrown; border-collapse: collapse; margin-left: auto; margin-right: auto; border-radius: 5px; -moz-border-radius: 5px; border-collapse:separate; box-shadow: 5px 5px 15px #888888;}
TH {text-align: left; vertical-align: top; padding: 5px;color: SaddleBrown;border: 1px solid SaddleBrown; background-color: SaddleBrown; color: white;}
TD {text-align: left; vertical-align: top; padding: 5px 10px;border: 1px solid SaddleBrown;}
pre { background-color: rgba(245, 245, 245, 1); color: #474747; padding: 1.5em; border: 1px solid #C7C7C7; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; overflow: auto; box-shadow: 5px 5px 15px #C7C7C7;}
.task-list {list-style-type: none; padding: 0; margin: 0 0 0 1em ;}
img{display: block; margin-left: auto; margin-right: auto; max-width: 750px; width: 100%; background:transparent; padding:3px; border:1px solid #999999; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; box-shadow:5px 5px 15px #888888;}
.indented {text-indent: -1.5em; padding-left: 1.5em; margin-left: 1em;}
a{ color: SaddleBrown;}
a:visited{color: SaddleBrown;}
</style>
</head>
<body>
<header id="title-block-header">
</header>
<h1 style="color: SaddleBrown" id="pyradio-radiobrowser-implementation">PyRadio RadioBrowser Implementation</h1>
<p><a target="_blank" href="https://www.radio-browser.info/">RadioBrowser</a> is “a community driven effort (like wikipedia) with the aim of collecting as many internet radio and TV stations as possible.”</p>
<p><strong>PyRadio</strong> uses the API provided to integrate it and provide its users the possibility to enjoy this great project.</p>
<h2 id="table-of-contents">Table of Contents <span style="padding-left: 10px;"><sup style="font-size: 50%"><a href="#" title="Go to top of the page">Top</a></sup></span></h2>
<!-- vim-markdown-toc Marked -->
<ul>
<li><a href="#opening-radiobrowser">Opening RadioBrowser</a></li>
<li><a href="#closing-radiobrowser">Closing RadioBrowser</a></li>
<li><a href="#how-it-works">How it works</a>
<ul>
<li><a href="#searching-in-the-list-of-stations">Searching in the list of stations</a></li>
<li><a href="#sorting-stations">Sorting stations</a></li>
</ul></li>
<li><a href="#controls">Controls</a></li>
<li><a href="#configuration">Configuration</a>
<ul>
<li><a href="#server-pinging">Server pinging</a></li>
</ul></li>
<li><a href="#server-selection">Server Selection</a></li>
<li><a href="#station-database-information">Station Database Information</a></li>
<li><a href="#station-clicking-and-voting">Station clicking and voting</a></li>
<li><a href="#search-window">Search Window</a>
<ul>
<li><a href="#search-term-composition">Search term composition</a></li>
<li><a href="#history-management">History Management</a></li>
</ul></li>
</ul>
<!-- vim-markdown-toc -->
<p class="indented">[ <a href="index.html#online-radio-directory-services">Return to main doc</a> ]</p>
<h2 id="opening-radiobrowser">Opening RadioBrowser <span style="padding-left: 10px;"><sup style="font-size: 50%"><a href="#" title="Go to top of the page">Top</a></sup></span></h2>
<p>To open <strong>RadioBrowser</strong> one would just press “<strong>O</strong>” at the program’s main window. Since at this point this is the only service supported, the service will be activated.</p>
<p><a href="https://members.hellug.gr/sng/pyradio/pyradio-radio-browser.png" target="_blank"><img style="width: 550px" src="https://members.hellug.gr/sng/pyradio/pyradio-radio-browser.png" alt="PyRadio’s RadioBrowser interface" /></a></p>
<p>Upon activation, the <strong>default query</strong> will be preformed and (if successful) its results will be presented to the user. If unsuccessful, a relevant message will be displayed and the program will return to the local playlist that was previously opened.</p>
<p>By default, <strong>PyRadio</strong> will load the first 100 most voted stations on <strong>RadioBrowser</strong>.</p>
<h2 id="closing-radiobrowser">Closing RadioBrowser <span style="padding-left: 10px;"><sup style="font-size: 50%"><a href="#" title="Go to top of the page">Top</a></sup></span></h2>
<p><strong>PyRadio</strong> treats the service as a special kind of a playlist, thus to close the service it is enough to “<em>go back to playlist history</em>”, pressing “<strong>\\</strong>” (double backslash), in addition to the normal way (“<strong>q</strong>” or <strong>Escape</strong>).</p>
<h2 id="how-it-works">How it works <span style="padding-left: 10px;"><sup style="font-size: 50%"><a href="#" title="Go to top of the page">Top</a></sup></span></h2>
<p>The implementation uses a list structure (we’ll call it “<strong>search history</strong>” from now on) to keep user specified queries (we’ll call them “<strong>search terms</strong>”).</p>
<p>The first item in the “<strong>search history</strong>” is the “<strong>empty search term</strong>” (or “<strong>empty item</strong>”), which cannot be deleted and cannot be used to actually query <strong>RadioBrowser</strong>; it is there to provide a “<strong>search term template</strong>” for user inserted search terms.</p>
<p>Upon activation, the “<strong>default search term</strong>” is used to automatically query a randomly selected <strong>RadioBrowser</strong> server and display stations’ results.</p>
<p>Once the results are fetched, they act as a special kind of playlist (some of the features of a local playlist are not functional, such as station renaming and such), and other features are introduced (such as the sort function and the station database info function).</p>
<p>Each search result, i.e. each station, has more data attached to it than just its name and URL (bitrate, votes, clicks, etc.). This data is displayed in field columns; the number of visible columns depend on the width of the terminal’s window. The name of the column that matches the sorting criteria is “highlighted”.</p>
<h3 id="searching-in-the-list-of-stations">Searching in the list of stations</h3>
<p>The normal local playlist search function has been enhanced in order to be able to search through the list of stations, since each station has a lot more info attached to it.</p>
<p>Searching for any string will return matches in the “<strong>Name</strong>” field only (just like in a local playlist), but starting the search string with a plus sign (“<strong>+</strong>”) will produce results from all available fields (visible or not).</p>
<h3 id="sorting-stations">Sorting stations</h3>
<p>Pressing “<strong>S</strong>” will present the user with a sorting list. Selecting one of the items will sort the stations based on it; selecting it again will reverse sorting order.</p>
<p style="margin: 1.5em 4em 0 4em; text-indent: -2.5em;"><strong>Note:</strong> This sorting function is different than the query sorting criterion which can be selected in the <a href="#search-window">Search window</a>. This one just sorts a query result set, the one in the “<strong>Search window</strong>” affects the actual stations that will be in the result set.</p>
<h2 id="controls">Controls <span style="padding-left: 10px;"><sup style="font-size: 50%"><a href="#" title="Go to top of the page">Top</a></sup></span></h2>
<p>These are the <strong>RadioBrowser</strong> specific keys one can use in addition to local playlist keys (if applicable).</p>
<table>
<thead>
<tr>
<th>Key</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td>O</td>
<td>Open RadioBrowser</td>
</tr>
<tr>
<td>c</td>
<td>Open config window</td>
</tr>
<tr>
<td>C</td>
<td>Select server to connect to</td>
</tr>
<tr>
<td>s</td>
<td>Search for stations</td>
</tr>
<tr>
<td>{ [ ]</td>
<td>Display the first / next /previous page</td>
</tr>
<tr>
<td>F1 F2 F3</td>
<td>Same functionally as above for Windows</td>
</tr>
<tr>
<td>S</td>
<td>Sort search results</td>
</tr>
<tr>
<td>I</td>
<td>Station database info (current selection)</td>
</tr>
<tr>
<td>V</td>
<td>Vote for station</td>
</tr>
<tr>
<td>\\ q Escape</td>
<td>Close RadioBrowser</td>
</tr>
</tbody>
</table>
<p style="margin: 1.5em 4em 0 4em; text-indent: -2.5em;"><strong>Note:</strong> One would get this information using the program’s help (pressing “<strong>?</strong>” and navigating to the last page of it).</p>
<h2 id="configuration">Configuration <span style="padding-left: 10px;"><sup style="font-size: 50%"><a href="#" title="Go to top of the page">Top</a></sup></span></h2>
<p>One can get to <strong>RadioBrowser</strong>’s configuration in any of the following ways:</p>
<ol type="1">
<li><p>From PyRadio <strong>Configuration</strong>, section <strong>Online Services</strong></p></li>
<li><p>From within <strong>RadioBrowser</strong> playlist, by pressing “<em>c</em>”</p></li>
</ol>
<p>The configuration window presents the following options:</p>
<ol type="1">
<li><p><strong>Auto save config</strong><br />
If True, no confirmation will be asked before saving the configuration when leaving the search window.<br />
Default value: <em>False</em></p></li>
<li><p><strong>Maximum number of results</strong><br />
<strong>RadioBrowser</strong>’s database is really huge and some queries will produce too many results. This is the way to limit returned result number.<br />
Setting this parameter to -1 will disable result limiting.<br />
Default value: <em>100</em></p></li>
<li><p><strong>Number of ping packages</strong><br />
The number of ping (ICMP) packages to send to a server while checking its availability. More on “<em>Server pinging</em>” later in this section.<br />
A value of 0 will disable server pinging.<br />
Default value: <em>1</em></p></li>
<li><p><strong>Ping timeout (seconds)</strong><br />
The number of seconds to wait for a ping command to terminate while checking a server’s availability.<br />
A value of 0 will disable server pinging.<br />
Default value: <em>1</em></p></li>
<li><p><strong>Default Server</strong><br />
The default server to connect to when using the service.<br />
Default value: <em>Random</em></p></li>
<li><p><strong>Search Terms</strong><br />
User defined “<em>Search Terms</em>” displayed in a compact way.<br />
Available actions: change the <strong>default</strong> search term and <strong>delete</strong> existing search terms.</p></li>
</ol>
<h3 id="server-pinging">Server pinging</h3>
<p><strong>RadioBrowser</strong> currently provides a network of 3 servers to connect to (always kept in sync with each other), in order to limit down time.</p>
<p>In the rare event an individual server is down, an application can just connect to any of the remaining servers to keep using the service.</p>
<p><strong>PyRadio</strong> will use the ICMP protocol (ping) to check servers availability before even trying to query a server. The configuration parameters “<em>Number of ping packages</em>” and “<em>Ping timeout (seconds)</em>” will be used to ping the servers. If any of them is set to 0, <strong>server pinging will be disabled.</strong></p>
<p>When opening the service, <strong>PyRadio</strong> will act depending upon its configured settings.</p>
<ol type="1">
<li><p><strong>No default server is specified and pinging is enabled</strong><br />
In this case, <strong>PyRadio</strong> will randomly select a server, make sure it’s online (ping it) and then use it to query and display results.<br />
If no server is available or if the internet connection has failed, a message will be displayed informing the user.</p></li>
<li><p><strong>A default server has been specified and pinging is enabled</strong><br />
<strong>PyRadio</strong> will ping the server and will connect to it if it’s available.<br />
If the default server is unresponsive, <strong>PyRadio</strong> will try to find and use one that is available.<br />
If no server is available or if the internet connection has failed, a message will be displayed informing the user.</p></li>
<li><p><strong>Pinging is disabled</strong><br />
No server availability check will occur.<br />
If the server (default or random) is unavailable or if the internet connection has failed, a message will be displayed informing the user.</p></li>
</ol>
<p>When using the “<strong>Server Selection Window</strong>” (either within the configuration window or the playlist):</p>
<ol type="1">
<li><p><strong>If pinging is enabled</strong><br />
The selected server availability will be checked, and if not responsive, it will not be accepted.</p></li>
<li><p><strong>If pinging is disabled</strong><br />
The server will be accepted regardless of its availability.</p></li>
</ol>
<h2 id="server-selection">Server Selection <span style="padding-left: 10px;"><sup style="font-size: 50%"><a href="#" title="Go to top of the page">Top</a></sup></span></h2>
<p>In addition to the “<em>default server</em>” which can be set at the configuration window, one has the possibility to select a server to connect after opening the service.</p>
<p>Pressing “<strong>C</strong>” will provide a list of available servers to choose from. This selection will be honored until the service is closed.</p>
<h2 id="station-database-information">Station Database Information <span style="padding-left: 10px;"><sup style="font-size: 50%"><a href="#" title="Go to top of the page">Top</a></sup></span></h2>
<p>The database information of the selected station can be displayed by pressing “<strong>I</strong>”. Keep in mind that, this is different than the “Station ino” displayed by pressing “<strong>i</strong>” (lowercase “i”), which is still available and presents live data.</p>
<h2 id="station-clicking-and-voting">Station clicking and voting <span style="padding-left: 10px;"><sup style="font-size: 50%"><a href="#" title="Go to top of the page">Top</a></sup></span></h2>
<p><strong>RadioBrowser</strong> provides two ways to measure a station’s popularity: voting and clicking.</p>
<p><strong>Clicking</strong> a station means that the station has been listened to; <strong>PyRadio</strong> will send a “click request” any time the user starts playback of a station; <strong>RadioBrowser</strong> will either reject or accept the action, and either ignore or increase click count for the station based on several criteria (time between consecutive clicks, possibly IP, etc.)</p>
<p>For this reason <strong>PyRadio</strong> will in no case adjust the click count presented to the user.</p>
<p><strong>Voting</strong> for a station is a different thing; the user has to choose to vote for it. In <strong>PyRadio</strong> a “vote request” is sent when “<strong>V</strong>” is pressed. If the vote has been accepted, the vote counter will be increased by one.</p>
<p style="margin: 1.5em 4em 0 4em; text-indent: -2.5em;"><strong>Note:</strong> Inconsistencies between a voted for station’s local vote counter value and the one reported in a consecutive server response should be expected, since it seems servers’ vote counter sync may take some time to complete.</p>
<h2 id="search-window">Search Window <span style="padding-left: 10px;"><sup style="font-size: 50%"><a href="#" title="Go to top of the page">Top</a></sup></span></h2>
<p>The “<strong>Search window</strong>” opens when “<strong>s</strong>” is pressed and loads the “<strong>search term</strong>” that was used to fetch the stations currently presented in the “<strong>RadioBrowser window</strong>”. If this is the first time this window is opened within this session, the search term that’s loaded is the “<strong>default search term</strong>”.</p>
<p style="margin: 1.5em 4em 0 4em; text-indent: -2.5em;"><strong>Note:</strong> In case the server returns no results, the window will automatically reopen so that you can redefine the “<strong>search term</strong>”.</p>
<p>Navigation between the various fields is done using the “<strong>Tab</strong>” (and “<strong>Shift-Tab</strong>”) key, the arrows and <strong>vim keys</strong> (“<strong>j</strong>”, “<strong>k</strong>”, “<strong>h</strong>” and “<strong>l</strong>”), provided that any given key is not already used by one of the on window “widgets”.</p>
<p>Toggling the state of check boxes is done by pressing <strong>SPACE</strong>. The “<em>Display by</em>” and “<em>Search for</em>” check boxes are mutually exclusive (enabling one disables the other). Each of them will give access to more fields when enabled.</p>
<p>To perform a search (server query) one would just press <strong>Enter</strong> on the “<strong>OK</strong>” button, or “<strong>s</strong>” on any widget other than a <em>Line editor</em>.</p>
<p><a href="https://members.hellug.gr/sng/pyradio/radio-browser-search-window.png" target="_blank"><img style="width: 550px" src="https://members.hellug.gr/sng/pyradio/radio-browser-search-window.png" alt="RadioBrowser Search Window" /></a></p>
<p>This window performs two functions:</p>
<ol type="1">
<li>composes a search term to be forwarded to the search function and</li>
<li>manages the “<strong>search history</strong>”.</li>
</ol>
<h3 id="search-term-composition">Search term composition</h3>
<p>The “<strong>Search window</strong>” can be divided in four parts:</p>
<ul>
<li><p>The “<strong>Display</strong>” part</p>
<p>In this part one would select to fetch a list of stations based on a single criterion such as their vote count, click count, etc.</p></li>
<li><p>The “<strong>Search</strong>” part</p>
<p>In this part, the user would insert a search string to one or more of the available fields.</p>
<p>Each of the fields has an “<strong>Exact</strong>” checkbox. If checked, an exact match will be returned, hopefully.</p>
<p>In the “<strong>Country</strong>” field one could either provide the name of a country or its two-letter code (based on <a target="_blank" href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166</a>). For example, to get a list of Greek stations, you would either insert “<em>greece</em>” or the country code, which is “<em>gr</em>”.</p></li>
</ul>
<p>These two parts are mutually exclusive, since when one is activated through its corresponding checkbox, the other one gets disabled.</p>
<ul>
<li><p>The “<strong>Sort</strong>” part</p>
<p>This part affects both previous parts.</p>
<p>It provides the server with the sorting criteria upon which the results will be returned.</p></li>
<li><p>The “<strong>Limit</strong>” part</p>
<p>In this part the maximum number or returned stations is specified. The default value is 100 stations (0 means no limit).</p>
<p>The value can be changed using the left and right arrows or “<strong>h</strong>”, “<strong>l</strong>” and “<strong>PgUp</strong>”, “<strong>PgDn</strong>” for a step of 10.</p></li>
</ul>
<h3 id="history-management">History Management</h3>
<p>At the bottom of the “<strong>Search window</strong>” you have the <strong>history information</strong> section; on the left the number of history items is displayed along with the number of the current history item (“<strong>search term</strong>”) and on the right there’s the history help legend.</p>
<p>The keys to manage the history are all <strong>Control</strong> combinations:</p>
<table>
<colgroup>
<col style="width: 21%" />
<col style="width: 78%" />
</colgroup>
<thead>
<tr>
<th>Key</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>^N</strong> <strong>^P</strong></td>
<td>Move to next / previous “<strong>search term</strong>” definition.</td>
</tr>
<tr>
<td><strong>HOME</strong> or <strong>0</strong></td>
<td>Move to the “<strong>empty search term</strong>” (history item 0), the <em>template item</em>. This is a quick way to “reset” all settings and start new. Of course, one could just navigate to this history item using <strong>^N</strong> or <strong>^P</strong>, but it’s here just for convenience.<br><br>Pressing <strong>0</strong> works on all widgets; <strong>HOME</strong> does not work on <strong>Line editors</strong>.<br>To inster a <strong>0</strong> on a <strong>Line editor</strong> just type “<strong>\0</strong>”.</td>
</tr>
<tr>
<td><strong>END</strong> or <strong>g</strong> or <strong>$</strong></td>
<td>Move to the last <strong>search term</strong>.<br><br>Pressing <strong>$</strong> works on all widgets; <strong>END</strong> and <strong>g</strong> do not work on <strong>Line editors</strong>.<br>To inster a <strong>$</strong> on a <strong>Line editor</strong> just type “<strong>\$</strong>”.</td>
</tr>
<tr>
<td><strong>PgUp</strong> / <strong>PgDown</strong></td>
<td>Jump up or down within the “<strong>search history</strong>” list.<br>These keys do not work when the “<em>Result limit</em>” counter field is focused.</td>
</tr>
<tr>
<td><strong>^Y</strong></td>
<td>Add current item to history.</td>
</tr>
<tr>
<td><strong>^X</strong></td>
<td>Delete the current history item.<br>There is no confirmation and once an item is deleted there’s no undo function.<br>These rules apply:<br> 1. The first item (<strong>search term template</strong>) cannot be deleted.<br>2. When the history contains only two items (the <strong>search term template</strong> will always be the first one; the second one is a user defined <strong>search term</strong>), no item deletion is possible.<br>3. When the <strong>default search term</strong> is deleted, the first user defined <strong>search term</strong> becomes the default one.</td>
</tr>
<tr>
<td><strong>^B</strong></td>
<td>Make the current history item the <strong>default</strong> one for <strong>RadioBrowser</strong> and save the history.<br>This means that, next time you open <strong>RadioBrowser</strong> this history item (“<strong>search term</strong>”) will be automatically loaded.</td>
</tr>
<tr>
<td><strong>^E</strong></td>
<td>Save the history.</td>
</tr>
</tbody>
</table>
<p style="margin: 1.5em 4em 0 4em; text-indent: -2.5em;"><strong>Note:</strong> All keys can also be used without pressing the Control key, provided that a line editor does not have the focus. For example, pressing “<strong>x</strong>” is the same as pressing “<strong>^X</strong>”, ”<strong>e</strong>” is the same as ”<strong>^E</strong>” and so on. This feature is provided for tiling window manager users who may have already assigned actions to any of these Contol-key combinations.</p>
<p>All history navigation actions (<strong>^N</strong>, <strong>^P</strong>, <strong>HOME</strong>, <strong>END</strong>, <strong>PgUp</strong>, <strong>PgDown</strong>) will check if the data currently in the “form” fields can create a new <strong>search term</strong> and if so, will add it to the history.</p>
<p>The <strong>Search Window</strong> actually works on a copy of the <strong>search history</strong> used by the service itself, so any changes made in it (adding and deleting items or changing the default item) are not passed to the service, until “<strong>OK</strong>” is pressed (or “<strong>s</strong>” is typed on any field other than a “<em>Line editor</em>”). Pressing “<strong>Cancel</strong>” will make all the changes go away.</p>
<p>Even when “<strong>OK</strong>” (or “<strong>s</strong>” is typed on any field other than a “<em>Line editor</em>”) is pressed, and the “<strong>Search Window</strong>” is closed, the “new” history is loaded into the service, but NOT saved to the <em>configuration file</em>.</p>
<p>To really save the “new” history, press “<strong>^E</strong>” in the <strong>Search Window</strong> (or “<strong>e</strong>” is typed on any field other than a “<em>Line editor</em>”), or press “<strong>y</strong>” in the confirmation window upon exiting the service.</p>
</body>
</html>