Bob Mottram il y a 8 ans
Parent
révision
60114b020e
2 fichiers modifiés avec 437 ajouts et 2 suppressions
  1. 435
    0
      src/freedombone-app-ghost
  2. 2
    2
      src/freedombone-app-htmly

+ 435
- 0
src/freedombone-app-ghost Voir le fichier

@@ -0,0 +1,435 @@
1
+#!/bin/bash
2
+#
3
+# .---.                  .              .
4
+# |                      |              |
5
+# |--- .--. .-.  .-.  .-.|  .-. .--.--. |.-.  .-. .--.  .-.
6
+# |    |   (.-' (.-' (   | (   )|  |  | |   )(   )|  | (.-'
7
+# '    '     --'  --'  -' -  -' '  '   -' -'   -' '   -  --'
8
+#
9
+#                    Freedom in the Cloud
10
+#
11
+# Ghost blog
12
+#
13
+# License
14
+# =======
15
+#
16
+# Copyright (C) 2016 Bob Mottram <bob@freedombone.net>
17
+#
18
+# This program is free software: you can redistribute it and/or modify
19
+# it under the terms of the GNU Affero General Public License as published by
20
+# the Free Software Foundation, either version 3 of the License, or
21
+# (at your option) any later version.
22
+#
23
+# This program is distributed in the hope that it will be useful,
24
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
25
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
+# GNU Affero General Public License for more details.
27
+#
28
+# You should have received a copy of the GNU Affero General Public License
29
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
30
+
31
+VARIANTS="full full-vim writer"
32
+
33
+IN_DEFAULT_INSTALL=0
34
+SHOW_ON_ABOUT=1
35
+
36
+GHOST_DOMAIN_NAME=
37
+GHOST_CODE=
38
+GHOST_ONION_PORT=8104
39
+GHOST_VERSION='0.11.3'
40
+GHOST_PORT=2368
41
+
42
+ghost_variables=(GHOST_VERSION
43
+                 GHOST_DOMAIN_NAME
44
+                 GHOST_CODE
45
+                 GHOST_ADMIN_PASSWORD
46
+                 ONION_ONLY
47
+                 DDNS_PROVIDER
48
+                 MY_USERNAME)
49
+
50
+function remove_user_ghost {
51
+    remove_username="$1"
52
+}
53
+
54
+function add_user_ghost {
55
+    if [[ $(app_is_installed ghost) == "0" ]]; then
56
+        echo '0'
57
+        return
58
+    fi
59
+
60
+    new_username="$1"
61
+    new_user_password="$2"
62
+
63
+    echo '0'
64
+}
65
+
66
+function install_interactive_ghost {
67
+    if [ ! $ONION_ONLY ]; then
68
+        ONION_ONLY='no'
69
+    fi
70
+
71
+    if [[ $ONION_ONLY != "no" ]]; then
72
+        GHOST_DOMAIN_NAME='ghost.local'
73
+        write_config_param "GHOST_DOMAIN_NAME" "$GHOST_DOMAIN_NAME"
74
+    else
75
+        function_check interactive_site_details
76
+        interactive_site_details "ghost" "GHOST_DOMAIN_NAME" "GHOST_CODE"
77
+    fi
78
+    APP_INSTALLED=1
79
+}
80
+
81
+function change_password_ghost {
82
+    set_completion_param "ghost domain" "$GHOST_DOMAIN_NAME"
83
+    GHOST_DOMAIN_NAME=$(get_completion_param "ghost domain")
84
+
85
+    GHOST_USERNAME="$1"
86
+    GHOST_PASSWORD="$2"
87
+    if [ ${#GHOST_PASSWORD} -lt 8 ]; then
88
+        echo $'Ghost password is too short'
89
+        return
90
+    fi
91
+}
92
+
93
+function reconfigure_ghost {
94
+    echo -n ''
95
+}
96
+
97
+function upgrade_ghost {
98
+    read_config_param "GHOST_DOMAIN_NAME"
99
+
100
+}
101
+
102
+function backup_local_ghost {
103
+    GHOST_DOMAIN_NAME='ghost.local'
104
+    if grep -q "ghost domain" $COMPLETION_FILE; then
105
+        GHOST_DOMAIN_NAME=$(get_completion_param "ghost domain")
106
+    fi
107
+
108
+    ghost_path=/var/www/${GHOST_DOMAIN_NAME}/htdocs
109
+    if [ -d $ghost_path ]; then
110
+        function_check backup_database_to_usb
111
+        backup_database_to_usb ghost
112
+
113
+        backup_directory_to_usb $ghost_path ghost
114
+        restart_site
115
+    fi
116
+}
117
+
118
+function restore_local_ghost {
119
+    GHOST_DOMAIN_NAME='ghost.local'
120
+    if grep -q "ghost domain" $COMPLETION_FILE; then
121
+        GHOST_DOMAIN_NAME=$(get_completion_param "ghost domain")
122
+    fi
123
+    if [ $GHOST_DOMAIN_NAME ]; then
124
+        function_check ghost_create_database
125
+        ghost_create_database
126
+
127
+        function_check restore_database
128
+        restore_database ghost ${GHOST_DOMAIN_NAME}
129
+    fi
130
+}
131
+
132
+function backup_remote_ghost {
133
+    GHOST_DOMAIN_NAME='ghost.local'
134
+    if grep -q "ghost domain" $COMPLETION_FILE; then
135
+        GHOST_DOMAIN_NAME=$(get_completion_param "ghost domain")
136
+    fi
137
+
138
+    temp_backup_dir=/var/www/${GHOST_DOMAIN_NAME}/htdocs
139
+    if [ -d $temp_backup_dir ]; then
140
+        suspend_site ${GHOST_DOMAIN_NAME}
141
+        backup_database_to_friend ghost
142
+        backup_directory_to_friend $temp_backup_dir ghost
143
+        restart_site
144
+    else
145
+        echo $"Ghost domain specified but not found in /var/www/${GHOST_DOMAIN_NAME}"
146
+        exit 2578
147
+    fi
148
+}
149
+
150
+function restore_remote_ghost {
151
+    GHOST_DOMAIN_NAME='ghost.local'
152
+    if grep -q "ghost domain" $COMPLETION_FILE; then
153
+        GHOST_DOMAIN_NAME=$(get_completion_param "ghost domain")
154
+    fi
155
+
156
+    function_check restore_database_from_friend
157
+
158
+    function_check ghost_create_database
159
+    ghost_create_database
160
+
161
+    restore_database_from_friend ghost ${GHOST_DOMAIN_NAME}
162
+    restart_site
163
+    chown -R ghost: /var/www/$GHOST_DOMAIN_NAME/htdocs/
164
+}
165
+
166
+function remove_ghost {
167
+    if [ ${#GHOST_DOMAIN_NAME} -eq 0 ]; then
168
+        return
169
+    fi
170
+
171
+    systemctl stop ghost
172
+    systemctl disable ghost
173
+    rm /etc/systemd/system/ghost.service
174
+
175
+    function_check remove_nodejs
176
+    remove_nodejs ghost
177
+
178
+    drop_database ghost
179
+    remove_backup_database_local ghost
180
+
181
+    read_config_param "GHOST_DOMAIN_NAME"
182
+    nginx_dissite $GHOST_DOMAIN_NAME
183
+    remove_certs ${GHOST_DOMAIN_NAME}
184
+    deluser -r ghost
185
+    if [ -f /etc/nginx/sites-available/$GHOST_DOMAIN_NAME ]; then
186
+        rm -f /etc/nginx/sites-available/$GHOST_DOMAIN_NAME
187
+    fi
188
+    if [ -d /var/www/$GHOST_DOMAIN_NAME ]; then
189
+        rm -rf /var/www/$GHOST_DOMAIN_NAME
190
+    fi
191
+    remove_config_param GHOST_DOMAIN_NAME
192
+    remove_config_param GHOST_CODE
193
+    function_check remove_onion_service
194
+    remove_onion_service ghost ${GHOST_ONION_PORT}
195
+    remove_completion_param "install_ghost"
196
+    sed -i '/Ghost/d' $COMPLETION_FILE
197
+    sed -i '/ghost/d' $COMPLETION_FILE
198
+    sed -i '/ghost/d' /home/$MY_USERNAME/README
199
+    sed -i '/Ghost/d' /home/$MY_USERNAME/README
200
+
201
+    function_check remove_ddns_domain
202
+    remove_ddns_domain $GHOST_DOMAIN_NAME
203
+}
204
+
205
+function get_ghost_admin_password {
206
+    if [ -f /home/$MY_USERNAME/README ]; then
207
+        if grep -q "Your ghost password is" /home/$MY_USERNAME/README; then
208
+            GHOST_ADMIN_PASSWORD=$(cat /home/$MY_USERNAME/README | grep "Your ghost password is" | awk -F ':' '{print $2}' | sed 's/^ *//')
209
+        fi
210
+    fi
211
+}
212
+
213
+function ghost_create_config {
214
+    ghost_config=/var/www/${GHOST_DOMAIN_NAME}/htdocs/config.js
215
+
216
+    echo "var path = require('path')," > $ghost_config
217
+    echo '    config;' >> $ghost_config
218
+    echo '' >> $ghost_config
219
+    echo 'config = {' >> $ghost_config
220
+    echo '    production: {' >> $ghost_config
221
+    if [[ $ONION_ONLY == 'no' ]]; then
222
+        echo "        url: 'https://${GHOST_DOMAIN_NAME}'," >> $ghost_config
223
+    else
224
+        echo "        url: 'http://${GHOST_DOMAIN_NAME}'," >> $ghost_config
225
+    fi
226
+    echo '        mail: {' >> $ghost_config
227
+    echo "            transport: 'SMTP'," >> $ghost_config
228
+    echo '            options: {' >> $ghost_config
229
+    echo "                service: 'Sendmail'," >> $ghost_config
230
+    echo '            }' >> $ghost_config
231
+    echo '        },' >> $ghost_config
232
+    echo '        database: {' >> $ghost_config
233
+    echo "            client: 'mysql'," >> $ghost_config
234
+    echo '            connection: {' >> $ghost_config
235
+    echo "                host     : '127.0.0.1'," >> $ghost_config
236
+    echo "                user     : 'root'," >> $ghost_config
237
+    echo "                password : '${MARIADB_PASSWORD}'," >> $ghost_config
238
+    echo "                database : 'ghost'," >> $ghost_config
239
+    echo "                charset  : 'utf8'" >> $ghost_config
240
+    echo '            }' >> $ghost_config
241
+    echo '        },' >> $ghost_config
242
+    echo '' >> $ghost_config
243
+    echo '        server: {' >> $ghost_config
244
+    echo "            host: '127.0.0.1'," >> $ghost_config
245
+    echo "            port: '${GHOST_PORT}'" >> $ghost_config
246
+    echo '        },' >> $ghost_config
247
+    echo '        logging: false' >> $ghost_config
248
+    echo '    }' >> $ghost_config
249
+    echo '};' >> $ghost_config
250
+    echo '' >> $ghost_config
251
+    echo 'module.exports = config;' >> $ghost_config
252
+    chmod 700 $ghost_config
253
+}
254
+
255
+function ghost_create_database {
256
+    function_check get_mariadb_git_admin_password
257
+    get_mariadb_git_admin_password
258
+
259
+    if [ ! ${GIT_ADMIN_PASSWORD} ]; then
260
+        if [ -f ${IMAGE_PASSWORD_FILE} ]; then
261
+            GIT_ADMIN_PASSWORD="$(printf `cat $IMAGE_PASSWORD_FILE`)"
262
+        else
263
+            GIT_ADMIN_PASSWORD="$(create_password ${MINIMUM_PASSWORD_LENGTH})"
264
+        fi
265
+    fi
266
+    if [ ! $GIT_ADMIN_PASSWORD ]; then
267
+        return
268
+    fi
269
+
270
+    function_check create_database
271
+    create_database ghost "$GHOST_ADMIN_PASSWORD"
272
+}
273
+
274
+function install_ghost {
275
+    if [ ! $ONION_ONLY ]; then
276
+        ONION_ONLY='no'
277
+    fi
278
+
279
+    if [ ! $GHOST_DOMAIN_NAME ]; then
280
+        echo $'The ghost domain name was not specified'
281
+        exit 5062
282
+    fi
283
+
284
+    # for the avatar changing command
285
+    apt-get -yq install unzip wget
286
+
287
+    function_check install_nodejs
288
+    install_nodejs ghost
289
+
290
+    if [ ! -d /var/www/$GHOST_DOMAIN_NAME/htdocs ]; then
291
+        mkdir -p /var/www/$GHOST_DOMAIN_NAME/htdocs
292
+    fi
293
+    cd /var/www/$GHOST_DOMAIN_NAME/htdocs
294
+    wget https://ghost.org/zip/ghost-${GHOST_VERSION}.zip
295
+    if [ ! -f ghost-${GHOST_VERSION}.zip ]; then
296
+        echo $'Unable to download ghost'
297
+        exit 63892
298
+    fi
299
+    unzip ghost-${GHOST_VERSION}.zip
300
+    if [ ! -f /var/www/${GHOST_DOMAIN_NAME}/htdocs/index.js ]; then
301
+        echo $'ghost failed to unzip'
302
+        exit 63835
303
+    fi
304
+    npm install --production
305
+
306
+    function_check install_mariadb
307
+    install_mariadb
308
+
309
+    function_check get_mariadb_password
310
+    get_mariadb_password
311
+
312
+    function_check ghost_create_database
313
+    ghost_create_database
314
+    ghost_create_config
315
+
316
+    adduser --system --home=/var/www/$GHOST_DOMAIN_NAME/htdocs/ --group ghost
317
+    chown -R ghost: /var/www/$GHOST_DOMAIN_NAME/htdocs/
318
+
319
+    echo '[Unit]' > /etc/systemd/system/ghost.service
320
+    echo 'Description=Ghost Blog' >> /etc/systemd/system/ghost.service
321
+    echo 'After=syslog.target' >> /etc/systemd/system/ghost.service
322
+    echo 'After=network.target' >> /etc/systemd/system/ghost.service
323
+    echo 'After=mysqld.service' >> /etc/systemd/system/ghost.service
324
+    echo '' >> /etc/systemd/system/ghost.service
325
+    echo '[Service]' >> /etc/systemd/system/ghost.service
326
+    echo 'Type=simple' >> /etc/systemd/system/ghost.service
327
+    echo 'User=ghost' >> /etc/systemd/system/ghost.service
328
+    echo 'Group=ghost' >> /etc/systemd/system/ghost.service
329
+    echo "WorkingDirectory=/var/www/${GHOST_DOMAIN_NAME}/htdocs" >> /etc/systemd/system/ghost.service
330
+    echo "ExecStart=/usr/bin/node /var/www/${GHOST_DOMAIN_NAME}/htdocs/index.js" >> /etc/systemd/system/ghost.service
331
+    echo 'Restart=always' >> /etc/systemd/system/ghost.service
332
+    echo 'RestartSec=60' >> /etc/systemd/system/ghost.service
333
+    echo "Environment=NODE_ENV=production PORT=${GHOST_PORT}" >> /etc/systemd/system/ghost.service
334
+    echo '' >> /etc/systemd/system/ghost.service
335
+    echo '[Install]' >> /etc/systemd/system/ghost.service
336
+    echo 'WantedBy=multi-user.target' >> /etc/systemd/system/ghost.service
337
+
338
+    systemctl enable ghost
339
+    systemctl daemon-reload
340
+    systemctl start ghost
341
+
342
+    if [[ ${ONION_ONLY} == "no" ]]; then
343
+        function_check nginx_http_redirect
344
+        nginx_http_redirect ${GHOST_DOMAIN_NAME}
345
+        echo 'server {' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
346
+        echo '    listen 443 ssl;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
347
+        echo "    root /var/www/${GHOST_DOMAIN_NAME}/htdocs;" >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
348
+        echo "    server_name ${GHOST_DOMAIN_NAME};" >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
349
+        echo '    access_log off;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
350
+        echo "    error_log /var/log/nginx/${GHOST_DOMAIN_NAME}_error.log ${WEBSERVER_LOG_LEVEL};" >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
351
+        echo '' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
352
+        function_check nginx_ssl
353
+        nginx_ssl ${GHOST_DOMAIN_NAME}
354
+        function_check nginx_disable_sniffing
355
+        nginx_disable_sniffing ${GHOST_DOMAIN_NAME}
356
+        echo '    add_header Strict-Transport-Security max-age=0;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
357
+        echo '' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
358
+        echo '    location / {' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
359
+        function_check nginx_limits
360
+        nginx_limits ${GHOST_DOMAIN_NAME} '10G'
361
+        echo "        proxy_pass http://localhost:${GHOST_PORT};" >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
362
+        echo '    }' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
363
+        echo '' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
364
+        echo '    fastcgi_buffers 64 4K;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
365
+        echo '' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
366
+        echo '    error_page 403 /core/templates/403.php;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
367
+        echo '    error_page 404 /core/templates/404.php;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
368
+        echo '' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
369
+        echo '    location = /robots.txt {' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
370
+        echo '        allow all;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
371
+        echo '        log_not_found off;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
372
+        echo '        access_log off;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
373
+        echo '    }' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
374
+        echo '}' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
375
+        echo '' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
376
+    else
377
+        echo -n '' > /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
378
+    fi
379
+    echo 'server {' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
380
+    echo "    listen 127.0.0.1:${GHOST_ONION_PORT} default_server;" >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
381
+    echo "    root /var/www/$GHOST_DOMAIN_NAME/htdocs;" >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
382
+    echo "    server_name $GHOST_DOMAIN_NAME;" >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
383
+    echo '    access_log off;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
384
+    echo "    error_log /var/log/nginx/${GHOST_DOMAIN_NAME}_error.log ${WEBSERVER_LOG_LEVEL};" >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
385
+    echo '' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
386
+    function_check nginx_disable_sniffing
387
+    nginx_disable_sniffing ${GHOST_DOMAIN_NAME}
388
+    echo '    add_header Strict-Transport-Security max-age=0;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
389
+    echo '' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
390
+    echo '    location / {' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
391
+    function_check nginx_limits
392
+    nginx_limits ${GHOST_DOMAIN_NAME} '10G'
393
+    echo "        proxy_pass http://localhost:${GHOST_PORT};" >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
394
+    echo '    }' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
395
+    echo '' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
396
+    echo '    fastcgi_buffers 64 4K;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
397
+    echo '' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
398
+    echo '    error_page 403 /core/templates/403.php;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
399
+    echo '    error_page 404 /core/templates/404.php;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
400
+    echo '' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
401
+    echo '    location = /robots.txt {' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
402
+    echo '        allow all;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
403
+    echo '        log_not_found off;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
404
+    echo '        access_log off;' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
405
+    echo '    }' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
406
+    echo '}' >> /etc/nginx/sites-available/${GHOST_DOMAIN_NAME}
407
+
408
+    function_check create_site_certificate
409
+    create_site_certificate $GHOST_DOMAIN_NAME 'yes'
410
+
411
+    function_check configure_php
412
+    configure_php
413
+
414
+    GHOST_ONION_HOSTNAME=$(add_onion_service ghost 80 ${GHOST_ONION_PORT})
415
+
416
+    function_check nginx_ensite
417
+    nginx_ensite $GHOST_DOMAIN_NAME
418
+
419
+    systemctl restart nginx
420
+
421
+    if ! grep -q "Ghost onion domain" /home/$MY_USERNAME/README; then
422
+        echo $"Ghost onion domain: ${GHOST_ONION_HOSTNAME}" >> /home/$MY_USERNAME/README
423
+        echo '' >> /home/$MY_USERNAME/README
424
+        chown $MY_USERNAME:$MY_USERNAME /home/$MY_USERNAME/README
425
+        chmod 600 /home/$MY_USERNAME/README
426
+    fi
427
+
428
+    function_check add_ddns_domain
429
+    add_ddns_domain $GHOST_DOMAIN_NAME
430
+
431
+    set_completion_param "ghost domain" "$GHOST_DOMAIN_NAME"
432
+    APP_INSTALLED=1
433
+}
434
+
435
+# NOTE: deliberately no exit 0

+ 2
- 2
src/freedombone-app-htmly Voir le fichier

@@ -195,7 +195,7 @@ function upgrade_htmly {
195 195
 }
196 196
 
197 197
 function backup_local_htmly {
198
-    HTMLY_DOMAIN_NAME='htmly'
198
+    HTMLY_DOMAIN_NAME='htmly.local'
199 199
     if grep -q "htmly domain" $COMPLETION_FILE; then
200 200
         HTMLY_DOMAIN_NAME=$(get_completion_param "htmly domain")
201 201
     fi
@@ -215,7 +215,7 @@ function backup_local_htmly {
215 215
 }
216 216
 
217 217
 function restore_local_htmly {
218
-    HTMLY_DOMAIN_NAME='htmly'
218
+    HTMLY_DOMAIN_NAME='htmly.local'
219 219
     if grep -q "htmly domain" $COMPLETION_FILE; then
220 220
         HTMLY_DOMAIN_NAME=$(get_completion_param "htmly domain")
221 221
     fi