Browse Source

Draft Gazelle install guide

biotorrents 3 years ago
parent
commit
2a10a772c5
10 changed files with 1205 additions and 387 deletions
  1. 2
    2
      .gitignore
  2. 5
    16
      docs/forums.md
  3. 9
    29
      docs/index.md
  4. 476
    0
      docs/install.md
  5. 69
    94
      docs/meta.md
  6. 126
    151
      docs/torrents.md
  7. 66
    94
      docs/users.md
  8. 13
    1
      mkdocs.yml
  9. 1
    0
      readme.md
  10. 438
    0
      sphinx.conf

+ 2
- 2
.gitignore View File

1
-site/
2
-.DS_Store
3
 *.sw*
1
 *.sw*
2
+.DS_Store
3
+site/

+ 5
- 16
docs/forums.md View File

2
 
2
 
3
 Endpoints related to the forums.
3
 Endpoints related to the forums.
4
 
4
 
5
-
6
 ## Category view
5
 ## Category view
7
 
6
 
8
 **Request**
7
 **Request**
9
 
8
 
10
 `ajax.php?action=forum`
9
 `ajax.php?action=forum`
11
 
10
 
12
-
13
 **Response**
11
 **Response**
14
 
12
 
15
 ```json
13
 ```json
64
 }
62
 }
65
 ```
63
 ```
66
 
64
 
67
-
68
 ## Forum view
65
 ## Forum view
69
 
66
 
70
 **Request**
67
 **Request**
75
 
72
 
76
 `&page=` — the page to display (default: `1`)
73
 `&page=` — the page to display (default: `1`)
77
 
74
 
78
-
79
 **Response**
75
 **Response**
80
 
76
 
81
 ```json
77
 ```json
114
 }
110
 }
115
 ```
111
 ```
116
 
112
 
117
-
118
-## Thread view 
113
+## Thread view
119
 
114
 
120
 **Request**
115
 **Request**
121
 
116
 
129
 
124
 
130
 `&updatelastread=` — set to `1` to not update the last read id (default: `0`)
125
 `&updatelastread=` — set to `1` to not update the last read id (default: `0`)
131
 
126
 
132
-
133
 **Response**
127
 **Response**
134
 
128
 
135
 ```json
129
 ```json
203
 }
197
 }
204
 ```
198
 ```
205
 
199
 
206
-
207
 ## Subscriptions
200
 ## Subscriptions
208
 
201
 
209
 **Request**
202
 **Request**
212
 
205
 
213
 `&showunread=` — `1` to show only unread, `0` for all subscriptions (default: `1`)
206
 `&showunread=` — `1` to show only unread, `0` for all subscriptions (default: `1`)
214
 
207
 
215
-
216
 **Response**
208
 **Response**
217
 
209
 
218
 ```json
210
 ```json
243
 }
235
 }
244
 ```
236
 ```
245
 
237
 
246
-
247
 ## Raw BBcode
238
 ## Raw BBcode
248
 
239
 
249
 Fetch a post's unrendered content.
240
 Fetch a post's unrendered content.
250
 
241
 
251
-
252
 **Request**
242
 **Request**
253
 
243
 
254
 `ajax.php?action=raw_bbcode`
244
 `ajax.php?action=raw_bbcode`
255
 
245
 
256
 `&postid=` — post id to display (required)
246
 `&postid=` — post id to display (required)
257
 
247
 
258
-
259
 **Response**
248
 **Response**
260
 
249
 
261
 ```json
250
 ```json
262
 {
251
 {
263
-    "status": "success",
264
-    "response": {
265
-        "body": "[img]https://i.gr-assets.com/images/S/compressed.photo.goodreads.com/books/1348970636l/12420783.jpg[/img]<br />\r\n<br />\r\nThe human species&#39; enjoyment of food is universal, though different cultures prefer wildly different flavors. Shepherd establishes a new companion field to molecular gastronomy called neurogastronomy. His book explains how the brain constructs and interprets multidimensional flavor profiles as the volatile compounds of food pass through the sense of retronasal smell. The science is accessible and still does justice to the complexity of the olfactory&ndash;neurological interactions described. This book will change the way you eat.<br />\r\n<br />\r\n[url=https://libgen.is/book/index.php?md5=6E9CE452E815418B1F134D5718751000]Library Genesis[/url] / [url=https://www.worldcat.org/title/neurogastronomy-how-the-brain-creates-flavor-and-why-it-matters/oclc/967255519&amp;referer=brief_results]WorldCat[/url]"
266
-    }
252
+  "status": "success",
253
+  "response": {
254
+    "body": "[img]https://i.gr-assets.com/images/S/compressed.photo.goodreads.com/books/1348970636l/12420783.jpg[/img]<br />\r\n<br />\r\nThe human species&#39; enjoyment of food is universal, though different cultures prefer wildly different flavors. Shepherd establishes a new companion field to molecular gastronomy called neurogastronomy. His book explains how the brain constructs and interprets multidimensional flavor profiles as the volatile compounds of food pass through the sense of retronasal smell. The science is accessible and still does justice to the complexity of the olfactory&ndash;neurological interactions described. This book will change the way you eat.<br />\r\n<br />\r\n[url=https://libgen.is/book/index.php?md5=6E9CE452E815418B1F134D5718751000]Library Genesis[/url] / [url=https://www.worldcat.org/title/neurogastronomy-how-the-brain-creates-flavor-and-why-it-matters/oclc/967255519&amp;referer=brief_results]WorldCat[/url]"
255
+  }
267
 }
256
 }
268
 ```
257
 ```

+ 9
- 29
docs/index.md View File

1
 The JSON API provides an easily parseable interface to [BioTorrents.de](https://biotorrents.de).
1
 The JSON API provides an easily parseable interface to [BioTorrents.de](https://biotorrents.de).
2
 Please use the navigation menu to find lists of endpoints, their arguments, and example responses.
2
 Please use the navigation menu to find lists of endpoints, their arguments, and example responses.
3
 
3
 
4
-
5
 # Introduction
4
 # Introduction
6
 
5
 
7
 All request URLs are in the form
6
 All request URLs are in the form
26
 If the request is invalid, or a problem occurs, the `status` will be `failure`.
25
 If the request is invalid, or a problem occurs, the `status` will be `failure`.
27
 In this case the value of `response` is `undefined`.
26
 In this case the value of `response` is `undefined`.
28
 
27
 
29
-
30
 ## Bearer token auth
28
 ## Bearer token auth
31
 
29
 
32
 First, generate a token in your profile security settings and keep it safe.
30
 First, generate a token in your profile security settings and keep it safe.
39
   -H "Authorization: Bearer {token}"
37
   -H "Authorization: Bearer {token}"
40
 ```
38
 ```
41
 
39
 
42
-
43
 ## Cookie auth
40
 ## Cookie auth
44
 
41
 
45
 Please send a POST request to `https://biotorrents.de/login.php` with `username` and `password`,
42
 Please send a POST request to `https://biotorrents.de/login.php` with `username` and `password`,
46
 or acquire a cookie from a browser session using the developer tools.
43
 or acquire a cookie from a browser session using the developer tools.
47
 Then store the cookie and use it to access the rest of the API.
44
 Then store the cookie and use it to access the rest of the API.
48
 
45
 
49
-
50
 # Libraries
46
 # Libraries
51
 
47
 
52
 These are the current public projects listed on the
48
 These are the current public projects listed on the
56
 
52
 
57
 Please get it touch if you'd like me to list your project below.
53
 Please get it touch if you'd like me to list your project below.
58
 
54
 
59
-
60
-| Language	| GitHub |
61
-| :--		| :-- |
62
-| C#		| [frankston/WhatAPI](https://github.com/frankston/WhatAPI) |
63
-| Go		| [kdvh/whatapi](https://github.com/kdvh/whatapi) |
64
-| JavaScript	| [deoxxa/whatcd](https://github.com/deoxxa/whatcd) |
65
-| Java		| [Gwindow/WhatAPI](https://github.com/Gwindow/WhatAPI) |
66
-| PHP		| [Jleagle/gazelle-api-client](https://github.com/Jleagle/gazelle-api-client) |
67
-| Python	| [isaaczafuta/whatapi](https://github.com/isaaczafuta/whatapi) |
68
-| Ruby		| [chasemgray/RubyGazelle](https://github.com/chasemgray/RubyGazelle) |
69
-
55
+| Language   | GitHub                                                                      |
56
+| :--------- | :-------------------------------------------------------------------------- |
57
+| C#         | [frankston/WhatAPI](https://github.com/frankston/WhatAPI)                   |
58
+| Go         | [kdvh/whatapi](https://github.com/kdvh/whatapi)                             |
59
+| JavaScript | [deoxxa/whatcd](https://github.com/deoxxa/whatcd)                           |
60
+| Java       | [Gwindow/WhatAPI](https://github.com/Gwindow/WhatAPI)                       |
61
+| PHP        | [Jleagle/gazelle-api-client](https://github.com/Jleagle/gazelle-api-client) |
62
+| Python     | [isaaczafuta/whatapi](https://github.com/isaaczafuta/whatapi)               |
63
+| Ruby       | [chasemgray/RubyGazelle](https://github.com/chasemgray/RubyGazelle)         |
70
 
64
 
71
 # Caveats
65
 # Caveats
72
 
66
 
73
 **Abusing or using this API for malicious purposes is a bannable offense and will not be taken lightly.**
67
 **Abusing or using this API for malicious purposes is a bannable offense and will not be taken lightly.**
74
 
68
 
75
-
76
 ## Rate limit
69
 ## Rate limit
77
 
70
 
78
 The API is rate-limited to one request every 6 seconds.
71
 The API is rate-limited to one request every 6 seconds.
80
 [Please consider donating](https://www.patreon.com/biotorrents)
73
 [Please consider donating](https://www.patreon.com/biotorrents)
81
 to support this scientific resource's development.
74
 to support this scientific resource's development.
82
 
75
 
83
-
84
 ## Under construction
76
 ## Under construction
85
 
77
 
86
 Some endpoints aren't working correctly right now:
78
 Some endpoints aren't working correctly right now:
95
 - `news_ajax`
87
 - `news_ajax`
96
 - `send_recommendation`
88
 - `send_recommendation`
97
 
89
 
98
-
99
 # Not implemented
90
 # Not implemented
100
 
91
 
101
 ## Similar artists
92
 ## Similar artists
108
 
99
 
109
 `&limit=` — maximum number of results to return (fewer might be returned)
100
 `&limit=` — maximum number of results to return (fewer might be returned)
110
 
101
 
111
-
112
 **Response**
102
 **Response**
113
 
103
 
114
 ```json
104
 ```json
115
 
105
 
116
 ```
106
 ```
117
 
107
 
118
-
119
 ## Better
108
 ## Better
120
 
109
 
121
 Fetch better.php (suggested torrent improvements).
110
 Fetch better.php (suggested torrent improvements).
122
 
111
 
123
-
124
 **Request**
112
 **Request**
125
 
113
 
126
 `ajax.php?action=better`
114
 `ajax.php?action=better`
127
 
115
 
128
-
129
 **Response**
116
 **Response**
130
 
117
 
131
 ```json
118
 ```json
132
 
119
 
133
 ```
120
 ```
134
 
121
 
135
-
136
-
137
 ## Torrent info
122
 ## Torrent info
138
 
123
 
139
 **Request**
124
 **Request**
140
 
125
 
141
 `ajax.php?action=torrent_info`
126
 `ajax.php?action=torrent_info`
142
 
127
 
143
-
144
 **Response**
128
 **Response**
145
 
129
 
146
 ```json
130
 ```json
147
 
131
 
148
 ```
132
 ```
149
 
133
 
150
-
151
 ## Check private
134
 ## Check private
152
 
135
 
153
 **Request**
136
 **Request**
154
 
137
 
155
 `ajax.php?action=checkprivate`
138
 `ajax.php?action=checkprivate`
156
 
139
 
157
-
158
 **Response**
140
 **Response**
159
 
141
 
160
 ```json
142
 ```json
161
 
143
 
162
 ```
144
 ```
163
 
145
 
164
-
165
 ## Vote favorite
146
 ## Vote favorite
166
 
147
 
167
 **Request**
148
 **Request**
168
 
149
 
169
 `ajax.php?action=votefavorite`
150
 `ajax.php?action=votefavorite`
170
 
151
 
171
-
172
 **Response**
152
 **Response**
173
 
153
 
174
 ```json
154
 ```json

+ 476
- 0
docs/install.md View File

1
+# Install
2
+
3
+Thanks for your interest in BioTorrents.de development!
4
+Gazelle is notoriously difficult to install and good docs are lacking.
5
+This page, based on the
6
+[original announcement protocol](https://github.com/biotorrents/announcement),
7
+is an attempt to make an evergreen install guide.
8
+It's fast paced and covers only the essentials.
9
+
10
+# Debian system profile
11
+
12
+```shell
13
+$ uname -a
14
+Linux ohm 5.10.0-6-amd64 #1 SMP Debian 5.10.28-1 (2021-04-09) x86_64 GNU/Linux
15
+
16
+$ nginx -v
17
+nginx version: nginx/1.18.0
18
+
19
+$ mysql -V
20
+mysql  Ver 15.1 Distrib 10.5.10-MariaDB, for debian-linux-gnu (x86_64) using  EditLine wrapper
21
+
22
+$ php -v
23
+PHP 7.4.21 (cli) (built: Jul  2 2021 03:59:48) ( NTS )
24
+
25
+$ memcached -h
26
+memcached 1.6.9
27
+
28
+$ indexer
29
+Sphinx 2.2.11-id64-release (95ae9a6)
30
+```
31
+
32
+# Server setup
33
+
34
+This section is done as root.
35
+If you're in a user shell, preface commands with `sudo`.
36
+
37
+## Upgrading to Debian unstable
38
+
39
+Install the most recent
40
+[Debian netinst image](https://www.debian.org/CD/netinst/)
41
+and modify `/etc/apt/sources.list`:
42
+
43
+```
44
+deb http://deb.debian.org/debian unstable main contrib non-free
45
+deb-src http://deb.debian.org/debian unstable main contrib non-free
46
+```
47
+
48
+Optionally, create `/etc/apt/apt.conf` with this content:
49
+
50
+```
51
+APT::Install-Recommends "1";
52
+APT::Install-Suggests "0";
53
+```
54
+
55
+Then upgrade the system:
56
+
57
+```shell
58
+# apt update
59
+# apt dist-upgrade
60
+# reboot
61
+```
62
+
63
+Further server setup,
64
+including TLD considerations, DNS, email, etc.,
65
+are beyond this guide's scope.
66
+For more info about SSH, Unbound, NSD, OpenSMTPd, Dovecot, Unix users, etc.,
67
+[please see the original launch announcement](https://github.com/biotorrents/announcement).
68
+
69
+## Nginx and Certbot
70
+
71
+Install Nginx and Certbot with `apt install nginx certbot python3-certbot-nginx`.
72
+
73
+The basic Gazelle Nginx config should look similar to this.
74
+Note that you'll likely have to change the file paths based on your setup.
75
+Also, PHP-FPM may need larger-than-default buffers to serve without 502 errors:
76
+
77
+```nginx
78
+server {
79
+        listen 443 ssl http2;
80
+        root /var/www/html/dev.biotorrents.de;
81
+
82
+        client_max_body_size 4M;
83
+        server_name dev.biotorrents.de;
84
+
85
+        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
86
+
87
+        ssl_certificate /etc/letsencrypt/live/biotorrents.de-0001/fullchain.pem; # managed by Certbot
88
+        ssl_certificate_key /etc/letsencrypt/live/biotorrents.de-0001/privkey.pem; # managed by Certbot
89
+
90
+        access_log off;
91
+        error_log  /var/log/nginx/dev.biotorrents.de-error.log;
92
+
93
+        location / {
94
+                index index.php;
95
+        }
96
+
97
+        # https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/
98
+        location ~ [^/]\.php(/|$) {
99
+                fastcgi_split_path_info ^(.+?\.php)(/.*)$;
100
+                if (!-f $document_root$fastcgi_script_name) {
101
+                        return 404;
102
+                }
103
+
104
+                # Mitigate https://httpoxy.org/ vulnerabilities
105
+                fastcgi_param HTTP_PROXY "";
106
+
107
+                fastcgi_pass  unix:/var/run/php/php7.4-fpm.sock;
108
+                fastcgi_index index.php;
109
+
110
+                # include the fastcgi_param setting
111
+                include /etc/nginx/params/fastcgi_params;
112
+
113
+                # https://stackoverflow.com/a/23845727
114
+                fastcgi_buffers 16 16k;
115
+                fastcgi_buffer_size 32k;
116
+        }
117
+
118
+        # https://nginx.org/en/docs/http/ngx_http_access_module.html
119
+        location ^~ /.git/ {
120
+                deny all;
121
+        }
122
+
123
+        location ^~ /classes/config.php {
124
+                deny all;
125
+        }
126
+}
127
+```
128
+
129
+The Nginx config for the Ocelot tracker should look like this.
130
+Nginx acts as a TLS reverse proxy so that Ocelot isn't directly exposed.
131
+Note the additional caveats of Ocelot's listening port (34000 is default),
132
+and setting the correct `Host` header (so tracker connections don't show up as localhost):
133
+
134
+```nginx
135
+server {
136
+        listen 443 ssl http2;
137
+        server_name tr0.biotorrents.de track.biotorrents.de;
138
+
139
+        add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
140
+
141
+        ssl_certificate /etc/letsencrypt/live/biotorrents.de-0001/fullchain.pem; # managed by Certbot
142
+        ssl_certificate_key /etc/letsencrypt/live/biotorrents.de-0001/privkey.pem; # managed by Certbot
143
+
144
+        access_log off;
145
+        error_log  /var/log/nginx/tr0.biotorrents.de-error.log;
146
+
147
+        # https://nginx.org/en/docs/http/ngx_http_proxy_module.html
148
+        location / {
149
+                proxy_pass http://127.0.0.1:34000;
150
+                proxy_set_header Host $remote_addr:$proxy_port;
151
+                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
152
+                proxy_set_header X-Real-IP $remote_addr;
153
+        }
154
+}
155
+```
156
+
157
+Finally, set up TLS certificates with `certbot --nginx`.
158
+Add this entry to the root crontab to renew the certs daily:
159
+
160
+```
161
+20 1 * * * certbot renew >/dev/null 2>&1 && systemctl restart nginx >/dev/null 2>&1
162
+```
163
+
164
+Please see the
165
+[Certbot docs](https://certbot.eff.org/docs/using.html)
166
+for more info.
167
+Also see the
168
+[OWASP Secure Headers Project](https://owasp.org/www-project-secure-headers/)
169
+for info on proper Nginx security.
170
+
171
+## MariaDB
172
+
173
+Install MariaDB with `apt install mariadb-server`
174
+and initialize it with `mysql_secure_installation`.
175
+
176
+Note that BioTorrents.de uses TLS connections to a dedicated database server.
177
+Unix sockets are preferred for the database running on localhost.
178
+The config should look similar to this, paying attention to `sql-mode`:
179
+
180
+```
181
+[client-server]
182
+# Port or socket location where to connect
183
+port = 3306
184
+#socket = /var/run/mysqld/mysqld.sock
185
+
186
+# Import all .cnf files from configuration directory
187
+#!includedir /etc/mysql/conf.d/
188
+#!includedir /etc/mysql/mariadb.conf.d/
189
+
190
+[mariadb]
191
+# https://mariadb.com/kb/en/secure-connections-overview/
192
+tls-version = TLSv1.3
193
+#require-secure-transport = on
194
+
195
+# https://mariadb.com/kb/en/securing-connections-for-client-and-server/
196
+ssl-cert=/etc/mysql/ssl/server-cert.pem
197
+ssl-key=/etc/mysql/ssl/server-key.pem
198
+ssl-ca=/etc/mysql/ssl/ca.pem
199
+
200
+# https://mariadb.com/kb/en/configuring-mariadb-for-remote-client-access/
201
+skip-networking = 0
202
+bind-address = 10.0.0.3
203
+
204
+# https://johnemb.blogspot.com/2014/09/adding-or-removing-individual-sql-modes.html
205
+sql-mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
206
+```
207
+
208
+If you'd like to use TLS crypto in your database connections,
209
+[please see the MariaDB docs](https://mariadb.com/kb/en/securing-connections-for-client-and-server/).
210
+They contain the necessary info to generate self-signed certs.
211
+
212
+Finally, load the Gazelle database schema in an SQL shell.
213
+I prefer to generate secure passphrases with `pwgen -s | encrypt`.
214
+
215
+```mysql
216
+CREATE DATABASE gazelle_development;
217
+USE gazelle_development;
218
+SOURCE /var/www/html/dev.biotorrents.de/gazelle.sql;
219
+CREATE USER 'gazelle_development'@'localhost' IDENTIFIED BY '';
220
+GRANT ALL PRIVILEGES ON `gazelle_development`.* TO 'gazelle_development'@'localhost';
221
+```
222
+
223
+## PHP
224
+
225
+Install PHP and the necessary extensions.
226
+The basic PHP package:
227
+`apt install php php-dev php-fpm`.
228
+
229
+The PHP extensions.
230
+Note that there are two PHP memcached extensions.
231
+The correct one is just `php-memcache` without the "d."
232
+Your distro may require other extensions:
233
+`php-apcu php-mbstring php-memcache php-mysql`.
234
+
235
+BioTorrents.de also supports the
236
+[Seqhash algorithm](https://blog.libredna.org/post/seqhash/)
237
+and requires Blake3 hash support for this feature.
238
+Optionally, please install
239
+[php-blake3](https://github.com/cypherbits/php-blake3).
240
+
241
+Gazelle isn't picky about its PHP config needs,
242
+except that `short_open_tag = On` is still required.
243
+I strongly recommend crafting a
244
+[secure PHP config](https://cheatsheetseries.owasp.org/cheatsheets/PHP_Configuration_Cheat_Sheet.html).
245
+
246
+## memcached
247
+
248
+Install memcached with `apt install memcached`.
249
+
250
+BioTorrents.de supports separate production and development instances.
251
+If you with to run two instances, it's necessary to run two memcached sockets.
252
+Otherwise the sites will experience significant data cross-contamination.
253
+The required `/etc/memcached.conf` content:
254
+
255
+```
256
+-d
257
+-m 5120
258
+-s /var/run/memcached/memcached.sock
259
+-a 0777
260
+-t16
261
+-C
262
+-u memcache
263
+```
264
+
265
+A helper script to quickly bring up a second memcached as root:
266
+
267
+```shell
268
+#!/bin/bash
269
+memcached -d -m 5120 -s /var/run/memcached/memcached-dev.sock -a 0777 -t16 -C -u memcache
270
+```
271
+
272
+## Sphinx
273
+
274
+Install Sphinx with `apt install sphinxsearch`.
275
+
276
+The `/etc/sphinxsearch/sphinx.conf` content is too large to reasonably inline.
277
+Please find a copy at
278
+[biotorrents/documentation](https://github.com/biotorrents/documentation/blob/master/sphinx.conf).
279
+The only other Sphinx-related configs are root crontab entries:
280
+
281
+```crontab
282
+@reboot /usr/bin/searchd`.
283
+* * * * * indexer -c /etc/sphinxsearch/sphinx.conf --rotate delta requests_delta >/dev/null 2>&1
284
+7 * * * * indexer -c /etc/sphinxsearch/sphinx.conf --rotate torrents >/dev/null 2>&1
285
+7 0,12 * * * indexer -c /etc/sphinxsearch/sphinx.conf --rotate --all >/dev/null 2>&1
286
+```
287
+
288
+## Email
289
+
290
+Email setup is beyond this guide's scope.
291
+Please see
292
+[Gilles's OpenSMTPd and Dovecot guide](https://poolp.org/posts/2019-09-14/setting-up-a-mail-server-with-opensmtpd-dovecot-and-rspamd/).
293
+
294
+# Application setup
295
+
296
+This section should use a separate Unix user for each component.
297
+Gazelle, Ocelot, IRC, and sitebot should each have a distinct home folder and full shell.
298
+The applications would otherwise be an insecure jumble and hard to maintain.
299
+
300
+## Gazelle
301
+
302
+First create the necessary files and folders.
303
+Note that locations are arbitrary and may be one of:
304
+home folder, subfolder of `/var/www`, etc.
305
+
306
+```shell
307
+# nginx(8) log location
308
+mkdir -m 700 -p /var/www/log/{development,production}
309
+touch /var/www/log/production/{peerupdate.log,schedule.log}
310
+touch /var/www/log/development/{peerupdate.log,schedule.log}
311
+chown -R biotorrents:biotorrents /var/www/log
312
+
313
+# files outside the web root
314
+mkdir -m 700 -p /var/www/pictures /var/www/torrents
315
+chown -R www-data:www-data /var/www/pictures /var/www/torrents /var/www/torrents-dev
316
+```
317
+
318
+The Gazelle app user also needs this crontab.
319
+Expect to have backups in place by this stage,
320
+and note that server backups are beyond this guide's scope:
321
+
322
+```crontab
323
+0,15,30,45 * * * * curl -s "https://dev.biotorrents.de/schedule.php?key=00000000000000000000000000000000" >> /var/www/log/development/schedule.log 2>&1
324
+2-59/5 * * * * php /var/www/html/dev.biotorrents.de/peerupdate.php "00000000000000000000000000000000" >> /var/www/log/development/peerupdate.log
325
+```
326
+
327
+A useful script for resetting file permissions:
328
+
329
+```shell
330
+#!/bin/sh
331
+find . -type f -print0 | xargs -0 chmod 0644
332
+find . -type d -print0 | xargs -0 chmod 0755
333
+```
334
+
335
+### Gazelle app config
336
+
337
+[`classes/config.php`](https://github.com/biotorrents/gazelle/blob/development/classes/config.template.php)
338
+warrants its own section.
339
+When setting up Gazelle for the first time, these options must be enabled.
340
+
341
+- `'DEBUG_MODE' = false`
342
+- `'OPEN_REGISTRATION' = true`
343
+- `'FEATURE_SET_ENC_KEY_PUBLIC' = true`
344
+
345
+Note the separate production and development values and the possibility of duplicate definitions.
346
+BioTorrents.de uses a singleton class with extended recursive ArrayObject support invoked by
347
+[$ENV = ENV::go()](https://github.com/biotorrents/gazelle/blob/development/classes/env.class.php).
348
+
349
+There are some other values to set up.
350
+Please pay attention to these values that Gazelle needs for proper function:
351
+
352
+- `SITE_DOMAIN` and `IMAGE_DOMAIN`
353
+- `WEB_ROOT` and `SERVER_ROOT`
354
+- `TORRENT_STORE` and `STATIC_SERVER`
355
+- The "App keys" and "Database" sections
356
+- The "Tracker" and "Tracker URLs" sections
357
+- `MEMCACHED_SERVERS`
358
+
359
+### Composer
360
+
361
+Assuming that `php.ini` is correctly set up,
362
+you may need these modified setup instructions from the
363
+[official Composer docs](https://getcomposer.org/download/):
364
+
365
+```shell
366
+mkdir -p /var/www/bin
367
+php -d allow_url_fopen=1 -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
368
+# Hash checking, running the install script, and unlinking
369
+# See the official Composer docs for details
370
+mv composer.phar /var/www/bin/composer
371
+```
372
+
373
+Then add `/var/www/bin` to the Gazelle user's `$PATH` and run:
374
+`php composer.phar update`.
375
+
376
+### SCSS and fonts
377
+
378
+Install SassC with `apt install sassc`.
379
+
380
+[Download the font pack](https://docs.biotorrents.de/fonts.tgz)
381
+and extract it with:
382
+`tar zxvf fonts.tgz -C /var/www/html/dev.biotorrents.de/static/styles/assets/fonts`.
383
+
384
+Then install SassC with `apt install sassc`.
385
+This should be a for loop, to compile the CSS:
386
+
387
+```shell
388
+#!/bin/bash
389
+styles="/var/www/html/dev.biotorrents.de/static/styles"
390
+sassc "$styles/beluga/beluga.scss" > "$styles/beluga.css"
391
+sassc "$styles/bookish/bookish.scss" > "$styles/bookish.css"
392
+sassc "$styles/development/development.scss" > "$styles/development.css"
393
+sassc "$styles/genaviv/genaviv.scss" > "$styles/genaviv.css"
394
+sassc "$styles/global/global.scss" > "$styles/global.css"
395
+sassc "$styles/matcha/matcha.scss" > "$styles/matcha.css"
396
+sassc "$styles/oppai/oppai.scss" > "$styles/oppai.css"
397
+sassc "$styles/postmod/postmod.scss" > "$styles/postmod.css"
398
+sassc "$styles/public/public.scss" > "$styles/public.css"
399
+```
400
+
401
+## Ocelot
402
+
403
+BioTorrents.de uses What.CD's Ocelot with the
404
+[10th anniversary mixtape patches](https://twitter.com/whatcd/status/923942203080273921)
405
+and developing TLS support.
406
+The patched version is available at
407
+[biotorrents/ocelot](/biotorrents/ocelot).
408
+
409
+Then installed the dependencies like below.
410
+Note that specific dependencies may differ on your system.
411
+
412
+```shell
413
+apt install \
414
+	automake \
415
+	g++ \
416
+	gcc \
417
+	libboost-dev \
418
+	libboost-iostreams-dev \
419
+	libboost-system-dev \
420
+	libev-dev \
421
+	libmysql++-dev \
422
+	libtcmalloc-minimal4 \
423
+	make
424
+```
425
+
426
+The compilation ritual is likewise fraught with pitfalls.
427
+I found `autoreconf` with manual library locations to work best:
428
+
429
+```shell
430
+autoreconf
431
+./configure \
432
+	--with-boost-libdir=/usr/lib/x86_64-linux-gnu \
433
+	--with-ev-lib=/usr/lib/x86_64-linux-gnu \
434
+	--with-mysql-lib=/usr/lib/x86_64-linux-gnu \
435
+	--with-mysqlpp-lib=/usr/lib/x86_64-linux-gnu
436
+make
437
+make install
438
+```
439
+
440
+Copy `ocelot/ocelot.conf.dist`.
441
+The daemon runs on `localhost:34000` and Nginx TLS reverse proxies it to `localhost:443`.
442
+`ocelot.conf` lives in the Ocelot user's home folder and the daemon runs in a tmux window there.
443
+
444
+## IRC and kana (sitebot)
445
+
446
+Docs pending the completion of sitebot API integration.
447
+
448
+## Inside the Gazelle admin panel
449
+
450
+At this point it should be possible to register for the site.
451
+The first account is the sysop so please act quickly here.
452
+Disable `DEBUG_MODE` and `FEATURE_SET_ENC_KEY_PUBLIC` as soon as you register!
453
+Do `apt install qrencode` for 2FA support and enable it with a GPG key on the sysop account.
454
+
455
+Configure a client whitelist on the Toolbox page by the
456
+[BitTorrent spec's peer ID list](https://wiki.theory.org/index.php/BitTorrentSpecification#peer_id).
457
+Please find a list of quality client peer IDs below.
458
+Note that LibTorrent 0.1x.y also covers rTorrent/ruTorrent and other clients that use
459
+[rakshasa's library](https://github.com/rakshasa/libtorrent):
460
+
461
+| Client Name       | Peer ID |
462
+| :---------------- | :-----: |
463
+| Deluge 1.x.y      | `-DE1`  |
464
+| Deluge 2.x.y      | `-DE2`  |
465
+| KTorrent 3.x.y    | `-KT3`  |
466
+| KTorrent 4.x.y    | `-KT4`  |
467
+| KTorrent 5.x.y    | `-KT5`  |
468
+| LibTorrent 0.x.y  | `-lt0`  |
469
+| qBittorrent 2.x.y | `-qB2`  |
470
+| qBittorrent 3.x.y | `-qB3`  |
471
+| qBittorrent 4.x.y | `-qB4`  |
472
+| Transmission 2.xy | `-TR2`  |
473
+
474
+Most of the Toolbox pages don't write to the database and all of them should work.
475
+For more BitTorrents info see
476
+[Calomel's rTorrent hacking guide](https://calomel.org/rtorrent_mods.html).

+ 69
- 94
docs/meta.md View File

2
 
2
 
3
 Endpoints related to [BioTorrents.de](https://biotorrents.de) itself.
3
 Endpoints related to [BioTorrents.de](https://biotorrents.de) itself.
4
 
4
 
5
-
6
 ## Index
5
 ## Index
7
 
6
 
8
 Fetch basic site info from the homepage,
7
 Fetch basic site info from the homepage,
9
 e.g., your ratio and any unread notices.
8
 e.g., your ratio and any unread notices.
10
 
9
 
11
-
12
 **Request**
10
 **Request**
13
 
11
 
14
 `ajax.php?action=index`
12
 `ajax.php?action=index`
15
 
13
 
16
-
17
 **Response**
14
 **Response**
18
 
15
 
19
 ```json
16
 ```json
20
 {
17
 {
21
-    "status": "success",
22
-    "response": {
23
-        "username": "me",
24
-        "id": 2,
25
-        "authkey": "00000000000000000000000000000000",
26
-        "passkey": "00000000000000000000000000000000",
27
-        "notifications": {
28
-            "messages": 0,
29
-            "notifications": 0,
30
-            "newAnnouncement": false,
31
-            "newBlog": false,
32
-            "newSubscriptions": false
33
-        },
34
-        "userstats": {
35
-            "uploaded": 15918336971,
36
-            "downloaded": 2341094384,
37
-            "ratio": 6.79,
38
-            "requiredratio": 0,
39
-            "class": "Member"
40
-        }
18
+  "status": "success",
19
+  "response": {
20
+    "username": "me",
21
+    "id": 2,
22
+    "authkey": "00000000000000000000000000000000",
23
+    "passkey": "00000000000000000000000000000000",
24
+    "notifications": {
25
+      "messages": 0,
26
+      "notifications": 0,
27
+      "newAnnouncement": false,
28
+      "newBlog": false,
29
+      "newSubscriptions": false
30
+    },
31
+    "userstats": {
32
+      "uploaded": 15918336971,
33
+      "downloaded": 2341094384,
34
+      "ratio": 6.79,
35
+      "requiredratio": 0,
36
+      "class": "Member"
41
     }
37
     }
38
+  }
42
 }
39
 }
43
 ```
40
 ```
44
 
41
 
45
-
46
 ## Stats
42
 ## Stats
47
 
43
 
48
 Fetch the homepage sidebar info.
44
 Fetch the homepage sidebar info.
49
 
45
 
50
-
51
 **Request**
46
 **Request**
52
 
47
 
53
 `ajax.php?action=stats`
48
 `ajax.php?action=stats`
54
 
49
 
55
-
56
 **Response**
50
 **Response**
57
 
51
 
58
 ```json
52
 ```json
59
 {
53
 {
60
-    "status": "success",
61
-    "response": {
62
-        "maxUsers": 0,
63
-        "enabledUsers": 82,
64
-        "usersActiveThisDay": 5,
65
-        "usersActiveThisWeek": 10,
66
-        "usersActiveThisMonth": 19,
67
-        "torrentCount": 60,
68
-        "groupCount": 12,
69
-        "artistCount": 151,
70
-        "requestCount": 3,
71
-        "filledRequestCount": 0,
72
-        "seederCount": 225,
73
-        "leecherCount": 0
74
-    }
54
+  "status": "success",
55
+  "response": {
56
+    "maxUsers": 0,
57
+    "enabledUsers": 82,
58
+    "usersActiveThisDay": 5,
59
+    "usersActiveThisWeek": 10,
60
+    "usersActiveThisMonth": 19,
61
+    "torrentCount": 60,
62
+    "groupCount": 12,
63
+    "artistCount": 151,
64
+    "requestCount": 3,
65
+    "filledRequestCount": 0,
66
+    "seederCount": 225,
67
+    "leecherCount": 0
68
+  }
75
 }
69
 }
76
 ```
70
 ```
77
 
71
 
78
-
79
 ## Manifest
72
 ## Manifest
80
 
73
 
81
 Fetch an app manifest.
74
 Fetch an app manifest.
82
 
75
 
83
-
84
 **Request**
76
 **Request**
85
 
77
 
86
 `ajax.php?action=manifest`
78
 `ajax.php?action=manifest`
87
 
79
 
88
-
89
 **Response**
80
 **Response**
90
 
81
 
91
 ```json
82
 ```json
92
 {
83
 {
93
-    "status": "success",
94
-    "response": {
95
-        "name": "BioTorrents.de",
96
-        "short_name": "BioTorrents.de",
97
-        "description": "A platform to share biological sequence and medical imaging data",
98
-        "start_url": "index.php",
99
-        "display": "standalone",
100
-        "background_color": "#ffffff",
101
-        "theme_color": "#0288d1",
102
-        "icons": [
103
-            {
104
-                "src": "/static/common/icon.png",
105
-                "sizes": "120x120",
106
-                "type": "image/png"
107
-            }
108
-        ]
109
-    }
84
+  "status": "success",
85
+  "response": {
86
+    "name": "BioTorrents.de",
87
+    "short_name": "BioTorrents.de",
88
+    "description": "A platform to share biological sequence and medical imaging data",
89
+    "start_url": "index.php",
90
+    "display": "standalone",
91
+    "background_color": "#ffffff",
92
+    "theme_color": "#0288d1",
93
+    "icons": [
94
+      {
95
+        "src": "/static/common/icon.png",
96
+        "sizes": "120x120",
97
+        "type": "image/png"
98
+      }
99
+    ]
100
+  }
110
 }
101
 }
111
 ```
102
 ```
112
 
103
 
113
-
114
 ## Load average
104
 ## Load average
115
 
105
 
116
 Requires moderator permissions to access without error.
106
 Requires moderator permissions to access without error.
119
 
109
 
120
 `ajax.php?action=loadavg`
110
 `ajax.php?action=loadavg`
121
 
111
 
122
-
123
 **Response**
112
 **Response**
124
 
113
 
125
 ```json
114
 ```json
126
 {
115
 {
127
-    "status": "success",
128
-    "response": {
129
-        "loadAverage": [
130
-            0.11,
131
-            0.06,
132
-            0.02
133
-        ]
134
-    }
116
+  "status": "success",
117
+  "response": {
118
+    "loadAverage": [0.11, 0.06, 0.02]
119
+  }
135
 }
120
 }
136
 ```
121
 ```
137
 
122
 
138
-
139
 **Error**
123
 **Error**
140
 
124
 
141
 `Invalid authorization key. Go back, refresh, and try again.`
125
 `Invalid authorization key. Go back, refresh, and try again.`
142
 
126
 
143
-
144
-## Announcements 
127
+## Announcements
145
 
128
 
146
 Fetch the recent news and blogs.
129
 Fetch the recent news and blogs.
147
 
130
 
148
-
149
 **Request**
131
 **Request**
150
 
132
 
151
 `ajax.php?action=announcements`
133
 `ajax.php?action=announcements`
152
 
134
 
153
-
154
 **Response**
135
 **Response**
155
 
136
 
156
 ```json
137
 ```json
194
 }
175
 }
195
 ```
176
 ```
196
 
177
 
197
-
198
 ## Wiki
178
 ## Wiki
199
 
179
 
200
 Either `id` or `name` is required.
180
 Either `id` or `name` is required.
201
 
181
 
202
-
203
 **Request**
182
 **Request**
204
 
183
 
205
 `ajax.php?action=wiki`
184
 `ajax.php?action=wiki`
208
 
187
 
209
 `&name=` — page alias to display
188
 `&name=` — page alias to display
210
 
189
 
211
-
212
 **Response**
190
 **Response**
213
 
191
 
214
 ```json
192
 ```json
215
 {
193
 {
216
-    "status": "success",
217
-    "response": {
218
-        "title": "User Classes",
219
-        "bbBody": "BBcode",
220
-        "body": "HTML",
221
-        "aliases": "userclasses",
222
-        "authorID": 1,
223
-        "authorName": "ohm",
224
-        "date": "2020-11-13 18:46:06",
225
-        "revision": 10
226
-    }
194
+  "status": "success",
195
+  "response": {
196
+    "title": "User Classes",
197
+    "bbBody": "BBcode",
198
+    "body": "HTML",
199
+    "aliases": "userclasses",
200
+    "authorID": 1,
201
+    "authorName": "ohm",
202
+    "date": "2020-11-13 18:46:06",
203
+    "revision": 10
204
+  }
227
 }
205
 }
228
 ```
206
 ```
229
 
207
 
230
-
231
 ## Ontology
208
 ## Ontology
232
 
209
 
233
 Fetch a site metadata blueprint.
210
 Fetch a site metadata blueprint.
234
 
211
 
235
-
236
 **Request**
212
 **Request**
237
 
213
 
238
 `ajax.php?action=ontology`
214
 `ajax.php?action=ontology`
239
 
215
 
240
-
241
 **Response**
216
 **Response**
242
 
217
 
243
 ```json
218
 ```json
274
                     },
249
                     },
275
                     "APML": {
250
                     "APML": {
276
                         "0": "apml"
251
                         "0": "apml"
277
-                    },		    
252
+                    },
278
                     # etc.
253
                     # etc.
279
                 },
254
                 },
280
 		# etc.
255
 		# etc.

+ 126
- 151
docs/torrents.md View File

2
 
2
 
3
 Endpoints related to torrents.
3
 Endpoints related to torrents.
4
 
4
 
5
-
6
 ## Torrent
5
 ## Torrent
7
 
6
 
8
 **Request**
7
 **Request**
13
 
12
 
14
 `&hash=` — torrent's hash (must be uppercase)
13
 `&hash=` — torrent's hash (must be uppercase)
15
 
14
 
16
-
17
 **Response**
15
 **Response**
18
 
16
 
19
 ```json
17
 ```json
20
 {
18
 {
21
-    "status": "success",
22
-    "response": {
23
-        "group": {
24
-            "description": "HTML",
25
-            "picture": "https://i.imgur.com/sF40cxi.png",
26
-            "id": 1,
27
-            "name": "Alcohol dehydrogenase ADH1",
28
-            "organism": "Saccharomyces cerevisiae",
29
-            "strain": "S288C",
30
-            "authors": [
31
-                {
32
-                    "id": 2,
33
-                    "name": "David Schild"
34
-                },
35
-                {
36
-                    "id": 1,
37
-                    "name": "Robert K. Mortimer"
38
-                }
39
-            ],
40
-            "year": 1985,
41
-            "accession": "YOL086C",
42
-            "categoryId": 1,
43
-            "categoryName": "Sequences",
44
-            "time": "2019-12-10 01:48:07",
45
-            "isBookmarked": false,
46
-            "tags": [
47
-                "coding",
48
-                "fungi",
49
-                "one.shot",
50
-                "organic.chemistry",
51
-                "protocol.available"
52
-            ]
19
+  "status": "success",
20
+  "response": {
21
+    "group": {
22
+      "description": "HTML",
23
+      "picture": "https://i.imgur.com/sF40cxi.png",
24
+      "id": 1,
25
+      "name": "Alcohol dehydrogenase ADH1",
26
+      "organism": "Saccharomyces cerevisiae",
27
+      "strain": "S288C",
28
+      "authors": [
29
+        {
30
+          "id": 2,
31
+          "name": "David Schild"
53
         },
32
         },
54
-        "torrent": {
55
-            "id": 1,
56
-            "infoHash": "6A5413B9A0C5EF5B68BED6ABBB8112CBE3870647",
57
-            "platform": "Sanger",
58
-            "format": "FASTA",
59
-            "license": "Public Domain",
60
-            "scope": "Contig",
61
-            "annotated": false,
62
-            "archive": "None",
63
-            "fileCount": 4,
64
-            "size": 5754,
65
-            "seeders": 5,
66
-            "leechers": 0,
67
-            "snatched": 3,
68
-            "freeTorrent": false,
69
-            "reported": false,
70
-            "time": "2019-12-10 01:48:08",
71
-            "description": "HTML",
72
-            "fileList": "S288C_YOL086C_ADH1_coding.fsa{{{1095}}}|||S288C_YOL086C_ADH1_flanking.fsa{{{3157}}}|||S288C_YOL086C_ADH1_genomic.fsa{{{1117}}}|||S288C_YOL086C_ADH1_protein.fsa{{{385}}}",
73
-            "filePath": "ADH1 - YOL086C",
74
-            "userId": 0,
75
-            "username": "Anonymous"
33
+        {
34
+          "id": 1,
35
+          "name": "Robert K. Mortimer"
76
         }
36
         }
37
+      ],
38
+      "year": 1985,
39
+      "accession": "YOL086C",
40
+      "categoryId": 1,
41
+      "categoryName": "Sequences",
42
+      "time": "2019-12-10 01:48:07",
43
+      "isBookmarked": false,
44
+      "tags": [
45
+        "coding",
46
+        "fungi",
47
+        "one.shot",
48
+        "organic.chemistry",
49
+        "protocol.available"
50
+      ]
51
+    },
52
+    "torrent": {
53
+      "id": 1,
54
+      "infoHash": "6A5413B9A0C5EF5B68BED6ABBB8112CBE3870647",
55
+      "platform": "Sanger",
56
+      "format": "FASTA",
57
+      "license": "Public Domain",
58
+      "scope": "Contig",
59
+      "annotated": false,
60
+      "archive": "None",
61
+      "fileCount": 4,
62
+      "size": 5754,
63
+      "seeders": 5,
64
+      "leechers": 0,
65
+      "snatched": 3,
66
+      "freeTorrent": false,
67
+      "reported": false,
68
+      "time": "2019-12-10 01:48:08",
69
+      "description": "HTML",
70
+      "fileList": "S288C_YOL086C_ADH1_coding.fsa{{{1095}}}|||S288C_YOL086C_ADH1_flanking.fsa{{{3157}}}|||S288C_YOL086C_ADH1_genomic.fsa{{{1117}}}|||S288C_YOL086C_ADH1_protein.fsa{{{385}}}",
71
+      "filePath": "ADH1 - YOL086C",
72
+      "userId": 0,
73
+      "username": "Anonymous"
77
     }
74
     }
75
+  }
78
 }
76
 }
79
 ```
77
 ```
80
 
78
 
81
-
82
 ## Torrent group
79
 ## Torrent group
83
 
80
 
84
 **Request**
81
 **Request**
89
 
86
 
90
 `&hash=` — hash of a torrent in the torrent group (must be uppercase)
87
 `&hash=` — hash of a torrent in the torrent group (must be uppercase)
91
 
88
 
92
-
93
 **Response**
89
 **Response**
94
 
90
 
95
 ```json
91
 ```json
160
 }
156
 }
161
 ```
157
 ```
162
 
158
 
163
-
164
 ## Browse (search)
159
 ## Browse (search)
165
 
160
 
166
 Note that [BioTorrents.de](https://biotorrents.de) still uses Oppaitime metadata behind the scenes.
161
 Note that [BioTorrents.de](https://biotorrents.de) still uses Oppaitime metadata behind the scenes.
167
 These docs are also adapted from What.CD, an older and different distribution.
162
 These docs are also adapted from What.CD, an older and different distribution.
168
 The advanced search options are certain to change in the future.
163
 The advanced search options are certain to change in the future.
169
 
164
 
170
-
171
 **Request**
165
 **Request**
172
 
166
 
173
 `ajax.php?action=browse`
167
 `ajax.php?action=browse`
178
 
172
 
179
 `taglist`, `tags_type`, `order_by`, `order_way`, `filter_cat`, `freetorrent`, `vanityhouse`, `scene`, `haslog`, `releasetype`, `media`, `format`, `encoding`, `artistname`, `filelist`, `groupname`, `recordlabel`, `cataloguenumber`, `year`, `remastertitle`, `remasteryear`, `remasterrecordlabel`, `remastercataloguenumber` — as in advanced search
173
 `taglist`, `tags_type`, `order_by`, `order_way`, `filter_cat`, `freetorrent`, `vanityhouse`, `scene`, `haslog`, `releasetype`, `media`, `format`, `encoding`, `artistname`, `filelist`, `groupname`, `recordlabel`, `cataloguenumber`, `year`, `remastertitle`, `remasteryear`, `remasterrecordlabel`, `remastercataloguenumber` — as in advanced search
180
 
174
 
181
-
182
 **Response**
175
 **Response**
183
 
176
 
184
 ```json
177
 ```json
252
 }
245
 }
253
 ```
246
 ```
254
 
247
 
255
-
256
-## Comments 
248
+## Comments
257
 
249
 
258
 Fetch comments from torrent pages.
250
 Fetch comments from torrent pages.
259
 
251
 
260
-
261
 **Request**
252
 **Request**
262
 
253
 
263
 `ajax.php?action=tcomments`
254
 `ajax.php?action=tcomments`
264
 
255
 
265
 `&id=` — torrent's id (required)
256
 `&id=` — torrent's id (required)
266
 
257
 
267
-
268
 **Response**
258
 **Response**
269
 
259
 
270
 ```json
260
 ```json
299
 }
289
 }
300
 ```
290
 ```
301
 
291
 
302
-
303
 # Torrent features
292
 # Torrent features
304
 
293
 
305
 Various features around the torrents themselves.
294
 Various features around the torrents themselves.
312
 
301
 
313
 `&id=` — collage's id (required)
302
 `&id=` — collage's id (required)
314
 
303
 
315
-
316
 **Response**
304
 **Response**
317
 
305
 
318
 ```json
306
 ```json
373
 }
361
 }
374
 ```
362
 ```
375
 
363
 
376
-
377
-## Artist 
364
+## Artist
378
 
365
 
379
 Under construction as of 2020-11-24.
366
 Under construction as of 2020-11-24.
380
 Currently not returning the artist's torrent groups.
367
 Currently not returning the artist's torrent groups.
381
 Please see the response below for details.
368
 Please see the response below for details.
382
 
369
 
383
-
384
 **Request**
370
 **Request**
385
 
371
 
386
 `ajax.php?action=artist`
372
 `ajax.php?action=artist`
391
 
377
 
392
 `&artistreleases=` — if set, only include groups where the artist is the main artist
378
 `&artistreleases=` — if set, only include groups where the artist is the main artist
393
 
379
 
394
-
395
 **Response**
380
 **Response**
396
 
381
 
397
 ```json
382
 ```json
398
 {
383
 {
399
-    "status": "success",
400
-    "response": {
401
-        "id": 94,
402
-        "name": "Jackie Treehorn",
403
-        "notificationsEnabled": false,
404
-        "hasBookmarked": false,
405
-        "image": "",
406
-        "body": "",
407
-        "vanityHouse": false,
408
-        "tags": [],
409
-        "statistics": {
410
-            "numGroups": 0,
411
-            "numTorrents": 0,
412
-            "numSeeders": 0,
413
-            "numLeechers": 0,
414
-            "numSnatches": 0
415
-        },
416
-        "torrentgroup": [],
417
-        "requests": []
418
-    }
384
+  "status": "success",
385
+  "response": {
386
+    "id": 94,
387
+    "name": "Jackie Treehorn",
388
+    "notificationsEnabled": false,
389
+    "hasBookmarked": false,
390
+    "image": "",
391
+    "body": "",
392
+    "vanityHouse": false,
393
+    "tags": [],
394
+    "statistics": {
395
+      "numGroups": 0,
396
+      "numTorrents": 0,
397
+      "numSeeders": 0,
398
+      "numLeechers": 0,
399
+      "numSnatches": 0
400
+    },
401
+    "torrentgroup": [],
402
+    "requests": []
403
+  }
419
 }
404
 }
420
 ```
405
 ```
421
 
406
 
422
-
423
 ## Request
407
 ## Request
424
 
408
 
425
 **Request**
409
 **Request**
430
 
414
 
431
 `&page=` — page of the comments to display (default: last page)
415
 `&page=` — page of the comments to display (default: last page)
432
 
416
 
433
-
434
 **Response**
417
 **Response**
435
 
418
 
436
 ```json
419
 ```json
437
 {
420
 {
438
-    "status": "success",
439
-    "response": {
440
-        "requestId": 2,
441
-        "requestorId": 2,
442
-        "requestorName": "me",
443
-        "isBookmarked": false,
444
-        "requestTax": 0.1,
445
-        "timeAdded": "2020-04-23 02:02:37",
446
-        "canEdit": true,
447
-        "canVote": true,
448
-        "minimumVote": 20971520,
449
-        "voteCount": 1,
450
-        "lastVote": "2020-11-15 06:51:56",
451
-        "topContributors": [
452
-            {
453
-                "userId": 2,
454
-                "userName": "me",
455
-                "bounty": 15461882266
456
-            }
457
-        ],
458
-        "totalBounty": 15461882266,
459
-        "categoryId": 10,
460
-        "categoryName": "Models",
461
-        "title": "Markov State Model Database of Protein Folding Datasets",
462
-        "year": 0,
463
-        "image": "",
464
-        "bbDescription": "BBcode",
465
-        "description": "HTML",
466
-        "artists": [
467
-            {
468
-                "id": 88,
469
-                "name": "Thomas Lane"
470
-            }
471
-        ],
472
-        "isFilled": false,
473
-        "fillerId": 0,
474
-        "fillerName": "",
475
-        "torrentId": 0,
476
-        "timeFilled": "",
477
-        "tags": [
478
-            "coding",
479
-            "proteomics",
480
-            "biochemistry",
481
-            "data.science",
482
-            "gene.expression"
483
-        ],
484
-        "comments": [],
485
-        "commentPage": 1,
486
-        "commentPages": 0
487
-    }
421
+  "status": "success",
422
+  "response": {
423
+    "requestId": 2,
424
+    "requestorId": 2,
425
+    "requestorName": "me",
426
+    "isBookmarked": false,
427
+    "requestTax": 0.1,
428
+    "timeAdded": "2020-04-23 02:02:37",
429
+    "canEdit": true,
430
+    "canVote": true,
431
+    "minimumVote": 20971520,
432
+    "voteCount": 1,
433
+    "lastVote": "2020-11-15 06:51:56",
434
+    "topContributors": [
435
+      {
436
+        "userId": 2,
437
+        "userName": "me",
438
+        "bounty": 15461882266
439
+      }
440
+    ],
441
+    "totalBounty": 15461882266,
442
+    "categoryId": 10,
443
+    "categoryName": "Models",
444
+    "title": "Markov State Model Database of Protein Folding Datasets",
445
+    "year": 0,
446
+    "image": "",
447
+    "bbDescription": "BBcode",
448
+    "description": "HTML",
449
+    "artists": [
450
+      {
451
+        "id": 88,
452
+        "name": "Thomas Lane"
453
+      }
454
+    ],
455
+    "isFilled": false,
456
+    "fillerId": 0,
457
+    "fillerName": "",
458
+    "torrentId": 0,
459
+    "timeFilled": "",
460
+    "tags": [
461
+      "coding",
462
+      "proteomics",
463
+      "biochemistry",
464
+      "data.science",
465
+      "gene.expression"
466
+    ],
467
+    "comments": [],
468
+    "commentPage": 1,
469
+    "commentPages": 0
470
+  }
488
 }
471
 }
489
 ```
472
 ```
490
 
473
 
491
-
492
 ## Request search
474
 ## Request search
493
 
475
 
494
 If no arguments are specified then the most recent requests are shown.
476
 If no arguments are specified then the most recent requests are shown.
495
 
477
 
496
-
497
 **Request**
478
 **Request**
498
 
479
 
499
 `ajax.php?action=requests`
480
 `ajax.php?action=requests`
510
 
491
 
511
 `filter_cat[]`, `releases[]`, `bitrates[]`, `formats[]`, `media[]` — as used on requests.php
492
 `filter_cat[]`, `releases[]`, `bitrates[]`, `formats[]`, `media[]` — as used on requests.php
512
 
493
 
513
-
514
 **Response**
494
 **Response**
515
 
495
 
516
 ```json
496
 ```json
557
 }
537
 }
558
 ```
538
 ```
559
 
539
 
560
-
561
 ## Top 10
540
 ## Top 10
562
 
541
 
563
 Fetch the Top 10 torrents, tags, or users.
542
 Fetch the Top 10 torrents, tags, or users.
564
 
543
 
565
-
566
 ### Torrents
544
 ### Torrents
567
 
545
 
568
 **Request**
546
 **Request**
573
 
551
 
574
 `&type=` — one of: torrents, tags, users (default: `torrents`)
552
 `&type=` — one of: torrents, tags, users (default: `torrents`)
575
 
553
 
576
-
577
 **Response**
554
 **Response**
578
 
555
 
579
 ```json
556
 ```json
709
 }
686
 }
710
 ```
687
 ```
711
 
688
 
712
-
713
 ### Tags
689
 ### Tags
714
 
690
 
715
 ```json
691
 ```json
760
 }
736
 }
761
 ```
737
 ```
762
 
738
 
763
-
764
 ### Users
739
 ### Users
765
 
740
 
766
 Usernames are masked to `null` in the output unless you have moderator permissions.
741
 Usernames are masked to `null` in the output unless you have moderator permissions.

+ 66
- 94
docs/users.md View File

2
 
2
 
3
 Endpoints related to user accounts.
3
 Endpoints related to user accounts.
4
 
4
 
5
-
6
 ## User
5
 ## User
7
 
6
 
8
 If you're viewing your own account, `personal->passkey` will be shown.
7
 If you're viewing your own account, `personal->passkey` will be shown.
9
 
8
 
10
-
11
 **Request**
9
 **Request**
12
 
10
 
13
 `ajax.php?action=user`
11
 `ajax.php?action=user`
14
 
12
 
15
 `&id=` — id of the user to display (required)
13
 `&id=` — id of the user to display (required)
16
 
14
 
17
-
18
 **Response**
15
 **Response**
19
 
16
 
20
 ```json
17
 ```json
21
 {
18
 {
22
-    "status": "success",
23
-    "response": {
24
-        "username": "eva",
25
-        "avatar": "https://ptpimg.me/1x1h48.png",
26
-        "isFriend": false,
27
-        "profileText": "",
28
-        "stats": {
29
-            "joinedDate": "2020-03-08 14:27:59",
30
-            "lastAccess": "2020-11-24 15:25:17",
31
-            "uploaded": 2192870833,
32
-            "downloaded": 1244283888,
33
-            "ratio": 1.76235,
34
-            "requiredRatio": 0
35
-        },
36
-        "ranks": {
37
-            "uploaded": 0,
38
-            "downloaded": 2,
39
-            "uploads": 0,
40
-            "requests": 0,
41
-            "bounty": 0,
42
-            "posts": 2,
43
-            "artists": 0,
44
-            "overall": 0
45
-        },
46
-        "personal": {
47
-            "class": "Donor",
48
-            "paranoia": 0,
49
-            "paranoiaText": "Off",
50
-            "donor": false,
51
-            "warned": false,
52
-            "enabled": true,
53
-            "passkey": ""
54
-        },
55
-        "community": {
56
-            "posts": 4,
57
-            "torrentComments": 0,
58
-            "artistComments": 0,
59
-            "collageComments": 0,
60
-            "requestComments": 0,
61
-            "collagesStarted": 1,
62
-            "collagesContrib": 1,
63
-            "requestsFilled": 0,
64
-            "bountyEarned": 0,
65
-            "requestsVoted": 0,
66
-            "bountySpent": 0,
67
-            "uploaded": 0,
68
-            "groups": 0,
69
-            "seeding": 0,
70
-            "leeching": 0,
71
-            "snatched": 7,
72
-            "invited": 0,
73
-            "artistsAdded": 0
74
-        }
19
+  "status": "success",
20
+  "response": {
21
+    "username": "eva",
22
+    "avatar": "https://ptpimg.me/1x1h48.png",
23
+    "isFriend": false,
24
+    "profileText": "",
25
+    "stats": {
26
+      "joinedDate": "2020-03-08 14:27:59",
27
+      "lastAccess": "2020-11-24 15:25:17",
28
+      "uploaded": 2192870833,
29
+      "downloaded": 1244283888,
30
+      "ratio": 1.76235,
31
+      "requiredRatio": 0
32
+    },
33
+    "ranks": {
34
+      "uploaded": 0,
35
+      "downloaded": 2,
36
+      "uploads": 0,
37
+      "requests": 0,
38
+      "bounty": 0,
39
+      "posts": 2,
40
+      "artists": 0,
41
+      "overall": 0
42
+    },
43
+    "personal": {
44
+      "class": "Donor",
45
+      "paranoia": 0,
46
+      "paranoiaText": "Off",
47
+      "donor": false,
48
+      "warned": false,
49
+      "enabled": true,
50
+      "passkey": ""
51
+    },
52
+    "community": {
53
+      "posts": 4,
54
+      "torrentComments": 0,
55
+      "artistComments": 0,
56
+      "collageComments": 0,
57
+      "requestComments": 0,
58
+      "collagesStarted": 1,
59
+      "collagesContrib": 1,
60
+      "requestsFilled": 0,
61
+      "bountyEarned": 0,
62
+      "requestsVoted": 0,
63
+      "bountySpent": 0,
64
+      "uploaded": 0,
65
+      "groups": 0,
66
+      "seeding": 0,
67
+      "leeching": 0,
68
+      "snatched": 7,
69
+      "invited": 0,
70
+      "artistsAdded": 0
75
     }
71
     }
72
+  }
76
 }
73
 }
77
 ```
74
 ```
78
 
75
 
79
-
80
-## User search 
76
+## User search
81
 
77
 
82
 **Request**
78
 **Request**
83
 
79
 
87
 
83
 
88
 `&page=` — page to display (default: `1`)
84
 `&page=` — page to display (default: `1`)
89
 
85
 
90
-
91
 **Response**
86
 **Response**
92
 
87
 
93
 ```json
88
 ```json
122
 }
117
 }
123
 ```
118
 ```
124
 
119
 
125
-
126
-## Community stats 
120
+## Community stats
127
 
121
 
128
 **Request**
122
 **Request**
129
 
123
 
131
 
125
 
132
 `&userid=` — id of the user to display (required)
126
 `&userid=` — id of the user to display (required)
133
 
127
 
134
-
135
 **Response**
128
 **Response**
136
 
129
 
137
 ```json
130
 ```json
138
 {
131
 {
139
-    "status": "success",
140
-    "response": {
141
-        "leeching": 0,
142
-        "seeding": "60",
143
-        "snatched": "3",
144
-        "usnatched": false,
145
-        "downloaded": false,
146
-        "udownloaded": false,
147
-        "seedingperc": 100
148
-    }
132
+  "status": "success",
133
+  "response": {
134
+    "leeching": 0,
135
+    "seeding": "60",
136
+    "snatched": "3",
137
+    "usnatched": false,
138
+    "downloaded": false,
139
+    "udownloaded": false,
140
+    "seedingperc": 100
141
+  }
149
 }
142
 }
150
 ```
143
 ```
151
 
144
 
152
-
153
 ## Recents (torrents)
145
 ## Recents (torrents)
154
 
146
 
155
 This endpoint circumvents the "upload anonymously" feature.
147
 This endpoint circumvents the "upload anonymously" feature.
156
 Various features of the response will likely change in the future.
148
 Various features of the response will likely change in the future.
157
 
149
 
158
-
159
 **Request**
150
 **Request**
160
 
151
 
161
 `ajax.php?action=user_recents`
152
 `ajax.php?action=user_recents`
164
 
155
 
165
 `&limit=` — how many recent torrents to fetch
156
 `&limit=` — how many recent torrents to fetch
166
 
157
 
167
-
168
 **Response**
158
 **Response**
169
 
159
 
170
 ```json
160
 ```json
220
 }
210
 }
221
 ```
211
 ```
222
 
212
 
223
-
224
 ## History (community)
213
 ## History (community)
225
 
214
 
226
 **Request**
215
 **Request**
229
 
218
 
230
 `&userid=` — id of user (required)
219
 `&userid=` — id of user (required)
231
 
220
 
232
-
233
 **Response**
221
 **Response**
234
 
222
 
235
 ```json
223
 ```json
270
 }
258
 }
271
 ```
259
 ```
272
 
260
 
273
-
274
 # Your account
261
 # Your account
275
 
262
 
276
 Endpoints that only fetch info about your own account.
263
 Endpoints that only fetch info about your own account.
277
 
264
 
278
-
279
 ## Inbox
265
 ## Inbox
280
 
266
 
281
 The current example isn't from the [BioTorrents.de](https://biotorrents.de) database.
267
 The current example isn't from the [BioTorrents.de](https://biotorrents.de) database.
282
 
268
 
283
-
284
 **Request**
269
 **Request**
285
 
270
 
286
 `ajax.php?action=inbox`
271
 `ajax.php?action=inbox`
295
 
280
 
296
 `&type=` — one of: inbox or sentbox (default: `inbox`)
281
 `&type=` — one of: inbox or sentbox (default: `inbox`)
297
 
282
 
298
-
299
 **Response**
283
 **Response**
300
 
284
 
301
 ```json
285
 ```json
325
 }
309
 }
326
 ```
310
 ```
327
 
311
 
328
-
329
-## Conversation 
312
+## Conversation
330
 
313
 
331
 The current example isn't from the [BioTorrents.de](https://biotorrents.de) database.
314
 The current example isn't from the [BioTorrents.de](https://biotorrents.de) database.
332
 
315
 
333
-
334
 **Request**
316
 **Request**
335
 
317
 
336
 `ajax.php?action=inbox&type=viewconv`
318
 `ajax.php?action=inbox&type=viewconv`
337
 
319
 
338
 `&id=` — id of the message to display (required)
320
 `&id=` — id of the message to display (required)
339
 
321
 
340
-
341
 **Response**
322
 **Response**
342
 
323
 
343
 ```json
324
 ```json
366
 
347
 
367
 Fetch bookmarked torrents or artists.
348
 Fetch bookmarked torrents or artists.
368
 
349
 
369
-
370
 ### Torrents
350
 ### Torrents
371
 
351
 
372
 **Request**
352
 **Request**
375
 
355
 
376
 `&type=` — one of torrents, artists (default: `torrents`)
356
 `&type=` — one of torrents, artists (default: `torrents`)
377
 
357
 
378
-
379
 **Response**
358
 **Response**
380
 
359
 
381
 ```json
360
 ```json
439
 }
418
 }
440
 ```
419
 ```
441
 
420
 
442
-
443
 ## Notifications
421
 ## Notifications
444
 
422
 
445
 Fetch new upload filter notifications.
423
 Fetch new upload filter notifications.
446
 
424
 
447
-
448
 **Request**
425
 **Request**
449
 
426
 
450
 `ajax.php?action=notifications`
427
 `ajax.php?action=notifications`
451
 
428
 
452
 `&page=` — page number to display (default: `1`)
429
 `&page=` — page number to display (default: `1`)
453
 
430
 
454
-
455
 **Response**
431
 **Response**
456
 
432
 
457
 ```json
433
 ```json
458
 
434
 
459
 ```
435
 ```
460
 
436
 
461
-
462
 ### Get user notifications
437
 ### Get user notifications
463
 
438
 
464
 **Request**
439
 **Request**
465
 
440
 
466
 `ajax.php?action=get_user_notifications`
441
 `ajax.php?action=get_user_notifications`
467
 
442
 
468
-
469
 **Response**
443
 **Response**
470
 
444
 
471
 ```json
445
 ```json
483
 }
457
 }
484
 ```
458
 ```
485
 
459
 
486
-
487
 ### Clear user notification
460
 ### Clear user notification
488
 
461
 
489
 **Request**
462
 **Request**
502
 - Collages
475
 - Collages
503
 - Global
476
 - Global
504
 
477
 
505
-
506
 **Response**
478
 **Response**
507
 
479
 
508
 ```php
480
 ```php

+ 13
- 1
mkdocs.yml View File

1
-site_name: 'API ⸬ BioTorrents.de'
1
+site_name: 'Docs ⸬ BioTorrents.de'
2
+site_url: 'https://docs.biotorrents.de'
3
+
4
+repo_name: 'Gazelle'
5
+repo_url: 'https://github.com/biotorrents/gazelle'
6
+
7
+nav:
8
+  - 'index.md'
9
+  - 'torrents.md'
10
+  - 'users.md'
11
+  - 'forums.md'
12
+  - 'meta.md'
13
+  - 'install.md'

+ 1
- 0
readme.md View File

2
 Please see
2
 Please see
3
 [API ⸬ BioTorrents.de](https://docs.biotorrents.de)
3
 [API ⸬ BioTorrents.de](https://docs.biotorrents.de)
4
 for more info.
4
 for more info.
5
+Now includes a Gazelle install guide!

+ 438
- 0
sphinx.conf View File

1
+source connect {
2
+    type = mysql
3
+    sql_host = 10.0.0.3
4
+    sql_port = 3306
5
+    #sql_sock = /var/run/mysqld/mysqld.sock
6
+    sql_user = gazelle_development
7
+    sql_pass = 
8
+    sql_db = gazelle_development
9
+
10
+    mysql_ssl_cert = /etc/mysql/ssl/client-cert.pem
11
+    mysql_ssl_key = /etc/mysql/ssl/client-key.pem
12
+    mysql_ssl_ca = /etc/mysql/ssl/ca.pem
13
+}
14
+
15
+source torrents_base : connect {
16
+    sql_attr_uint = groupid
17
+    sql_attr_uint = time
18
+    sql_attr_uint = categoryid
19
+    sql_attr_bigint = size
20
+    sql_attr_uint = snatched
21
+    sql_attr_uint = seeders
22
+    sql_attr_uint = leechers
23
+    sql_attr_uint = year
24
+    sql_attr_uint = freetorrent
25
+    sql_attr_uint = censored
26
+}
27
+
28
+source torrents : torrents_base {
29
+    # By inheriting from torrents_base, we keep all the connection info
30
+
31
+    sql_query_pre = SET group_concat_max_len = 101400
32
+    sql_query_pre = SET @starttime = NOW()
33
+    sql_query_pre = REPLACE INTO sphinx_index_last_pos VALUES ('torrents', UNIX_TIMESTAMP(@starttime))
34
+
35
+    sql_query_pre = TRUNCATE sphinx_tg
36
+    sql_query_pre = INSERT INTO sphinx_tg \
37
+        (id, name, namejp, tags, year, cnumber, catid, \
38
+            studio, series, dlsid) \
39
+        SELECT id, name, namejp, taglist, year, cataloguenumber, \
40
+            categoryid, studio, series, dlsiteid \
41
+        FROM torrents_group \
42
+        WHERE time < @starttime
43
+
44
+    sql_query_pre = TRUNCATE sphinx_t
45
+    sql_query_pre = INSERT INTO sphinx_t \
46
+        (id, gid, size, snatched, seeders, leechers, time, \
47
+            freetorrent, description, media, container, resolution, codec, \
48
+            audioformat, language, subber, censored, \
49
+            filelist, uid) \
50
+        SELECT ID, GroupID, Size, Snatched, Seeders, Leechers, UNIX_TIMESTAMP(Time), \
51
+            CAST(FreeTorrent AS CHAR), Description, Media, Container, Resolution, Codec, \
52
+            AudioFormat, Subbing, Language, Subber, Censored, \
53
+            FileList, UserID \
54
+        FROM torrents \
55
+        WHERE Time < @starttime
56
+
57
+    sql_query_pre = TRUNCATE sphinx_a
58
+    sql_query_pre = INSERT INTO sphinx_a \
59
+        (gid, aname) \
60
+        SELECT GroupID, GROUP_CONCAT(ag.Name SEPARATOR ' ') \
61
+        FROM torrents_artists AS ta \
62
+            JOIN artists_group AS ag USING(ArtistID) \
63
+        GROUP BY ta.groupid \
64
+        ORDER BY NULL
65
+
66
+    sql_query = SELECT t.id, g.id AS groupid, g.name AS groupname, \
67
+            g.namejp AS groupnamejp, tags AS taglist, year, year AS yearfulltext, \
68
+            cnumber AS cataloguenumber, dlsid AS dlsiteid, \
69
+            studio, series, \
70
+            catid AS categoryid, t.time, \
71
+            size, snatched, seeders, leechers, \
72
+            freetorrent, description, media, container, \
73
+            resolution, codec, audioformat, language, subber, censored, \
74
+            REPLACE(filelist, '_', ' ') AS filelist, \
75
+            '_all' AS fake \
76
+        FROM sphinx_t AS t \
77
+            JOIN sphinx_tg AS g ON t.gid = g.id
78
+
79
+    sql_joined_field = artistname from query; \
80
+        SELECT t.id, aname FROM sphinx_a JOIN sphinx_t AS t USING(gid) ORDER BY t.id ASC;
81
+
82
+    sql_query_post_index = DELETE FROM sphinx_delta WHERE Time <= \
83
+        (SELECT id FROM sphinx_index_last_pos WHERE type = 'torrents')
84
+}
85
+
86
+index torrents {
87
+    source = torrents
88
+    path = /var/lib/sphinxsearch/torrents
89
+    dict = keywords
90
+    preopen = 1
91
+
92
+    # http://sphinxsearch.com/docs/current.html#conf-morphology
93
+    morphology = stem_en, libstemmer_sv
94
+    #morphology = lemmatize_en_all
95
+    expand_keywords = 1
96
+
97
+    min_word_len = 2
98
+    phrase_boundary = U+F7 # This needs to the the same as the file delimiter in classes/torrents.class.php
99
+    phrase_boundary_step = 50
100
+    min_infix_len = 3
101
+
102
+    charset_table = \
103
+    U+00C0->a, U+00C1->a, U+00C2->a, U+00C3->a, U+00C4->a, U+00C5->a, U+00E0->a, U+00E1->a, U+00E2->a, \
104
+    U+00E3->a, U+00E4->a, U+00E5->a, U+0100->a, U+0101->a, U+0102->a, U+0103->a, U+010300->a, U+0104->a, U+0105->a, U+01CD->a, U+01CE->a, U+01DE->a, U+01DF->a, \
105
+    U+01E0->a, U+01E1->a, U+01FA->a, U+01FB->a, U+0200->a, U+0201->a, U+0202->a, U+0203->a, U+0226->a, U+0227->a, U+023A->a, U+0250->a, U+04D0->a, U+04D1->a, U+1D2C->a, U+1D43->a, U+1D44->a, U+1D8F->a, U+1E00->a, U+1E01->a, U+1E9A->a, U+1EA0->a, U+1EA1->a, \
106
+    U+1EA2->a, U+1EA3->a, U+1EA4->a, U+1EA5->a, U+1EA6->a, U+1EA7->a, U+1EA8->a, U+1EA9->a, U+1EAA->a, U+1EAB->a, U+1EAC->a, U+1EAD->a, U+1EAE->a, U+1EAF->a, U+1EB0->a, U+1EB1->a, U+1EB2->a, U+1EB3->a, U+1EB4->a, U+1EB5->a, U+1EB6->a, U+1EB7->a, U+2090->a, \
107
+    U+2C65->a, U+0180->b, U+0181->b, U+0182->b, U+0183->b, U+0243->b, U+0253->b, U+0299->b, U+16D2->b, U+1D03->b, U+1D2E->b, U+1D2F->b, U+1D47->b, U+1D6C->b, U+1D80->b, U+1E02->b, U+1E03->b, U+1E04->b, U+1E05->b, U+1E06->b, U+1E07->b, U+00C7->c, U+00E7->c, \
108
+    U+0106->c, U+0107->c, U+0108->c, U+0109->c, U+010A->c, U+010B->c, U+010C->c, U+010D->c, U+0187->c, U+0188->c, U+023B->c, U+023C->c, U+0255->c, U+0297->c, U+1D9C->c, U+1D9D->c, U+1E08->c, U+1E09->c, U+212D->c, U+2184->c, U+C487->c, U+010E->d, U+010F->d, U+0110->d, \
109
+    U+0111->d, U+0189->d, U+018A->d, U+018B->d, U+018C->d, U+01C5->d, U+01F2->d, U+0221->d, U+0256->d, U+0257->d, U+1D05->d, U+1D30->d, U+1D48->d, U+1D6D->d, U+1D81->d, U+1D91->d, U+1E0A->d, U+1E0B->d, U+1E0C->d, U+1E0D->d, U+1E0E->d, U+1E0F->d, U+1E10->d, \
110
+    U+1E11->d, U+1E12->d, U+1E13->d, U+00C8->e, U+00C9->e, U+00CA->e, U+00CB->e, U+00E8->e, U+00E9->e, U+00EA->e, U+00EB->e, U+0112->e, U+0113->e, U+0114->e, U+0115->e, U+0116->e, U+0117->e, U+0118->e, U+0119->e, U+011A->e, U+011B->e, U+018E->e, U+0190->e, \
111
+    U+01DD->e, U+0204->e, U+0205->e, U+0206->e, U+0207->e, U+0228->e, U+0229->e, U+0246->e, U+0247->e, U+0258->e, U+025B->e, U+025C->e, U+025D->e, U+025E->e, U+029A->e, U+1D07->e, U+1D08->e, U+1D31->e, U+1D32->e, U+1D49->e, U+1D4B->e, U+1D4C->e, U+1D92->e, \
112
+    U+1D93->e, U+1D94->e, U+1D9F->e, U+1E14->e, U+1E15->e, U+1E16->e, U+1E17->e, U+1E18->e, U+1E19->e, U+1E1A->e, U+1E1B->e, U+1E1C->e, U+1E1D->e, U+1EB8->e, U+1EB9->e, U+1EBA->e, U+1EBB->e, U+1EBC->e, U+1EBD->e, U+1EBE->e, U+1EBF->e, U+1EC0->e, U+1EC1->e, \
113
+    U+1EC2->e, U+1EC3->e, U+1EC4->e, U+1EC5->e, U+1EC6->e, U+1EC7->e, U+2091->e, U+0191->f, U+0192->f, U+1D6E->f, U+1D82->f, U+1DA0->f, U+1E1E->f, U+1E1F->f, U+011C->g, U+011D->g, U+011E->g, U+011F->g, U+0120->g, U+0121->g, U+0122->g, U+0123->g, U+0193->g, \
114
+    U+01E4->g, U+01E5->g, U+01E6->g, U+01E7->g, U+01F4->g, U+01F5->g, U+0260->g, U+0261->g, U+0262->g, U+029B->g, U+1D33->g, U+1D4D->g, U+1D77->g, U+1D79->g, U+1D83->g, U+1DA2->g, U+1E20->g, U+1E21->g, U+0124->h, U+0125->h, U+0126->h, U+0127->h, U+021E->h, \
115
+    U+021F->h, U+0265->h, U+0266->h, U+029C->h, U+02AE->h, U+02AF->h, U+02B0->h, U+02B1->h, U+1D34->h, U+1DA3->h, U+1E22->h, U+1E23->h, U+1E24->h, U+1E25->h, U+1E26->h, U+1E27->h, U+1E28->h, U+1E29->h, U+1E2A->h, U+1E2B->h, U+1E96->h, U+210C->h, U+2C67->h, \
116
+    U+2C68->h, U+2C75->h, U+2C76->h, U+00CC->i, U+00CD->i, U+00CE->i, U+00CF->i, U+00EC->i, U+00ED->i, U+00EE->i, U+00EF->i, U+010309->i, U+0128->i, U+0129->i, U+012A->i, U+012B->i, U+012C->i, U+012D->i, U+012E->i, U+012F->i, U+0130->i, U+0131->i, U+0197->i, \
117
+    U+01CF->i, U+01D0->i, U+0208->i, U+0209->i, U+020A->i, U+020B->i, U+0268->i, U+026A->i, U+040D->i, U+0418->i, U+0419->i, U+0438->i, U+0439->i, U+0456->i, U+1D09->i, U+1D35->i, U+1D4E->i, U+1D62->i, U+1D7B->i, U+1D96->i, U+1DA4->i, U+1DA6->i, U+1DA7->i, \
118
+    U+1E2C->i, U+1E2D->i, U+1E2E->i, U+1E2F->i, U+1EC8->i, U+1EC9->i, U+1ECA->i, U+1ECB->i, U+2071->i, U+2111->i, U+0134->j, U+0135->j, U+01C8->j, U+01CB->j, U+01F0->j, U+0237->j, U+0248->j, U+0249->j, U+025F->j, U+0284->j, U+029D->j, U+02B2->j, U+1D0A->j, \
119
+    U+1D36->j, U+1DA1->j, U+1DA8->j, U+0136->k, U+0137->k, U+0198->k, U+0199->k, U+01E8->k, U+01E9->k, U+029E->k, U+1D0B->k, U+1D37->k, U+1D4F->k, U+1D84->k, U+1E30->k, U+1E31->k, U+1E32->k, U+1E33->k, U+1E34->k, U+1E35->k, U+2C69->k, U+2C6A->k, U+0139->l, \
120
+    U+013A->l, U+013B->l, U+013C->l, U+013D->l, U+013E->l, U+013F->l, U+0140->l, U+0141->l, U+0142->l, U+019A->l, U+01C8->l, U+0234->l, U+023D->l, U+026B->l, U+026C->l, U+026D->l, U+029F->l, U+02E1->l, U+1D0C->l, U+1D38->l, U+1D85->l, U+1DA9->l, U+1DAA->l, \
121
+    U+1DAB->l, U+1E36->l, U+1E37->l, U+1E38->l, U+1E39->l, U+1E3A->l, U+1E3B->l, U+1E3C->l, U+1E3D->l, U+2C60->l, U+2C61->l, U+2C62->l, U+019C->m, U+026F->m, U+0270->m, U+0271->m, U+1D0D->m, U+1D1F->m, U+1D39->m, U+1D50->m, U+1D5A->m, U+1D6F->m, U+1D86->m, \
122
+    U+1DAC->m, U+1DAD->m, U+1E3E->m, U+1E3F->m, U+1E40->m, U+1E41->m, U+1E42->m, U+1E43->m, U+00D1->n, U+00F1->n, U+0143->n, U+0144->n, U+0145->n, U+0146->n, U+0147->n, U+0148->n, U+0149->n, U+019D->n, U+019E->n, U+01CB->n, U+01F8->n, U+01F9->n, U+0220->n, \
123
+    U+0235->n, U+0272->n, U+0273->n, U+0274->n, U+1D0E->n, U+1D3A->n, U+1D3B->n, U+1D70->n, U+1D87->n, U+1DAE->n, U+1DAF->n, U+1DB0->n, U+1E44->n, U+1E45->n, U+1E46->n, U+1E47->n, U+1E48->n, U+1E49->n, U+1E4A->n, U+1E4B->n, U+207F->n, U+00D2->o, U+00D3->o, \
124
+    U+00D4->o, U+00D5->o, U+00D6->o, U+00D8->o, U+00F2->o, U+00F3->o, U+00F4->o, U+00F5->o, U+00F6->o, U+00F8->o, U+01030F->o, U+014C->o, U+014D->o, U+014E->o, U+014F->o, U+0150->o, U+0151->o, U+0186->o, U+019F->o, U+01A0->o, U+01A1->o, U+01D1->o, U+01D2->o, \
125
+    U+01EA->o, U+01EB->o, U+01EC->o, U+01ED->o, U+01FE->o, U+01FF->o, U+020C->o, U+020D->o, U+020E->o, U+020F->o, U+022A->o, U+022B->o, U+022C->o, U+022D->o, U+022E->o, U+022F->o, U+0230->o, U+0231->o, U+0254->o, U+0275->o, U+043E->o, U+04E6->o, U+04E7->o, \
126
+    U+04E8->o, U+04E9->o, U+04EA->o, U+04EB->o, U+1D0F->o, U+1D10->o, U+1D11->o, U+1D12->o, U+1D13->o, U+1D16->o, U+1D17->o, U+1D3C->o, U+1D52->o, U+1D53->o, U+1D54->o, U+1D55->o, U+1D97->o, U+1DB1->o, U+1E4C->o, U+1E4D->o, U+1E4E->o, U+1E4F->o, U+1E50->o, \
127
+    U+1E51->o, U+1E52->o, U+1E53->o, U+1ECC->o, U+1ECD->o, U+1ECE->o, U+1ECF->o, U+1ED0->o, U+1ED1->o, U+1ED2->o, U+1ED3->o, U+1ED4->o, U+1ED5->o, U+1ED6->o, U+1ED7->o, U+1ED8->o, U+1ED9->o, U+1EDA->o, U+1EDB->o, U+1EDC->o, U+1EDD->o, U+1EDE->o, U+1EDF->o, \
128
+    U+1EE0->o, U+1EE1->o, U+1EE2->o, U+1EE3->o, U+2092->o, U+2C9E->o, U+2C9F->o, U+01A4->p, U+01A5->p, U+1D18->p, U+1D3E->p, U+1D56->p, U+1D71->p, U+1D7D->p, U+1D88->p, U+1E54->p, U+1E55->p, U+1E56->p, U+1E57->p, U+2C63->p, U+024A->q, U+024B->q, U+02A0->q, \
129
+    U+0154->r, U+0155->r, U+0156->r, U+0157->r, U+0158->r, U+0159->r, U+0210->r, U+0211->r, U+0212->r, U+0213->r, U+024C->r, U+024D->r, U+0279->r, U+027A->r, U+027B->r, U+027C->r, U+027D->r, U+027E->r, U+027F->r, U+0280->r, U+0281->r, U+02B3->r, U+02B4->r, \
130
+    U+02B5->r, U+02B6->r, U+1D19->r, U+1D1A->r, U+1D3F->r, U+1D63->r, U+1D72->r, U+1D73->r, U+1D89->r, U+1DCA->r, U+1E58->r, U+1E59->r, U+1E5A->r, U+1E5B->r, U+1E5C->r, U+1E5D->r, U+1E5E->r, U+1E5F->r, U+211C->r, U+2C64->r, U+00DF->s, U+015A->s, U+015B->s, \
131
+    U+015C->s, U+015D->s, U+015E->s, U+015F->s, U+0160->s, U+0161->s, U+017F->s, U+0218->s, U+0219->s, U+023F->s, U+0282->s, U+02E2->s, U+1D74->s, U+1D8A->s, U+1DB3->s, U+1E60->s, U+1E61->s, U+1E62->s, U+1E63->s, U+1E64->s, U+1E65->s, U+1E66->s, U+1E67->s, \
132
+    U+1E68->s, U+1E69->s, U+1E9B->s, U+0162->t, U+0163->t, U+0164->t, U+0165->t, U+0166->t, U+0167->t, U+01AB->t, U+01AC->t, U+01AD->t, U+01AE->t, U+021A->t, U+021B->t, U+0236->t, U+023E->t, U+0287->t, U+0288->t, U+1D1B->t, U+1D40->t, U+1D57->t, U+1D75->t, \
133
+    U+1DB5->t, U+1E6A->t, U+1E6B->t, U+1E6C->t, U+1E6D->t, U+1E6E->t, U+1E6F->t, U+1E70->t, U+1E71->t, U+1E97->t, U+2C66->t, U+00D9->u, U+00DA->u, U+00DB->u, U+00DC->u, U+00F9->u, U+00FA->u, U+00FB->u, U+00FC->u, U+010316->u, U+0168->u, U+0169->u, U+016A->u, \
134
+    U+016B->u, U+016C->u, U+016D->u, U+016E->u, U+016F->u, U+0170->u, U+0171->u, U+0172->u, U+0173->u, U+01AF->u, U+01B0->u, U+01D3->u, U+01D4->u, U+01D5->u, U+01D6->u, U+01D7->u, U+01D8->u, U+01D9->u, U+01DA->u, U+01DB->u, U+01DC->u, U+0214->u, U+0215->u, \
135
+    U+0216->u, U+0217->u, U+0244->u, U+0289->u, U+1D1C->u, U+1D1D->u, U+1D1E->u, U+1D41->u, U+1D58->u, U+1D59->u, U+1D64->u, U+1D7E->u, U+1D99->u, U+1DB6->u, U+1DB8->u, U+1E72->u, U+1E73->u, U+1E74->u, U+1E75->u, U+1E76->u, U+1E77->u, U+1E78->u, U+1E79->u, \
136
+    U+1E7A->u, U+1E7B->u, U+1EE4->u, U+1EE5->u, U+1EE6->u, U+1EE7->u, U+1EE8->u, U+1EE9->u, U+1EEA->u, U+1EEB->u, U+1EEC->u, U+1EED->u, U+1EEE->u, U+1EEF->u, U+1EF0->u, U+1EF1->u, U+01B2->v, U+0245->v, U+028B->v, U+028C->v, U+1D20->v, U+1D5B->v, U+1D65->v, \
137
+    U+1D8C->v, U+1DB9->v, U+1DBA->v, U+1E7C->v, U+1E7D->v, U+1E7E->v, U+1E7F->v, U+2C74->v, U+0174->w, U+0175->w, U+028D->w, U+02B7->w, U+1D21->w, U+1D42->w, U+1E80->w, U+1E81->w, U+1E82->w, U+1E83->w, U+1E84->w, U+1E85->w, U+1E86->w, U+1E87->w, U+1E88->w, \
138
+    U+1E89->w, U+1E98->w, U+02E3->x, U+1D8D->x, U+1E8A->x, U+1E8B->x, U+1E8C->x, U+1E8D->x, U+2093->x, U+00DD->y, U+00FD->y, U+00FF->y, U+0176->y, U+0177->y, U+0178->y, U+01B3->y, U+01B4->y, U+0232->y, U+0233->y, U+024E->y, U+024F->y, U+028E->y, U+028F->y, \
139
+    U+02B8->y, U+1E8E->y, U+1E8F->y, U+1E99->y, U+1EF2->y, U+1EF3->y, U+1EF4->y, U+1EF5->y, U+1EF6->y, U+1EF7->y, U+1EF8->y, U+1EF9->y, U+0179->z, U+017A->z, U+017B->z, U+017C->z, U+017D->z, U+017E->z, U+01B5->z, U+01B6->z, U+0224->z, U+0225->z, U+0240->z, \
140
+    U+0290->z, U+0291->z, U+1D22->z, U+1D76->z, U+1D8E->z, U+1DBB->z, U+1DBC->z, U+1DBD->z, U+1E90->z, U+1E91->z, U+1E92->z, U+1E93->z, U+1E94->z, U+1E95->z, U+2128->z, U+2C6B->z, U+2C6C->z, U+00C6->U+00E6, U+01E2->U+00E6, U+01E3->U+00E6, U+01FC->U+00E6, \
141
+    U+01FD->U+00E6, U+1D01->U+00E6, U+1D02->U+00E6, U+1D2D->U+00E6, U+1D46->U+00E6, U+00E6, U+0622->U+0627, U+0623->U+0627, U+0624->U+0648, U+0625->U+0627, U+0626->U+064A, U+06C0->U+06D5, U+06C2->U+06C1, U+06D3->U+06D2, U+FB50->U+0671, U+FB51->U+0671, U+FB52->U+067B, \
142
+    U+FB53->U+067B, U+FB54->U+067B, U+FB56->U+067E, U+FB57->U+067E, U+FB58->U+067E, U+FB5A->U+0680, U+FB5B->U+0680, U+FB5C->U+0680, U+FB5E->U+067A, U+FB5F->U+067A, U+FB60->U+067A, U+FB62->U+067F, U+FB63->U+067F, U+FB64->U+067F, U+FB66->U+0679, U+FB67->U+0679, \
143
+    U+FB68->U+0679, U+FB6A->U+06A4, U+FB6B->U+06A4, U+FB6C->U+06A4, U+FB6E->U+06A6, U+FB6F->U+06A6, U+FB70->U+06A6, U+FB72->U+0684, U+FB73->U+0684, U+FB74->U+0684, U+FB76->U+0683, U+FB77->U+0683, U+FB78->U+0683, U+FB7A->U+0686, U+FB7B->U+0686, U+FB7C->U+0686, \
144
+    U+FB7E->U+0687, U+FB7F->U+0687, U+FB80->U+0687, U+FB82->U+068D, U+FB83->U+068D, U+FB84->U+068C, U+FB85->U+068C, U+FB86->U+068E, U+FB87->U+068E, U+FB88->U+0688, U+FB89->U+0688, U+FB8A->U+0698, U+FB8B->U+0698, U+FB8C->U+0691, U+FB8D->U+0691, U+FB8E->U+06A9, \
145
+    U+FB8F->U+06A9, U+FB90->U+06A9, U+FB92->U+06AF, U+FB93->U+06AF, U+FB94->U+06AF, U+FB96->U+06B3, U+FB97->U+06B3, U+FB98->U+06B3, U+FB9A->U+06B1, U+FB9B->U+06B1, U+FB9C->U+06B1, U+FB9E->U+06BA, U+FB9F->U+06BA, U+FBA0->U+06BB, U+FBA1->U+06BB, U+FBA2->U+06BB, \
146
+    U+FBA4->U+06C0, U+FBA5->U+06C0, U+FBA6->U+06C1, U+FBA7->U+06C1, U+FBA8->U+06C1, U+FBAA->U+06BE, U+FBAB->U+06BE, U+FBAC->U+06BE, U+FBAE->U+06D2, U+FBAF->U+06D2, U+FBB0->U+06D3, U+FBB1->U+06D3, U+FBD3->U+06AD, U+FBD4->U+06AD, U+FBD5->U+06AD, U+FBD7->U+06C7, \
147
+    U+FBD8->U+06C7, U+FBD9->U+06C6, U+FBDA->U+06C6, U+FBDB->U+06C8, U+FBDC->U+06C8, U+FBDD->U+0677, U+FBDE->U+06CB, U+FBDF->U+06CB, U+FBE0->U+06C5, U+FBE1->U+06C5, U+FBE2->U+06C9, U+FBE3->U+06C9, U+FBE4->U+06D0, U+FBE5->U+06D0, U+FBE6->U+06D0, U+FBE8->U+0649, \
148
+    U+FBFC->U+06CC, U+FBFD->U+06CC, U+FBFE->U+06CC, U+0621, U+0627..U+063A, U+0641..U+064A, U+0660..U+0669, U+066E, U+066F, U+0671..U+06BF, U+06C1, U+06C3..U+06D2, U+06D5, U+06EE..U+06FC, U+06FF, U+0750..U+076D, U+FB55, U+FB59, U+FB5D, U+FB61, U+FB65, U+FB69, \
149
+    U+FB6D, U+FB71, U+FB75, U+FB79, U+FB7D, U+FB81, U+FB91, U+FB95, U+FB99, U+FB9D, U+FBA3, U+FBA9, U+FBAD, U+FBD6, U+FBE7, U+FBE9, U+FBFF, U+0531..U+0556->U+0561..U+0586, U+0561..U+0586, U+0587, U+09DC->U+09A1, U+09DD->U+09A2, U+09DF->U+09AF, U+09F0->U+09AC, \
150
+    U+09F1->U+09AC, U+0985..U+0990, U+0993..U+09B0, U+09B2, U+09B6..U+09B9, U+09CE, U+09E0, U+09E1, U+09E6..U+09EF, U+F900->U+8C48, U+F901->U+66F4, U+F902->U+8ECA, U+F903->U+8CC8, U+F904->U+6ED1, U+F905->U+4E32, U+F906->U+53E5, U+F907->U+9F9C, U+F908->U+9F9C, \
151
+    U+F909->U+5951, U+F90A->U+91D1, U+F90B->U+5587, U+F90C->U+5948, U+F90D->U+61F6, U+F90E->U+7669, U+F90F->U+7F85, U+F910->U+863F, U+F911->U+87BA, U+F912->U+88F8, U+F913->U+908F, U+F914->U+6A02, U+F915->U+6D1B, U+F916->U+70D9, U+F917->U+73DE, U+F918->U+843D, \
152
+    U+F919->U+916A, U+F91A->U+99F1, U+F91B->U+4E82, U+F91C->U+5375, U+F91D->U+6B04, U+F91E->U+721B, U+F91F->U+862D, U+F920->U+9E1E, U+F921->U+5D50, U+F922->U+6FEB, U+F923->U+85CD, U+F924->U+8964, U+F925->U+62C9, U+F926->U+81D8, U+F927->U+881F, U+F928->U+5ECA, \
153
+    U+F929->U+6717, U+F92A->U+6D6A, U+F92B->U+72FC, U+F92C->U+90CE, U+F92D->U+4F86, U+F92E->U+51B7, U+F92F->U+52DE, U+F930->U+64C4, U+F931->U+6AD3, U+F932->U+7210, U+F933->U+76E7, U+F934->U+8001, U+F935->U+8606, U+F936->U+865C, U+F937->U+8DEF, U+F938->U+9732, \
154
+    U+F939->U+9B6F, U+F93A->U+9DFA, U+F93B->U+788C, U+F93C->U+797F, U+F93D->U+7DA0, U+F93E->U+83C9, U+F93F->U+9304, U+F940->U+9E7F, U+F941->U+8AD6, U+F942->U+58DF, U+F943->U+5F04, U+F944->U+7C60, U+F945->U+807E, U+F946->U+7262, U+F947->U+78CA, U+F948->U+8CC2, \
155
+    U+F949->U+96F7, U+F94A->U+58D8, U+F94B->U+5C62, U+F94C->U+6A13, U+F94D->U+6DDA, U+F94E->U+6F0F, U+F94F->U+7D2F, U+F950->U+7E37, U+F951->U+964B, U+F952->U+52D2, U+F953->U+808B, U+F954->U+51DC, U+F955->U+51CC, U+F956->U+7A1C, U+F957->U+7DBE, U+F958->U+83F1, \
156
+    U+F959->U+9675, U+F95A->U+8B80, U+F95B->U+62CF, U+F95C->U+6A02, U+F95D->U+8AFE, U+F95E->U+4E39, U+F95F->U+5BE7, U+F960->U+6012, U+F961->U+7387, U+F962->U+7570, U+F963->U+5317, U+F964->U+78FB, U+F965->U+4FBF, U+F966->U+5FA9, U+F967->U+4E0D, U+F968->U+6CCC, \
157
+    U+F969->U+6578, U+F96A->U+7D22, U+F96B->U+53C3, U+F96C->U+585E, U+F96D->U+7701, U+F96E->U+8449, U+F96F->U+8AAA, U+F970->U+6BBA, U+F971->U+8FB0, U+F972->U+6C88, U+F973->U+62FE, U+F974->U+82E5, U+F975->U+63A0, U+F976->U+7565, U+F977->U+4EAE, U+F978->U+5169, \
158
+    U+F979->U+51C9, U+F97A->U+6881, U+F97B->U+7CE7, U+F97C->U+826F, U+F97D->U+8AD2, U+F97E->U+91CF, U+F97F->U+52F5, U+F980->U+5442, U+F981->U+5973, U+F982->U+5EEC, U+F983->U+65C5, U+F984->U+6FFE, U+F985->U+792A, U+F986->U+95AD, U+F987->U+9A6A, U+F988->U+9E97, \
159
+    U+F989->U+9ECE, U+F98A->U+529B, U+F98B->U+66C6, U+F98C->U+6B77, U+F98D->U+8F62, U+F98E->U+5E74, U+F98F->U+6190, U+F990->U+6200, U+F991->U+649A, U+F992->U+6F23, U+F993->U+7149, U+F994->U+7489, U+F995->U+79CA, U+F996->U+7DF4, U+F997->U+806F, U+F998->U+8F26, \
160
+    U+F999->U+84EE, U+F99A->U+9023, U+F99B->U+934A, U+F99C->U+5217, U+F99D->U+52A3, U+F99E->U+54BD, U+F99F->U+70C8, U+F9A0->U+88C2, U+F9A1->U+8AAA, U+F9A2->U+5EC9, U+F9A3->U+5FF5, U+F9A4->U+637B, U+F9A5->U+6BAE, U+F9A6->U+7C3E, U+F9A7->U+7375, U+F9A8->U+4EE4, \
161
+    U+F9A9->U+56F9, U+F9AA->U+5BE7, U+F9AB->U+5DBA, U+F9AC->U+601C, U+F9AD->U+73B2, U+F9AE->U+7469, U+F9AF->U+7F9A, U+F9B0->U+8046, U+F9B1->U+9234, U+F9B2->U+96F6, U+F9B3->U+9748, U+F9B4->U+9818, U+F9B5->U+4F8B, U+F9B6->U+79AE, U+F9B7->U+91B4, U+F9B8->U+96B8, \
162
+    U+F9B9->U+60E1, U+F9BA->U+4E86, U+F9BB->U+50DA, U+F9BC->U+5BEE, U+F9BD->U+5C3F, U+F9BE->U+6599, U+F9BF->U+6A02, U+F9C0->U+71CE, U+F9C1->U+7642, U+F9C2->U+84FC, U+F9C3->U+907C, U+F9C4->U+9F8D, U+F9C5->U+6688, U+F9C6->U+962E, U+F9C7->U+5289, U+F9C8->U+677B, \
163
+    U+F9C9->U+67F3, U+F9CA->U+6D41, U+F9CB->U+6E9C, U+F9CC->U+7409, U+F9CD->U+7559, U+F9CE->U+786B, U+F9CF->U+7D10, U+F9D0->U+985E, U+F9D1->U+516D, U+F9D2->U+622E, U+F9D3->U+9678, U+F9D4->U+502B, U+F9D5->U+5D19, U+F9D6->U+6DEA, U+F9D7->U+8F2A, U+F9D8->U+5F8B, \
164
+    U+F9D9->U+6144, U+F9DA->U+6817, U+F9DB->U+7387, U+F9DC->U+9686, U+F9DD->U+5229, U+F9DE->U+540F, U+F9DF->U+5C65, U+F9E0->U+6613, U+F9E1->U+674E, U+F9E2->U+68A8, U+F9E3->U+6CE5, U+F9E4->U+7406, U+F9E5->U+75E2, U+F9E6->U+7F79, U+F9E7->U+88CF, U+F9E8->U+88E1, \
165
+    U+F9E9->U+91CC, U+F9EA->U+96E2, U+F9EB->U+533F, U+F9EC->U+6EBA, U+F9ED->U+541D, U+F9EE->U+71D0, U+F9EF->U+7498, U+F9F0->U+85FA, U+F9F1->U+96A3, U+F9F2->U+9C57, U+F9F3->U+9E9F, U+F9F4->U+6797, U+F9F5->U+6DCB, U+F9F6->U+81E8, U+F9F7->U+7ACB, U+F9F8->U+7B20, \
166
+    U+F9F9->U+7C92, U+F9FA->U+72C0, U+F9FB->U+7099, U+F9FC->U+8B58, U+F9FD->U+4EC0, U+F9FE->U+8336, U+F9FF->U+523A, U+FA00->U+5207, U+FA01->U+5EA6, U+FA02->U+62D3, U+FA03->U+7CD6, U+FA04->U+5B85, U+FA05->U+6D1E, U+FA06->U+66B4, U+FA07->U+8F3B, U+FA08->U+884C, \
167
+    U+FA09->U+964D, U+FA0A->U+898B, U+FA0B->U+5ED3, U+FA0C->U+5140, U+FA0D->U+55C0, U+FA10->U+585A, U+FA12->U+6674, U+FA15->U+51DE, U+FA16->U+732A, U+FA17->U+76CA, U+FA18->U+793C, U+FA19->U+795E, U+FA1A->U+7965, U+FA1B->U+798F, U+FA1C->U+9756, U+FA1D->U+7CBE, \
168
+    U+FA1E->U+7FBD, U+FA20->U+8612, U+FA22->U+8AF8, U+FA25->U+9038, U+FA26->U+90FD, U+FA2A->U+98EF, U+FA2B->U+98FC, U+FA2C->U+9928, U+FA2D->U+9DB4, U+FA30->U+4FAE, U+FA31->U+50E7, U+FA32->U+514D, U+FA33->U+52C9, U+FA34->U+52E4, U+FA35->U+5351, U+FA36->U+559D, \
169
+    U+FA37->U+5606, U+FA38->U+5668, U+FA39->U+5840, U+FA3A->U+58A8, U+FA3B->U+5C64, U+FA3C->U+5C6E, U+FA3D->U+6094, U+FA3E->U+6168, U+FA3F->U+618E, U+FA40->U+61F2, U+FA41->U+654F, U+FA42->U+65E2, U+FA43->U+6691, U+FA44->U+6885, U+FA45->U+6D77, U+FA46->U+6E1A, \
170
+    U+FA47->U+6F22, U+FA48->U+716E, U+FA49->U+722B, U+FA4A->U+7422, U+FA4B->U+7891, U+FA4C->U+793E, U+FA4D->U+7949, U+FA4E->U+7948, U+FA4F->U+7950, U+FA50->U+7956, U+FA51->U+795D, U+FA52->U+798D, U+FA53->U+798E, U+FA54->U+7A40, U+FA55->U+7A81, U+FA56->U+7BC0, \
171
+    U+FA57->U+7DF4, U+FA58->U+7E09, U+FA59->U+7E41, U+FA5A->U+7F72, U+FA5B->U+8005, U+FA5C->U+81ED, U+FA5D->U+8279, U+FA5E->U+8279, U+FA5F->U+8457, U+FA60->U+8910, U+FA61->U+8996, U+FA62->U+8B01, U+FA63->U+8B39, U+FA64->U+8CD3, U+FA65->U+8D08, U+FA66->U+8FB6, \
172
+    U+FA67->U+9038, U+FA68->U+96E3, U+FA69->U+97FF, U+FA6A->U+983B, U+FA70->U+4E26, U+FA71->U+51B5, U+FA72->U+5168, U+FA73->U+4F80, U+FA74->U+5145, U+FA75->U+5180, U+FA76->U+52C7, U+FA77->U+52FA, U+FA78->U+559D, U+FA79->U+5555, U+FA7A->U+5599, U+FA7B->U+55E2, \
173
+    U+FA7C->U+585A, U+FA7D->U+58B3, U+FA7E->U+5944, U+FA7F->U+5954, U+FA80->U+5A62, U+FA81->U+5B28, U+FA82->U+5ED2, U+FA83->U+5ED9, U+FA84->U+5F69, U+FA85->U+5FAD, U+FA86->U+60D8, U+FA87->U+614E, U+FA88->U+6108, U+FA89->U+618E, U+FA8A->U+6160, U+FA8B->U+61F2, \
174
+    U+FA8C->U+6234, U+FA8D->U+63C4, U+FA8E->U+641C, U+FA8F->U+6452, U+FA90->U+6556, U+FA91->U+6674, U+FA92->U+6717, U+FA93->U+671B, U+FA94->U+6756, U+FA95->U+6B79, U+FA96->U+6BBA, U+FA97->U+6D41, U+FA98->U+6EDB, U+FA99->U+6ECB, U+FA9A->U+6F22, U+FA9B->U+701E, \
175
+    U+FA9C->U+716E, U+FA9D->U+77A7, U+FA9E->U+7235, U+FA9F->U+72AF, U+FAA0->U+732A, U+FAA1->U+7471, U+FAA2->U+7506, U+FAA3->U+753B, U+FAA4->U+761D, U+FAA5->U+761F, U+FAA6->U+76CA, U+FAA7->U+76DB, U+FAA8->U+76F4, U+FAA9->U+774A, U+FAAA->U+7740, U+FAAB->U+78CC, \
176
+    U+FAAC->U+7AB1, U+FAAD->U+7BC0, U+FAAE->U+7C7B, U+FAAF->U+7D5B, U+FAB0->U+7DF4, U+FAB1->U+7F3E, U+FAB2->U+8005, U+FAB3->U+8352, U+FAB4->U+83EF, U+FAB5->U+8779, U+FAB6->U+8941, U+FAB7->U+8986, U+FAB8->U+8996, U+FAB9->U+8ABF, U+FABA->U+8AF8, U+FABB->U+8ACB, \
177
+    U+FABC->U+8B01, U+FABD->U+8AFE, U+FABE->U+8AED, U+FABF->U+8B39, U+FAC0->U+8B8A, U+FAC1->U+8D08, U+FAC2->U+8F38, U+FAC3->U+9072, U+FAC4->U+9199, U+FAC5->U+9276, U+FAC6->U+967C, U+FAC7->U+96E3, U+FAC8->U+9756, U+FAC9->U+97DB, U+FACA->U+97FF, U+FACB->U+980B, \
178
+    U+FACC->U+983B, U+FACD->U+9B12, U+FACE->U+9F9C, U+FACF->U+2284A, U+FAD0->U+22844, U+FAD1->U+233D5, U+FAD2->U+3B9D, U+FAD3->U+4018, U+FAD4->U+4039, U+FAD5->U+25249, U+FAD6->U+25CD0, U+FAD7->U+27ED3, U+FAD8->U+9F43, U+FAD9->U+9F8E, U+2F800->U+4E3D, U+2F801->U+4E38, \
179
+    U+2F802->U+4E41, U+2F803->U+20122, U+2F804->U+4F60, U+2F805->U+4FAE, U+2F806->U+4FBB, U+2F807->U+5002, U+2F808->U+507A, U+2F809->U+5099, U+2F80A->U+50E7, U+2F80B->U+50CF, U+2F80C->U+349E, U+2F80D->U+2063A, U+2F80E->U+514D, U+2F80F->U+5154, U+2F810->U+5164, \
180
+    U+2F811->U+5177, U+2F812->U+2051C, U+2F813->U+34B9, U+2F814->U+5167, U+2F815->U+518D, U+2F816->U+2054B, U+2F817->U+5197, U+2F818->U+51A4, U+2F819->U+4ECC, U+2F81A->U+51AC, U+2F81B->U+51B5, U+2F81C->U+291DF, U+2F81D->U+51F5, U+2F81E->U+5203, U+2F81F->U+34DF, \
181
+    U+2F820->U+523B, U+2F821->U+5246, U+2F822->U+5272, U+2F823->U+5277, U+2F824->U+3515, U+2F825->U+52C7, U+2F826->U+52C9, U+2F827->U+52E4, U+2F828->U+52FA, U+2F829->U+5305, U+2F82A->U+5306, U+2F82B->U+5317, U+2F82C->U+5349, U+2F82D->U+5351, U+2F82E->U+535A, \
182
+    U+2F82F->U+5373, U+2F830->U+537D, U+2F831->U+537F, U+2F832->U+537F, U+2F833->U+537F, U+2F834->U+20A2C, U+2F835->U+7070, U+2F836->U+53CA, U+2F837->U+53DF, U+2F838->U+20B63, U+2F839->U+53EB, U+2F83A->U+53F1, U+2F83B->U+5406, U+2F83C->U+549E, U+2F83D->U+5438, \
183
+    U+2F83E->U+5448, U+2F83F->U+5468, U+2F840->U+54A2, U+2F841->U+54F6, U+2F842->U+5510, U+2F843->U+5553, U+2F844->U+5563, U+2F845->U+5584, U+2F846->U+5584, U+2F847->U+5599, U+2F848->U+55AB, U+2F849->U+55B3, U+2F84A->U+55C2, U+2F84B->U+5716, U+2F84C->U+5606, \
184
+    U+2F84D->U+5717, U+2F84E->U+5651, U+2F84F->U+5674, U+2F850->U+5207, U+2F851->U+58EE, U+2F852->U+57CE, U+2F853->U+57F4, U+2F854->U+580D, U+2F855->U+578B, U+2F856->U+5832, U+2F857->U+5831, U+2F858->U+58AC, U+2F859->U+214E4, U+2F85A->U+58F2, U+2F85B->U+58F7, \
185
+    U+2F85C->U+5906, U+2F85D->U+591A, U+2F85E->U+5922, U+2F85F->U+5962, U+2F860->U+216A8, U+2F861->U+216EA, U+2F862->U+59EC, U+2F863->U+5A1B, U+2F864->U+5A27, U+2F865->U+59D8, U+2F866->U+5A66, U+2F867->U+36EE, U+2F868->U+36FC, U+2F869->U+5B08, U+2F86A->U+5B3E, \
186
+    U+2F86B->U+5B3E, U+2F86C->U+219C8, U+2F86D->U+5BC3, U+2F86E->U+5BD8, U+2F86F->U+5BE7, U+2F870->U+5BF3, U+2F871->U+21B18, U+2F872->U+5BFF, U+2F873->U+5C06, U+2F874->U+5F53, U+2F875->U+5C22, U+2F876->U+3781, U+2F877->U+5C60, U+2F878->U+5C6E, U+2F879->U+5CC0, \
187
+    U+2F87A->U+5C8D, U+2F87B->U+21DE4, U+2F87C->U+5D43, U+2F87D->U+21DE6, U+2F87E->U+5D6E, U+2F87F->U+5D6B, U+2F880->U+5D7C, U+2F881->U+5DE1, U+2F882->U+5DE2, U+2F883->U+382F, U+2F884->U+5DFD, U+2F885->U+5E28, U+2F886->U+5E3D, U+2F887->U+5E69, U+2F888->U+3862, \
188
+    U+2F889->U+22183, U+2F88A->U+387C, U+2F88B->U+5EB0, U+2F88C->U+5EB3, U+2F88D->U+5EB6, U+2F88E->U+5ECA, U+2F88F->U+2A392, U+2F890->U+5EFE, U+2F891->U+22331, U+2F892->U+22331, U+2F893->U+8201, U+2F894->U+5F22, U+2F895->U+5F22, U+2F896->U+38C7, U+2F897->U+232B8, \
189
+    U+2F898->U+261DA, U+2F899->U+5F62, U+2F89A->U+5F6B, U+2F89B->U+38E3, U+2F89C->U+5F9A, U+2F89D->U+5FCD, U+2F89E->U+5FD7, U+2F89F->U+5FF9, U+2F8A0->U+6081, U+2F8A1->U+393A, U+2F8A2->U+391C, U+2F8A3->U+6094, U+2F8A4->U+226D4, U+2F8A5->U+60C7, U+2F8A6->U+6148, \
190
+    U+2F8A7->U+614C, U+2F8A8->U+614E, U+2F8A9->U+614C, U+2F8AA->U+617A, U+2F8AB->U+618E, U+2F8AC->U+61B2, U+2F8AD->U+61A4, U+2F8AE->U+61AF, U+2F8AF->U+61DE, U+2F8B0->U+61F2, U+2F8B1->U+61F6, U+2F8B2->U+6210, U+2F8B3->U+621B, U+2F8B4->U+625D, U+2F8B5->U+62B1, \
191
+    U+2F8B6->U+62D4, U+2F8B7->U+6350, U+2F8B8->U+22B0C, U+2F8B9->U+633D, U+2F8BA->U+62FC, U+2F8BB->U+6368, U+2F8BC->U+6383, U+2F8BD->U+63E4, U+2F8BE->U+22BF1, U+2F8BF->U+6422, U+2F8C0->U+63C5, U+2F8C1->U+63A9, U+2F8C2->U+3A2E, U+2F8C3->U+6469, U+2F8C4->U+647E, \
192
+    U+2F8C5->U+649D, U+2F8C6->U+6477, U+2F8C7->U+3A6C, U+2F8C8->U+654F, U+2F8C9->U+656C, U+2F8CA->U+2300A, U+2F8CB->U+65E3, U+2F8CC->U+66F8, U+2F8CD->U+6649, U+2F8CE->U+3B19, U+2F8CF->U+6691, U+2F8D0->U+3B08, U+2F8D1->U+3AE4, U+2F8D2->U+5192, U+2F8D3->U+5195, \
193
+    U+2F8D4->U+6700, U+2F8D5->U+669C, U+2F8D6->U+80AD, U+2F8D7->U+43D9, U+2F8D8->U+6717, U+2F8D9->U+671B, U+2F8DA->U+6721, U+2F8DB->U+675E, U+2F8DC->U+6753, U+2F8DD->U+233C3, U+2F8DE->U+3B49, U+2F8DF->U+67FA, U+2F8E0->U+6785, U+2F8E1->U+6852, U+2F8E2->U+6885, \
194
+    U+2F8E3->U+2346D, U+2F8E4->U+688E, U+2F8E5->U+681F, U+2F8E6->U+6914, U+2F8E7->U+3B9D, U+2F8E8->U+6942, U+2F8E9->U+69A3, U+2F8EA->U+69EA, U+2F8EB->U+6AA8, U+2F8EC->U+236A3, U+2F8ED->U+6ADB, U+2F8EE->U+3C18, U+2F8EF->U+6B21, U+2F8F0->U+238A7, U+2F8F1->U+6B54, \
195
+    U+2F8F2->U+3C4E, U+2F8F3->U+6B72, U+2F8F4->U+6B9F, U+2F8F5->U+6BBA, U+2F8F6->U+6BBB, U+2F8F7->U+23A8D, U+2F8F8->U+21D0B, U+2F8F9->U+23AFA, U+2F8FA->U+6C4E, U+2F8FB->U+23CBC, U+2F8FC->U+6CBF, U+2F8FD->U+6CCD, U+2F8FE->U+6C67, U+2F8FF->U+6D16, U+2F900->U+6D3E, \
196
+    U+2F901->U+6D77, U+2F902->U+6D41, U+2F903->U+6D69, U+2F904->U+6D78, U+2F905->U+6D85, U+2F906->U+23D1E, U+2F907->U+6D34, U+2F908->U+6E2F, U+2F909->U+6E6E, U+2F90A->U+3D33, U+2F90B->U+6ECB, U+2F90C->U+6EC7, U+2F90D->U+23ED1, U+2F90E->U+6DF9, U+2F90F->U+6F6E, \
197
+    U+2F910->U+23F5E, U+2F911->U+23F8E, U+2F912->U+6FC6, U+2F913->U+7039, U+2F914->U+701E, U+2F915->U+701B, U+2F916->U+3D96, U+2F917->U+704A, U+2F918->U+707D, U+2F919->U+7077, U+2F91A->U+70AD, U+2F91B->U+20525, U+2F91C->U+7145, U+2F91D->U+24263, U+2F91E->U+719C, \
198
+    U+2F91F->U+243AB, U+2F920->U+7228, U+2F921->U+7235, U+2F922->U+7250, U+2F923->U+24608, U+2F924->U+7280, U+2F925->U+7295, U+2F926->U+24735, U+2F927->U+24814, U+2F928->U+737A, U+2F929->U+738B, U+2F92A->U+3EAC, U+2F92B->U+73A5, U+2F92C->U+3EB8, U+2F92D->U+3EB8, \
199
+    U+2F92E->U+7447, U+2F92F->U+745C, U+2F930->U+7471, U+2F931->U+7485, U+2F932->U+74CA, U+2F933->U+3F1B, U+2F934->U+7524, U+2F935->U+24C36, U+2F936->U+753E, U+2F937->U+24C92, U+2F938->U+7570, U+2F939->U+2219F, U+2F93A->U+7610, U+2F93B->U+24FA1, U+2F93C->U+24FB8, \
200
+    U+2F93D->U+25044, U+2F93E->U+3FFC, U+2F93F->U+4008, U+2F940->U+76F4, U+2F941->U+250F3, U+2F942->U+250F2, U+2F943->U+25119, U+2F944->U+25133, U+2F945->U+771E, U+2F946->U+771F, U+2F947->U+771F, U+2F948->U+774A, U+2F949->U+4039, U+2F94A->U+778B, U+2F94B->U+4046, \
201
+    U+2F94C->U+4096, U+2F94D->U+2541D, U+2F94E->U+784E, U+2F94F->U+788C, U+2F950->U+78CC, U+2F951->U+40E3, U+2F952->U+25626, U+2F953->U+7956, U+2F954->U+2569A, U+2F955->U+256C5, U+2F956->U+798F, U+2F957->U+79EB, U+2F958->U+412F, U+2F959->U+7A40, U+2F95A->U+7A4A, \
202
+    U+2F95B->U+7A4F, U+2F95C->U+2597C, U+2F95D->U+25AA7, U+2F95E->U+25AA7, U+2F95F->U+7AEE, U+2F960->U+4202, U+2F961->U+25BAB, U+2F962->U+7BC6, U+2F963->U+7BC9, U+2F964->U+4227, U+2F965->U+25C80, U+2F966->U+7CD2, U+2F967->U+42A0, U+2F968->U+7CE8, U+2F969->U+7CE3, \
203
+    U+2F96A->U+7D00, U+2F96B->U+25F86, U+2F96C->U+7D63, U+2F96D->U+4301, U+2F96E->U+7DC7, U+2F96F->U+7E02, U+2F970->U+7E45, U+2F971->U+4334, U+2F972->U+26228, U+2F973->U+26247, U+2F974->U+4359, U+2F975->U+262D9, U+2F976->U+7F7A, U+2F977->U+2633E, U+2F978->U+7F95, \
204
+    U+2F979->U+7FFA, U+2F97A->U+8005, U+2F97B->U+264DA, U+2F97C->U+26523, U+2F97D->U+8060, U+2F97E->U+265A8, U+2F97F->U+8070, U+2F980->U+2335F, U+2F981->U+43D5, U+2F982->U+80B2, U+2F983->U+8103, U+2F984->U+440B, U+2F985->U+813E, U+2F986->U+5AB5, U+2F987->U+267A7, \
205
+    U+2F988->U+267B5, U+2F989->U+23393, U+2F98A->U+2339C, U+2F98B->U+8201, U+2F98C->U+8204, U+2F98D->U+8F9E, U+2F98E->U+446B, U+2F98F->U+8291, U+2F990->U+828B, U+2F991->U+829D, U+2F992->U+52B3, U+2F993->U+82B1, U+2F994->U+82B3, U+2F995->U+82BD, U+2F996->U+82E6, \
206
+    U+2F997->U+26B3C, U+2F998->U+82E5, U+2F999->U+831D, U+2F99A->U+8363, U+2F99B->U+83AD, U+2F99C->U+8323, U+2F99D->U+83BD, U+2F99E->U+83E7, U+2F99F->U+8457, U+2F9A0->U+8353, U+2F9A1->U+83CA, U+2F9A2->U+83CC, U+2F9A3->U+83DC, U+2F9A4->U+26C36, U+2F9A5->U+26D6B, \
207
+    U+2F9A6->U+26CD5, U+2F9A7->U+452B, U+2F9A8->U+84F1, U+2F9A9->U+84F3, U+2F9AA->U+8516, U+2F9AB->U+273CA, U+2F9AC->U+8564, U+2F9AD->U+26F2C, U+2F9AE->U+455D, U+2F9AF->U+4561, U+2F9B0->U+26FB1, U+2F9B1->U+270D2, U+2F9B2->U+456B, U+2F9B3->U+8650, U+2F9B4->U+865C, \
208
+    U+2F9B5->U+8667, U+2F9B6->U+8669, U+2F9B7->U+86A9, U+2F9B8->U+8688, U+2F9B9->U+870E, U+2F9BA->U+86E2, U+2F9BB->U+8779, U+2F9BC->U+8728, U+2F9BD->U+876B, U+2F9BE->U+8786, U+2F9BF->U+45D7, U+2F9C0->U+87E1, U+2F9C1->U+8801, U+2F9C2->U+45F9, U+2F9C3->U+8860, \
209
+    U+2F9C4->U+8863, U+2F9C5->U+27667, U+2F9C6->U+88D7, U+2F9C7->U+88DE, U+2F9C8->U+4635, U+2F9C9->U+88FA, U+2F9CA->U+34BB, U+2F9CB->U+278AE, U+2F9CC->U+27966, U+2F9CD->U+46BE, U+2F9CE->U+46C7, U+2F9CF->U+8AA0, U+2F9D0->U+8AED, U+2F9D1->U+8B8A, U+2F9D2->U+8C55, \
210
+    U+2F9D3->U+27CA8, U+2F9D4->U+8CAB, U+2F9D5->U+8CC1, U+2F9D6->U+8D1B, U+2F9D7->U+8D77, U+2F9D8->U+27F2F, U+2F9D9->U+20804, U+2F9DA->U+8DCB, U+2F9DB->U+8DBC, U+2F9DC->U+8DF0, U+2F9DD->U+208DE, U+2F9DE->U+8ED4, U+2F9DF->U+8F38, U+2F9E0->U+285D2, U+2F9E1->U+285ED, \
211
+    U+2F9E2->U+9094, U+2F9E3->U+90F1, U+2F9E4->U+9111, U+2F9E5->U+2872E, U+2F9E6->U+911B, U+2F9E7->U+9238, U+2F9E8->U+92D7, U+2F9E9->U+92D8, U+2F9EA->U+927C, U+2F9EB->U+93F9, U+2F9EC->U+9415, U+2F9ED->U+28BFA, U+2F9EE->U+958B, U+2F9EF->U+4995, U+2F9F0->U+95B7, \
212
+    U+2F9F1->U+28D77, U+2F9F2->U+49E6, U+2F9F3->U+96C3, U+2F9F4->U+5DB2, U+2F9F5->U+9723, U+2F9F6->U+29145, U+2F9F7->U+2921A, U+2F9F8->U+4A6E, U+2F9F9->U+4A76, U+2F9FA->U+97E0, U+2F9FB->U+2940A, U+2F9FC->U+4AB2, U+2F9FD->U+29496, U+2F9FE->U+980B, U+2F9FF->U+980B, \
213
+    U+2FA00->U+9829, U+2FA01->U+295B6, U+2FA02->U+98E2, U+2FA03->U+4B33, U+2FA04->U+9929, U+2FA05->U+99A7, U+2FA06->U+99C2, U+2FA07->U+99FE, U+2FA08->U+4BCE, U+2FA09->U+29B30, U+2FA0A->U+9B12, U+2FA0B->U+9C40, U+2FA0C->U+9CFD, U+2FA0D->U+4CCE, U+2FA0E->U+4CED, \
214
+    U+2FA0F->U+9D67, U+2FA10->U+2A0CE, U+2FA11->U+4CF8, U+2FA12->U+2A105, U+2FA13->U+2A20E, U+2FA14->U+2A291, U+2FA15->U+9EBB, U+2FA16->U+4D56, U+2FA17->U+9EF9, U+2FA18->U+9EFE, U+2FA19->U+9F05, U+2FA1A->U+9F0F, U+2FA1B->U+9F16, U+2FA1C->U+9F3B, U+2FA1D->U+2A600, \
215
+    U+2F00->U+4E00, U+2F01->U+4E28, U+2F02->U+4E36, U+2F03->U+4E3F, U+2F04->U+4E59, U+2F05->U+4E85, U+2F06->U+4E8C, U+2F07->U+4EA0, U+2F08->U+4EBA, U+2F09->U+513F, U+2F0A->U+5165, U+2F0B->U+516B, U+2F0C->U+5182, U+2F0D->U+5196, U+2F0E->U+51AB, U+2F0F->U+51E0, \
216
+    U+2F10->U+51F5, U+2F11->U+5200, U+2F12->U+529B, U+2F13->U+52F9, U+2F14->U+5315, U+2F15->U+531A, U+2F16->U+5338, U+2F17->U+5341, U+2F18->U+535C, U+2F19->U+5369, U+2F1A->U+5382, U+2F1B->U+53B6, U+2F1C->U+53C8, U+2F1D->U+53E3, U+2F1E->U+56D7, U+2F1F->U+571F, \
217
+    U+2F20->U+58EB, U+2F21->U+5902, U+2F22->U+590A, U+2F23->U+5915, U+2F24->U+5927, U+2F25->U+5973, U+2F26->U+5B50, U+2F27->U+5B80, U+2F28->U+5BF8, U+2F29->U+5C0F, U+2F2A->U+5C22, U+2F2B->U+5C38, U+2F2C->U+5C6E, U+2F2D->U+5C71, U+2F2E->U+5DDB, U+2F2F->U+5DE5, \
218
+    U+2F30->U+5DF1, U+2F31->U+5DFE, U+2F32->U+5E72, U+2F33->U+5E7A, U+2F34->U+5E7F, U+2F35->U+5EF4, U+2F36->U+5EFE, U+2F37->U+5F0B, U+2F38->U+5F13, U+2F39->U+5F50, U+2F3A->U+5F61, U+2F3B->U+5F73, U+2F3C->U+5FC3, U+2F3D->U+6208, U+2F3E->U+6236, U+2F3F->U+624B, \
219
+    U+2F40->U+652F, U+2F41->U+6534, U+2F42->U+6587, U+2F43->U+6597, U+2F44->U+65A4, U+2F45->U+65B9, U+2F46->U+65E0, U+2F47->U+65E5, U+2F48->U+66F0, U+2F49->U+6708, U+2F4A->U+6728, U+2F4B->U+6B20, U+2F4C->U+6B62, U+2F4D->U+6B79, U+2F4E->U+6BB3, U+2F4F->U+6BCB, \
220
+    U+2F50->U+6BD4, U+2F51->U+6BDB, U+2F52->U+6C0F, U+2F53->U+6C14, U+2F54->U+6C34, U+2F55->U+706B, U+2F56->U+722A, U+2F57->U+7236, U+2F58->U+723B, U+2F59->U+723F, U+2F5A->U+7247, U+2F5B->U+7259, U+2F5C->U+725B, U+2F5D->U+72AC, U+2F5E->U+7384, U+2F5F->U+7389, \
221
+    U+2F60->U+74DC, U+2F61->U+74E6, U+2F62->U+7518, U+2F63->U+751F, U+2F64->U+7528, U+2F65->U+7530, U+2F66->U+758B, U+2F67->U+7592, U+2F68->U+7676, U+2F69->U+767D, U+2F6A->U+76AE, U+2F6B->U+76BF, U+2F6C->U+76EE, U+2F6D->U+77DB, U+2F6E->U+77E2, U+2F6F->U+77F3, \
222
+    U+2F70->U+793A, U+2F71->U+79B8, U+2F72->U+79BE, U+2F73->U+7A74, U+2F74->U+7ACB, U+2F75->U+7AF9, U+2F76->U+7C73, U+2F77->U+7CF8, U+2F78->U+7F36, U+2F79->U+7F51, U+2F7A->U+7F8A, U+2F7B->U+7FBD, U+2F7C->U+8001, U+2F7D->U+800C, U+2F7E->U+8012, U+2F7F->U+8033, \
223
+    U+2F80->U+807F, U+2F81->U+8089, U+2F82->U+81E3, U+2F83->U+81EA, U+2F84->U+81F3, U+2F85->U+81FC, U+2F86->U+820C, U+2F87->U+821B, U+2F88->U+821F, U+2F89->U+826E, U+2F8A->U+8272, U+2F8B->U+8278, U+2F8C->U+864D, U+2F8D->U+866B, U+2F8E->U+8840, U+2F8F->U+884C, \
224
+    U+2F90->U+8863, U+2F91->U+897E, U+2F92->U+898B, U+2F93->U+89D2, U+2F94->U+8A00, U+2F95->U+8C37, U+2F96->U+8C46, U+2F97->U+8C55, U+2F98->U+8C78, U+2F99->U+8C9D, U+2F9A->U+8D64, U+2F9B->U+8D70, U+2F9C->U+8DB3, U+2F9D->U+8EAB, U+2F9E->U+8ECA, U+2F9F->U+8F9B, \
225
+    U+2FA0->U+8FB0, U+2FA1->U+8FB5, U+2FA2->U+9091, U+2FA3->U+9149, U+2FA4->U+91C6, U+2FA5->U+91CC, U+2FA6->U+91D1, U+2FA7->U+9577, U+2FA8->U+9580, U+2FA9->U+961C, U+2FAA->U+96B6, U+2FAB->U+96B9, U+2FAC->U+96E8, U+2FAD->U+9751, U+2FAE->U+975E, U+2FAF->U+9762, \
226
+    U+2FB0->U+9769, U+2FB1->U+97CB, U+2FB2->U+97ED, U+2FB3->U+97F3, U+2FB4->U+9801, U+2FB5->U+98A8, U+2FB6->U+98DB, U+2FB7->U+98DF, U+2FB8->U+9996, U+2FB9->U+9999, U+2FBA->U+99AC, U+2FBB->U+9AA8, U+2FBC->U+9AD8, U+2FBD->U+9ADF, U+2FBE->U+9B25, U+2FBF->U+9B2F, \
227
+    U+2FC0->U+9B32, U+2FC1->U+9B3C, U+2FC2->U+9B5A, U+2FC3->U+9CE5, U+2FC4->U+9E75, U+2FC5->U+9E7F, U+2FC6->U+9EA5, U+2FC7->U+9EBB, U+2FC8->U+9EC3, U+2FC9->U+9ECD, U+2FCA->U+9ED1, U+2FCB->U+9EF9, U+2FCC->U+9EFD, U+2FCD->U+9F0E, U+2FCE->U+9F13, U+2FCF->U+9F20, \
228
+    U+2FD0->U+9F3B, U+2FD1->U+9F4A, U+2FD2->U+9F52, U+2FD3->U+9F8D, U+2FD4->U+9F9C, U+2FD5->U+9FA0, U+3042->U+3041, U+3044->U+3043, U+3046->U+3045, U+3048->U+3047, U+304A->U+3049, U+304C->U+304B, U+304E->U+304D, U+3050->U+304F, U+3052->U+3051, U+3054->U+3053, \
229
+    U+3056->U+3055, U+3058->U+3057, U+305A->U+3059, U+305C->U+305B, U+305E->U+305D, U+3060->U+305F, U+3062->U+3061, U+3064->U+3063, U+3065->U+3063, U+3067->U+3066, U+3069->U+3068, U+3070->U+306F, U+3071->U+306F, U+3073->U+3072, U+3074->U+3072, U+3076->U+3075, \
230
+    U+3077->U+3075, U+3079->U+3078, U+307A->U+3078, U+307C->U+307B, U+307D->U+307B, U+3084->U+3083, U+3086->U+3085, U+3088->U+3087, U+308F->U+308E, U+3094->U+3046, U+3095->U+304B, U+3096->U+3051, U+30A2->U+30A1, U+30A4->U+30A3, U+30A6->U+30A5, U+30A8->U+30A7, \
231
+    U+30AA->U+30A9, U+30AC->U+30AB, U+30AE->U+30AD, U+30B0->U+30AF, U+30B2->U+30B1, U+30B4->U+30B3, U+30B6->U+30B5, U+30B8->U+30B7, U+30BA->U+30B9, U+30BC->U+30BB, U+30BE->U+30BD, U+30C0->U+30BF, U+30C2->U+30C1, U+30C5->U+30C4, U+30C7->U+30C6, U+30C9->U+30C8, \
232
+    U+30D0->U+30CF, U+30D1->U+30CF, U+30D3->U+30D2, U+30D4->U+30D2, U+30D6->U+30D5, U+30D7->U+30D5, U+30D9->U+30D8, U+30DA->U+30D8, U+30DC->U+30DB, U+30DD->U+30DB, U+30E4->U+30E3, U+30E6->U+30E5, U+30E8->U+30E7, U+30EF->U+30EE, U+30F4->U+30A6, U+30AB->U+30F5, \
233
+    U+30B1->U+30F6, U+30F7->U+30EF, U+30F8->U+30F0, U+30F9->U+30F1, U+30FA->U+30F2, U+30AF->U+31F0, U+30B7->U+31F1, U+30B9->U+31F2, U+30C8->U+31F3, U+30CC->U+31F4, U+30CF->U+31F5, U+30D2->U+31F6, U+30D5->U+31F7, U+30D8->U+31F8, U+30DB->U+31F9, U+30E0->U+31FA, \
234
+    U+30E9->U+31FB, U+30EA->U+31FC, U+30EB->U+31FD, U+30EC->U+31FE, U+30ED->U+31FF, U+FF66->U+30F2, U+FF67->U+30A1, U+FF68->U+30A3, U+FF69->U+30A5, U+FF6A->U+30A7, U+FF6B->U+30A9, U+FF6C->U+30E3, U+FF6D->U+30E5, U+FF6E->U+30E7, U+FF6F->U+30C3, U+FF71->U+30A1, \
235
+    U+FF72->U+30A3, U+FF73->U+30A5, U+FF74->U+30A7, U+FF75->U+30A9, U+FF76->U+30AB, U+FF77->U+30AD, U+FF78->U+30AF, U+FF79->U+30B1, U+FF7A->U+30B3, U+FF7B->U+30B5, U+FF7C->U+30B7, U+FF7D->U+30B9, U+FF7E->U+30BB, U+FF7F->U+30BD, U+FF80->U+30BF, U+FF81->U+30C1, \
236
+    U+FF82->U+30C3, U+FF83->U+30C6, U+FF84->U+30C8, U+FF85->U+30CA, U+FF86->U+30CB, U+FF87->U+30CC, U+FF88->U+30CD, U+FF89->U+30CE, U+FF8A->U+30CF, U+FF8B->U+30D2, U+FF8C->U+30D5, U+FF8D->U+30D8, U+FF8E->U+30DB, U+FF8F->U+30DE, U+FF90->U+30DF, U+FF91->U+30E0, \
237
+    U+FF92->U+30E1, U+FF93->U+30E2, U+FF94->U+30E3, U+FF95->U+30E5, U+FF96->U+30E7, U+FF97->U+30E9, U+FF98->U+30EA, U+FF99->U+30EB, U+FF9A->U+30EC, U+FF9B->U+30ED, U+FF9C->U+30EF, U+FF9D->U+30F3, U+FFA0->U+3164, U+FFA1->U+3131, U+FFA2->U+3132, U+FFA3->U+3133, \
238
+    U+FFA4->U+3134, U+FFA5->U+3135, U+FFA6->U+3136, U+FFA7->U+3137, U+FFA8->U+3138, U+FFA9->U+3139, U+FFAA->U+313A, U+FFAB->U+313B, U+FFAC->U+313C, U+FFAD->U+313D, U+FFAE->U+313E, U+FFAF->U+313F, U+FFB0->U+3140, U+FFB1->U+3141, U+FFB2->U+3142, U+FFB3->U+3143, \
239
+    U+FFB4->U+3144, U+FFB5->U+3145, U+FFB6->U+3146, U+FFB7->U+3147, U+FFB8->U+3148, U+FFB9->U+3149, U+FFBA->U+314A, U+FFBB->U+314B, U+FFBC->U+314C, U+FFBD->U+314D, U+FFBE->U+314E, U+FFC2->U+314F, U+FFC3->U+3150, U+FFC4->U+3151, U+FFC5->U+3152, U+FFC6->U+3153, \
240
+    U+FFC7->U+3154, U+FFCA->U+3155, U+FFCB->U+3156, U+FFCC->U+3157, U+FFCD->U+3158, U+FFCE->U+3159, U+FFCF->U+315A, U+FFD2->U+315B, U+FFD3->U+315C, U+FFD4->U+315D, U+FFD5->U+315E, U+FFD6->U+315F, U+FFD7->U+3160, U+FFDA->U+3161, U+FFDB->U+3162, U+FFDC->U+3163, \
241
+    U+3131->U+1100, U+3132->U+1101, U+3133->U+11AA, U+3134->U+1102, U+3135->U+11AC, U+3136->U+11AD, U+3137->U+1103, U+3138->U+1104, U+3139->U+1105, U+313A->U+11B0, U+313B->U+11B1, U+313C->U+11B2, U+313D->U+11B3, U+313E->U+11B4, U+313F->U+11B5, U+3140->U+111A, \
242
+    U+3141->U+1106, U+3142->U+1107, U+3143->U+1108, U+3144->U+1121, U+3145->U+1109, U+3146->U+110A, U+3147->U+110B, U+3148->U+110C, U+3149->U+110D, U+314A->U+110E, U+314B->U+110F, U+314C->U+1110, U+314D->U+1111, U+314E->U+1112, U+314F->U+1161, U+3150->U+1162, \
243
+    U+3151->U+1163, U+3152->U+1164, U+3153->U+1165, U+3154->U+1166, U+3155->U+1167, U+3156->U+1168, U+3157->U+1169, U+3158->U+116A, U+3159->U+116B, U+315A->U+116C, U+315B->U+116D, U+315C->U+116E, U+315D->U+116F, U+315E->U+1170, U+315F->U+1171, U+3160->U+1172, \
244
+    U+3161->U+1173, U+3162->U+1174, U+3163->U+1175, U+3165->U+1114, U+3166->U+1115, U+3167->U+11C7, U+3168->U+11C8, U+3169->U+11CC, U+316A->U+11CE, U+316B->U+11D3, U+316C->U+11D7, U+316D->U+11D9, U+316E->U+111C, U+316F->U+11DD, U+3170->U+11DF, U+3171->U+111D, \
245
+    U+3172->U+111E, U+3173->U+1120, U+3174->U+1122, U+3175->U+1123, U+3176->U+1127, U+3177->U+1129, U+3178->U+112B, U+3179->U+112C, U+317A->U+112D, U+317B->U+112E, U+317C->U+112F, U+317D->U+1132, U+317E->U+1136, U+317F->U+1140, U+3180->U+1147, U+3181->U+114C, \
246
+    U+3182->U+11F1, U+3183->U+11F2, U+3184->U+1157, U+3185->U+1158, U+3186->U+1159, U+3187->U+1184, U+3188->U+1185, U+3189->U+1188, U+318A->U+1191, U+318B->U+1192, U+318C->U+1194, U+318D->U+119E, U+318E->U+11A1, U+A490->U+A408, U+A491->U+A1B9, U+4E00..U+9FBB, \
247
+    U+3400..U+4DB5, U+20000..U+2A6D6, U+FA0E, U+FA0F, U+FA11, U+FA13, U+FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27, U+FA28, U+FA29, U+3105..U+312C, U+31A0..U+31B7, U+3041, U+3043, U+3045, U+3047, U+3049, U+304B, U+304D, U+304F, U+3051, U+3053, U+3055, U+3057, \
248
+    U+3059, U+305B, U+305D, U+305F, U+3061, U+3063, U+3066, U+3068, U+306A..U+306F, U+3072, U+3075, U+3078, U+307B, U+307E..U+3083, U+3085, U+3087, U+3089..U+308E, U+3090..U+3093, U+30A1, U+30A3, U+30A5, U+30A7, U+30A9, U+30AD, U+30AF, U+30B3, U+30B5, U+30BB, \
249
+    U+30BD, U+30BF, U+30C1, U+30C3, U+30C4, U+30C6, U+30CA, U+30CB, U+30CD, U+30CE, U+30DE, U+30DF, U+30E1, U+30E2, U+30E3, U+30E5, U+30E7, U+30EE, U+30F0..U+30F3, U+30F5, U+30F6, U+31F0, U+31F1, U+31F2, U+31F3, U+31F4, U+31F5, U+31F6, U+31F7, U+31F8, U+31F9, \
250
+    U+31FA, U+31FB, U+31FC, U+31FD, U+31FE, U+31FF, U+AC00..U+D7A3, U+1100..U+1159, U+1161..U+11A2, U+11A8..U+11F9, U+A000..U+A48C, U+A492..U+A4C6, U+2C80->U+2C81, U+2C81, U+2C82->U+2C83, U+2C83, U+2C84->U+2C85, U+2C85, U+2C86->U+2C87, U+2C87, U+2C88->U+2C89, \
251
+    U+2C89, U+2C8A->U+2C8B, U+2C8B, U+2C8C->U+2C8D, U+2C8D, U+2C8E->U+2C8F, U+2C8F, U+2C90->U+2C91, U+2C91, U+2C92->U+2C93, U+2C93, U+2C94->U+2C95, U+2C95, U+2C96->U+2C97, U+2C97, U+2C98->U+2C99, U+2C99, U+2C9A->U+2C9B, U+2C9B, U+2C9C->U+2C9D, U+2C9D, U+2C9E->U+2C9F, \
252
+    U+2C9F, U+2CA0->U+2CA1, U+2CA1, U+2CA2->U+2CA3, U+2CA3, U+2CA4->U+2CA5, U+2CA5, U+2CA6->U+2CA7, U+2CA7, U+2CA8->U+2CA9, U+2CA9, U+2CAA->U+2CAB, U+2CAB, U+2CAC->U+2CAD, U+2CAD, U+2CAE->U+2CAF, U+2CAF, U+2CB0->U+2CB1, U+2CB1, U+2CB2->U+2CB3, U+2CB3, U+2CB4->U+2CB5, \
253
+    U+2CB5, U+2CB6->U+2CB7, U+2CB7, U+2CB8->U+2CB9, U+2CB9, U+2CBA->U+2CBB, U+2CBB, U+2CBC->U+2CBD, U+2CBD, U+2CBE->U+2CBF, U+2CBF, U+2CC0->U+2CC1, U+2CC1, U+2CC2->U+2CC3, U+2CC3, U+2CC4->U+2CC5, U+2CC5, U+2CC6->U+2CC7, U+2CC7, U+2CC8->U+2CC9, U+2CC9, U+2CCA->U+2CCB, \
254
+    U+2CCB, U+2CCC->U+2CCD, U+2CCD, U+2CCE->U+2CCF, U+2CCF, U+2CD0->U+2CD1, U+2CD1, U+2CD2->U+2CD3, U+2CD3, U+2CD4->U+2CD5, U+2CD5, U+2CD6->U+2CD7, U+2CD7, U+2CD8->U+2CD9, U+2CD9, U+2CDA->U+2CDB, U+2CDB, U+2CDC->U+2CDD, U+2CDD, U+2CDE->U+2CDF, U+2CDF, U+2CE0->U+2CE1, \
255
+    U+2CE1, U+2CE2->U+2CE3, U+2CE3, U+0400->U+0435, U+0401->U+0435, U+0402->U+0452, U+0452, U+0403->U+0433, U+0404->U+0454, U+0454, U+0405->U+0455, U+0455, U+0406->U+0456, U+0407->U+0456, U+0457->U+0456, U+0456, U+0408..U+040B->U+0458..U+045B, U+0458..U+045B, \
256
+    U+040C->U+043A, U+040D->U+0438, U+040E->U+0443, U+040F->U+045F, U+045F, U+0450->U+0435, U+0451->U+0435, U+0453->U+0433, U+045C->U+043A, U+045D->U+0438, U+045E->U+0443, U+0460->U+0461, U+0461, U+0462->U+0463, U+0463, U+0464->U+0465, U+0465, U+0466->U+0467, \
257
+    U+0467, U+0468->U+0469, U+0469, U+046A->U+046B, U+046B, U+046C->U+046D, U+046D, U+046E->U+046F, U+046F, U+0470->U+0471, U+0471, U+0472->U+0473, U+0473, U+0474->U+0475, U+0476->U+0475, U+0477->U+0475, U+0475, U+0478->U+0479, U+0479, U+047A->U+047B, U+047B, \
258
+    U+047C->U+047D, U+047D, U+047E->U+047F, U+047F, U+0480->U+0481, U+0481, U+048A->U+0438, U+048B->U+0438, U+048C->U+044C, U+048D->U+044C, U+048E->U+0440, U+048F->U+0440, U+0490->U+0433, U+0491->U+0433, U+0490->U+0433, U+0491->U+0433, U+0492->U+0433, U+0493->U+0433, \
259
+    U+0494->U+0433, U+0495->U+0433, U+0496->U+0436, U+0497->U+0436, U+0498->U+0437, U+0499->U+0437, U+049A->U+043A, U+049B->U+043A, U+049C->U+043A, U+049D->U+043A, U+049E->U+043A, U+049F->U+043A, U+04A0->U+043A, U+04A1->U+043A, U+04A2->U+043D, U+04A3->U+043D, \
260
+    U+04A4->U+043D, U+04A5->U+043D, U+04A6->U+043F, U+04A7->U+043F, U+04A8->U+04A9, U+04A9, U+04AA->U+0441, U+04AB->U+0441, U+04AC->U+0442, U+04AD->U+0442, U+04AE->U+0443, U+04AF->U+0443, U+04B0->U+0443, U+04B1->U+0443, U+04B2->U+0445, U+04B3->U+0445, U+04B4->U+04B5, \
261
+    U+04B5, U+04B6->U+0447, U+04B7->U+0447, U+04B8->U+0447, U+04B9->U+0447, U+04BA->U+04BB, U+04BB, U+04BC->U+04BD, U+04BE->U+04BD, U+04BF->U+04BD, U+04BD, U+04C0->U+04CF, U+04CF, U+04C1->U+0436, U+04C2->U+0436, U+04C3->U+043A, U+04C4->U+043A, U+04C5->U+043B, \
262
+    U+04C6->U+043B, U+04C7->U+043D, U+04C8->U+043D, U+04C9->U+043D, U+04CA->U+043D, U+04CB->U+0447, U+04CC->U+0447, U+04CD->U+043C, U+04CE->U+043C, U+04D0->U+0430, U+04D1->U+0430, U+04D2->U+0430, U+04D3->U+0430, U+04D4->U+00E6, U+04D5->U+00E6, U+04D6->U+0435, \
263
+    U+04D7->U+0435, U+04D8->U+04D9, U+04DA->U+04D9, U+04DB->U+04D9, U+04D9, U+04DC->U+0436, U+04DD->U+0436, U+04DE->U+0437, U+04DF->U+0437, U+04E0->U+04E1, U+04E1, U+04E2->U+0438, U+04E3->U+0438, U+04E4->U+0438, U+04E5->U+0438, U+04E6->U+043E, U+04E7->U+043E, \
264
+    U+04E8->U+043E, U+04E9->U+043E, U+04EA->U+043E, U+04EB->U+043E, U+04EC->U+044D, U+04ED->U+044D, U+04EE->U+0443, U+04EF->U+0443, U+04F0->U+0443, U+04F1->U+0443, U+04F2->U+0443, U+04F3->U+0443, U+04F4->U+0447, U+04F5->U+0447, U+04F6->U+0433, U+04F7->U+0433, \
265
+    U+04F8->U+044B, U+04F9->U+044B, U+04FA->U+0433, U+04FB->U+0433, U+04FC->U+0445, U+04FD->U+0445, U+04FE->U+0445, U+04FF->U+0445, U+0410..U+0418->U+0430..U+0438, U+0419->U+0438, U+0430..U+0438, U+041A..U+042F->U+043A..U+044F, U+043A..U+044F, U+0929->U+0928, \
266
+    U+0931->U+0930, U+0934->U+0933, U+0958->U+0915, U+0959->U+0916, U+095A->U+0917, U+095B->U+091C, U+095C->U+0921, U+095D->U+0922, U+095E->U+092B, U+095F->U+092F, U+0904..U+0928, U+092A..U+0930, U+0932, U+0933, U+0935..U+0939, U+0960, U+0961, U+0966..U+096F, \
267
+    U+097B..U+097F, U+10FC->U+10DC, U+10D0..U+10FA, U+10A0..U+10C5->U+2D00..U+2D25, U+2D00..U+2D25, U+0386->U+03B1, U+0388->U+03B5, U+0389->U+03B7, U+038A->U+03B9, U+038C->U+03BF, U+038E->U+03C5, U+038F->U+03C9, U+0390->U+03B9, U+03AA->U+03B9, U+03AB->U+03C5, \
268
+    U+03AC->U+03B1, U+03AD->U+03B5, U+03AE->U+03B7, U+03AF->U+03B9, U+03B0->U+03C5, U+03CA->U+03B9, U+03CB->U+03C5, U+03CC->U+03BF, U+03CD->U+03C5, U+03CE->U+03C9, U+03D0->U+03B2, U+03D1->U+03B8, U+03D2->U+03C5, U+03D3->U+03C5, U+03D4->U+03C5, U+03D5->U+03C6, \
269
+    U+03D6->U+03C0, U+03D8->U+03D9, U+03DA->U+03DB, U+03DC->U+03DD, U+03DE->U+03DF, U+03E0->U+03E1, U+03E2->U+03E3, U+03E4->U+03E5, U+03E6->U+03E7, U+03E8->U+03E9, U+03EA->U+03EB, U+03EC->U+03ED, U+03EE->U+03EF, U+03F0->U+03BA, U+03F1->U+03C1, U+03F2->U+03C3, \
270
+    U+03F4->U+03B8, U+03F5->U+03B5, U+03F6->U+03B5, U+03F7->U+03F8, U+03F9->U+03C3, U+03FA->U+03FB, U+1F00->U+03B1, U+1F01->U+03B1, U+1F02->U+03B1, U+1F03->U+03B1, U+1F04->U+03B1, U+1F05->U+03B1, U+1F06->U+03B1, U+1F07->U+03B1, U+1F08->U+03B1, U+1F09->U+03B1, \
271
+    U+1F0A->U+03B1, U+1F0B->U+03B1, U+1F0C->U+03B1, U+1F0D->U+03B1, U+1F0E->U+03B1, U+1F0F->U+03B1, U+1F10->U+03B5, U+1F11->U+03B5, U+1F12->U+03B5, U+1F13->U+03B5, U+1F14->U+03B5, U+1F15->U+03B5, U+1F18->U+03B5, U+1F19->U+03B5, U+1F1A->U+03B5, U+1F1B->U+03B5, \
272
+    U+1F1C->U+03B5, U+1F1D->U+03B5, U+1F20->U+03B7, U+1F21->U+03B7, U+1F22->U+03B7, U+1F23->U+03B7, U+1F24->U+03B7, U+1F25->U+03B7, U+1F26->U+03B7, U+1F27->U+03B7, U+1F28->U+03B7, U+1F29->U+03B7, U+1F2A->U+03B7, U+1F2B->U+03B7, U+1F2C->U+03B7, U+1F2D->U+03B7, \
273
+    U+1F2E->U+03B7, U+1F2F->U+03B7, U+1F30->U+03B9, U+1F31->U+03B9, U+1F32->U+03B9, U+1F33->U+03B9, U+1F34->U+03B9, U+1F35->U+03B9, U+1F36->U+03B9, U+1F37->U+03B9, U+1F38->U+03B9, U+1F39->U+03B9, U+1F3A->U+03B9, U+1F3B->U+03B9, U+1F3C->U+03B9, U+1F3D->U+03B9, \
274
+    U+1F3E->U+03B9, U+1F3F->U+03B9, U+1F40->U+03BF, U+1F41->U+03BF, U+1F42->U+03BF, U+1F43->U+03BF, U+1F44->U+03BF, U+1F45->U+03BF, U+1F48->U+03BF, U+1F49->U+03BF, U+1F4A->U+03BF, U+1F4B->U+03BF, U+1F4C->U+03BF, U+1F4D->U+03BF, U+1F50->U+03C5, U+1F51->U+03C5, \
275
+    U+1F52->U+03C5, U+1F53->U+03C5, U+1F54->U+03C5, U+1F55->U+03C5, U+1F56->U+03C5, U+1F57->U+03C5, U+1F59->U+03C5, U+1F5B->U+03C5, U+1F5D->U+03C5, U+1F5F->U+03C5, U+1F60->U+03C9, U+1F61->U+03C9, U+1F62->U+03C9, U+1F63->U+03C9, U+1F64->U+03C9, U+1F65->U+03C9, \
276
+    U+1F66->U+03C9, U+1F67->U+03C9, U+1F68->U+03C9, U+1F69->U+03C9, U+1F6A->U+03C9, U+1F6B->U+03C9, U+1F6C->U+03C9, U+1F6D->U+03C9, U+1F6E->U+03C9, U+1F6F->U+03C9, U+1F70->U+03B1, U+1F71->U+03B1, U+1F72->U+03B5, U+1F73->U+03B5, U+1F74->U+03B7, U+1F75->U+03B7, \
277
+    U+1F76->U+03B9, U+1F77->U+03B9, U+1F78->U+03BF, U+1F79->U+03BF, U+1F7A->U+03C5, U+1F7B->U+03C5, U+1F7C->U+03C9, U+1F7D->U+03C9, U+1F80->U+03B1, U+1F81->U+03B1, U+1F82->U+03B1, U+1F83->U+03B1, U+1F84->U+03B1, U+1F85->U+03B1, U+1F86->U+03B1, U+1F87->U+03B1, \
278
+    U+1F88->U+03B1, U+1F89->U+03B1, U+1F8A->U+03B1, U+1F8B->U+03B1, U+1F8C->U+03B1, U+1F8D->U+03B1, U+1F8E->U+03B1, U+1F8F->U+03B1, U+1F90->U+03B7, U+1F91->U+03B7, U+1F92->U+03B7, U+1F93->U+03B7, U+1F94->U+03B7, U+1F95->U+03B7, U+1F96->U+03B7, U+1F97->U+03B7, \
279
+    U+1F98->U+03B7, U+1F99->U+03B7, U+1F9A->U+03B7, U+1F9B->U+03B7, U+1F9C->U+03B7, U+1F9D->U+03B7, U+1F9E->U+03B7, U+1F9F->U+03B7, U+1FA0->U+03C9, U+1FA1->U+03C9, U+1FA2->U+03C9, U+1FA3->U+03C9, U+1FA4->U+03C9, U+1FA5->U+03C9, U+1FA6->U+03C9, U+1FA7->U+03C9, \
280
+    U+1FA8->U+03C9, U+1FA9->U+03C9, U+1FAA->U+03C9, U+1FAB->U+03C9, U+1FAC->U+03C9, U+1FAD->U+03C9, U+1FAE->U+03C9, U+1FAF->U+03C9, U+1FB0->U+03B1, U+1FB1->U+03B1, U+1FB2->U+03B1, U+1FB3->U+03B1, U+1FB4->U+03B1, U+1FB6->U+03B1, U+1FB7->U+03B1, U+1FB8->U+03B1, \
281
+    U+1FB9->U+03B1, U+1FBA->U+03B1, U+1FBB->U+03B1, U+1FBC->U+03B1, U+1FC2->U+03B7, U+1FC3->U+03B7, U+1FC4->U+03B7, U+1FC6->U+03B7, U+1FC7->U+03B7, U+1FC8->U+03B5, U+1FC9->U+03B5, U+1FCA->U+03B7, U+1FCB->U+03B7, U+1FCC->U+03B7, U+1FD0->U+03B9, U+1FD1->U+03B9, \
282
+    U+1FD2->U+03B9, U+1FD3->U+03B9, U+1FD6->U+03B9, U+1FD7->U+03B9, U+1FD8->U+03B9, U+1FD9->U+03B9, U+1FDA->U+03B9, U+1FDB->U+03B9, U+1FE0->U+03C5, U+1FE1->U+03C5, U+1FE2->U+03C5, U+1FE3->U+03C5, U+1FE4->U+03C1, U+1FE5->U+03C1, U+1FE6->U+03C5, U+1FE7->U+03C5, \
283
+    U+1FE8->U+03C5, U+1FE9->U+03C5, U+1FEA->U+03C5, U+1FEB->U+03C5, U+1FEC->U+03C1, U+1FF2->U+03C9, U+1FF3->U+03C9, U+1FF4->U+03C9, U+1FF6->U+03C9, U+1FF7->U+03C9, U+1FF8->U+03BF, U+1FF9->U+03BF, U+1FFA->U+03C9, U+1FFB->U+03C9, U+1FFC->U+03C9, U+0391..U+03A1->U+03B1..U+03C1, \
284
+    U+03B1..U+03C1, U+03A3..U+03A9->U+03C3..U+03C9, U+03C3..U+03C9, U+03C2, U+03D9, U+03DB, U+03DD, U+03DF, U+03E1, U+03E3, U+03E5, U+03E7, U+03E9, U+03EB, U+03ED, U+03EF, U+03F3, U+03F8, U+03FB, U+0A85..U+0A8C, U+0A8F, U+0A90, U+0A93..U+0AB0, U+0AB2, U+0AB3, \
285
+    U+0AB5..U+0AB9, U+0AE0, U+0AE1, U+0AE6..U+0AEF, U+0A33->U+0A32, U+0A36->U+0A38, U+0A59->U+0A16, U+0A5A->U+0A17, U+0A5B->U+0A1C, U+0A5E->U+0A2B, U+0A05..U+0A0A, U+0A0F, U+0A10, U+0A13..U+0A28, U+0A2A..U+0A30, U+0A32, U+0A35, U+0A38, U+0A39, U+0A5C, U+0A66..U+0A6F, \
286
+    U+FB1D->U+05D9, U+FB1F->U+05F2, U+FB20->U+05E2, U+FB21->U+05D0, U+FB22->U+05D3, U+FB23->U+05D4, U+FB24->U+05DB, U+FB25->U+05DC, U+FB26->U+05DD, U+FB27->U+05E8, U+FB28->U+05EA, U+FB2A->U+05E9, U+FB2B->U+05E9, U+FB2C->U+05E9, U+FB2D->U+05E9, U+FB2E->U+05D0, \
287
+    U+FB2F->U+05D0, U+FB30->U+05D0, U+FB31->U+05D1, U+FB32->U+05D2, U+FB33->U+05D3, U+FB34->U+05D4, U+FB35->U+05D5, U+FB36->U+05D6, U+FB38->U+05D8, U+FB39->U+05D9, U+FB3A->U+05DA, U+FB3B->U+05DB, U+FB3C->U+05DC, U+FB3E->U+05DE, U+FB40->U+05E0, U+FB41->U+05E1, \
288
+    U+FB43->U+05E3, U+FB44->U+05E4, U+FB46->U+05E6, U+FB47->U+05E7, U+FB48->U+05E8, U+FB49->U+05E9, U+FB4A->U+05EA, U+FB4B->U+05D5, U+FB4C->U+05D1, U+FB4D->U+05DB, U+FB4E->U+05E4, U+FB4F->U+05D0, U+05D0..U+05F2, U+0C85..U+0C8C, U+0C8E..U+0C90, U+0C92..U+0CA8, \
289
+    U+0CAA..U+0CB3, U+0CB5..U+0CB9, U+0CE0, U+0CE1, U+0CE6..U+0CEF, U+1900..U+191C, U+1930..U+1938, U+1946..U+194F, U+0D05..U+0D0C, U+0D0E..U+0D10, U+0D12..U+0D28, U+0D2A..U+0D39, U+0D60, U+0D61, U+0D66..U+0D6F, U+0B94->U+0B92, U+0B85..U+0B8A, U+0B8E..U+0B90, \
290
+    U+0B92, U+0B93, U+0B95, U+0B99, U+0B9A, U+0B9C, U+0B9E, U+0B9F, U+0BA3, U+0BA4, U+0BA8..U+0BAA, U+0BAE..U+0BB9, U+0BE6..U+0BEF, U+0E01..U+0E30, U+0E32, U+0E33, U+0E40..U+0E46, U+0E50..U+0E5B, U+FF10..U+FF19->0..9, U+FF21..U+FF3A->a..z, U+FF41..U+FF5A->a..z, \
291
+    U+3040..U+309F, U+30A0..U+30FF, \
292
+    0..9, A..Z->a..z, a..z, _
293
+
294
+    blend_chars = !, ", U+23, $, %, &, ', (, ), *, +, U+2C, -, ., /, :, U+3B, <, =, >, ?, @, U+5B, U+5C, U+5D, ^, U+60, U+7C, U+7E, U+A1..U+BF
295
+    blend_mode = trim_none, trim_head, trim_tail, trim_both
296
+}
297
+
298
+source delta : torrents_base {
299
+    sql_query = SELECT *, Year AS yearfulltext, '_all' AS fake FROM sphinx_delta WHERE Size > 0;
300
+    sql_query_killlist = SELECT ID FROM sphinx_delta
301
+}
302
+
303
+index delta : torrents {
304
+    source = delta
305
+    path = /var/lib/sphinxsearch/delta
306
+}
307
+
308
+source requests_base : connect {
309
+    sql_attr_uint = UserID
310
+    sql_attr_uint = TimeAdded
311
+    sql_attr_uint = LastVote
312
+    sql_attr_uint = CategoryID
313
+    sql_attr_uint = FillerID
314
+    sql_attr_uint = TorrentID
315
+    sql_attr_uint = TimeFilled
316
+    sql_attr_uint = Visible
317
+    sql_attr_uint = Votes
318
+    sql_attr_uint = Bounty
319
+}
320
+
321
+source requests : requests_base {
322
+    sql_query_pre = TRUNCATE TABLE sphinx_requests
323
+    sql_query_pre = SET group_concat_max_len = 10140
324
+    sql_query_pre = SET @starttime = NOW()
325
+    sql_query_pre = REPLACE INTO sphinx_index_last_pos VALUES ('requests', UNIX_TIMESTAMP(@starttime))
326
+
327
+    sql_query_pre = INSERT INTO sphinx_requests ( \
328
+                ID, UserID, TimeAdded, LastVote, CategoryID, Title, \
329
+                TitleJP, CatalogueNumber, DLSiteID, FillerID, \
330
+                TorrentID, TimeFilled, Visible, Votes, Bounty ) \
331
+            SELECT \
332
+                r.ID, r.UserID, UNIX_TIMESTAMP(TimeAdded), \
333
+                UNIX_TIMESTAMP(LastVote), CategoryID, Title, \
334
+                TitleJP, CatalogueNumber, DLSiteID, \
335
+                FillerID, TorrentID, \
336
+                UNIX_TIMESTAMP(TimeFilled), Visible, \
337
+                COUNT(rv.RequestID), SUM(rv.Bounty) >> 10 \
338
+            FROM requests AS r \
339
+                JOIN requests_votes AS rv ON rv.RequestID = r.ID \
340
+            GROUP BY rv.RequestID
341
+
342
+    sql_query_pre = INSERT INTO sphinx_requests ( \
343
+                ID, ArtistList ) \
344
+            SELECT \
345
+                RequestID, \
346
+                GROUP_CONCAT(ag.Name SEPARATOR ' ') \
347
+            FROM requests_artists AS ra \
348
+                JOIN artists_group AS ag ON ag.ArtistID = ra.ArtistID \
349
+                JOIN requests AS r ON r.ID = ra.RequestID \
350
+            WHERE TimeAdded <= @starttime \
351
+            GROUP BY r.ID \
352
+            ON DUPLICATE KEY UPDATE ArtistList = VALUES(ArtistList)
353
+
354
+    sql_query = SELECT ID, UserID, TimeAdded, LastVote, CategoryID, Title, \
355
+                TitleJP, ArtistList, CatalogueNumber, DLSiteID, FillerID, \
356
+                TorrentID, TimeFilled, Visible, Votes, Bounty \
357
+            FROM sphinx_requests
358
+
359
+    sql_joined_field = taglist from query; \
360
+        SELECT rt.RequestID, REPLACE(t.Name, '.', '_') \
361
+        FROM requests_tags AS rt \
362
+            JOIN tags AS t ON TagID = ID \
363
+        ORDER BY requestid ASC;
364
+
365
+    sql_attr_multi = uint Voter from query; \
366
+        SELECT RequestID AS ID, UserID FROM requests_votes
367
+
368
+    sql_attr_multi = uint Bookmarker from query; \
369
+        SELECT RequestID AS ID, UserID FROM bookmarks_requests
370
+
371
+    sql_query_post_index = DELETE FROM sphinx_requests_delta WHERE TimeAdded <= \
372
+        (SELECT ID FROM sphinx_index_last_pos WHERE type = 'requests')
373
+}
374
+
375
+source requests_delta : requests_base {
376
+    sql_query = SELECT ID, UserID, TimeAdded, LastVote, CategoryID, Title, TitleJP, TagList, \
377
+                ArtistList, CatalogueNumber, DLSiteID, FillerID, \
378
+                TorrentID, TimeFilled, Visible, Votes, Bounty \
379
+            FROM sphinx_requests_delta
380
+
381
+    sql_query_killlist = SELECT ID FROM sphinx_requests_delta
382
+
383
+    sql_attr_multi = uint Voter from query; \
384
+        SELECT v.RequestID, v.UserID FROM requests_votes AS v \
385
+        JOIN sphinx_requests_delta AS d ON d.ID = v.RequestID
386
+
387
+    sql_attr_multi = uint Bookmarker from query; \
388
+        SELECT b.RequestID, b.UserID FROM bookmarks_requests AS b \
389
+        JOIN sphinx_requests_delta AS d ON d.ID = b.RequestID
390
+}
391
+
392
+index requests : torrents {
393
+    source = requests
394
+    path = /var/lib/sphinxsearch/requests
395
+    min_infix_len = 3
396
+}
397
+
398
+index requests_delta : requests {
399
+    source = requests_delta
400
+    path = /var/lib/sphinxsearch/requests_delta
401
+}
402
+
403
+source log : connect {
404
+    sql_attr_uint = Time
405
+    sql_query = SELECT ID, UNIX_TIMESTAMP(Time) AS Time, Message FROM log
406
+    sql_query_post_index = REPLACE INTO sphinx_index_last_pos VALUES ('log', $maxid)
407
+}
408
+
409
+source log_delta : log {
410
+    sql_query_pre = SELECT ID FROM sphinx_index_last_pos WHERE type = 'log' INTO @lastid
411
+    sql_query = SELECT ID, UNIX_TIMESTAMP(Time) AS Time, Message FROM log WHERE ID > @lastid
412
+    sql_query_post_index = SET @nothing = 0
413
+}
414
+
415
+index log : torrents {
416
+    source = log
417
+    path = /var/lib/sphinxsearch/log
418
+    min_word_len = 1
419
+    min_infix_len = 0
420
+}
421
+
422
+index log_delta : log {
423
+    source = log_delta
424
+    path = /var/lib/sphinxsearch/log_delta
425
+}
426
+
427
+indexer {
428
+    mem_limit = 64M
429
+}
430
+
431
+searchd {
432
+    listen = localhost:9312
433
+    listen = localhost:9306:mysql41
434
+    log = /var/log/searchd/searchd.log
435
+    query_log = /var/log/searchd/query.log
436
+    pid_file = /var/log/searchd/searchd.pid
437
+    mva_updates_pool = 16M
438
+}

Loading…
Cancel
Save