* [sisyphus] странное и некрасивое поведение utf8 в паре rails/mysql
@ 2009-06-24 16:31 Michael Bykov
2009-06-25 6:57 ` Anton V. Boyarshinov
0 siblings, 1 reply; 6+ messages in thread
From: Michael Bykov @ 2009-06-24 16:31 UTC (permalink / raw)
To: ALT Linux Sisyphus discussions
Вторая строка - корректный результат, первая загадочна:
первая буква слова в поле wo_stress, по которому я ищу, ἰ = 0xF130, а
в значении, которое mysql нашёл, ἱ = 0x1F31. То есть это разные
строки!
>> Dict.find_all_by_wo_stress "ἰκετευω"
=> [#<Dict id: 81723, parent_id: nil, group_id: nil, variant_id: nil,
word: "ἱκετεύω", wo_stress: "ἱκετευω", plain: "ἱκετευω", raw_lsj:
"ἱκετεύω, fut. -σω E.IA462 (cj. Markl.), ...", raw_dvr: nil>]
>> Dict.find_all_by_wo_stress "ἱκετευω"
=> [#<Dict id: 81723, parent_id: nil, group_id: nil, variant_id: nil,
word: "ἱκετεύω", wo_stress: "ἱκετευω", plain: "ἱκετευω", raw_lsj:
"ἱκετεύω, fut. -σω E.IA462 (cj. Markl.), ...", raw_dvr: nil>]
Случайно обнаружил, никакие другие символы в подобном поведении не
замечены, всё уже долгое время работает корректно!
Куда рыть?
libMySQL-devel-5.0.67-alt1
MySQL-server-5.0.67-alt1
MySQL-client-5.0.67-alt1
libMySQL-5.0.67-alt1
mysql> show variables;
+---------------------------------+-----------------------------------------------------------+
| Variable_name | Value
|
+---------------------------------+-----------------------------------------------------------+
| auto_increment_increment | 1
|
| auto_increment_offset | 1
|
| automatic_sp_privileges | ON
|
| back_log | 50
|
| basedir | /usr/
|
| bdb_cache_size | 8384512
|
| bdb_home | /db/
|
| bdb_log_buffer_size | 262144
|
| bdb_logdir | /log
|
| bdb_max_lock | 10000
|
| bdb_shared_data | OFF
|
| bdb_tmpdir | /tmp/
|
| binlog_cache_size | 32768
|
| bulk_insert_buffer_size | 8388608
|
| character_set_client | latin1
|
| character_set_connection | latin1
|
| character_set_database | utf8
|
| character_set_filesystem | binary
|
| character_set_results | latin1
|
| character_set_server | utf8
|
| character_set_system | utf8
|
| character_sets_dir | /usr/share/mysql/charsets/
|
| collation_connection | latin1_swedish_ci
|
| collation_database | utf8_general_ci
|
| collation_server | utf8_general_ci
|
| completion_type | 0
|
| concurrent_insert | 1
|
| connect_timeout | 10
|
| datadir | /db/
|
| date_format | %Y-%m-%d
|
| datetime_format | %Y-%m-%d %H:%i:%s
|
| default_week_format | 0
|
| delay_key_write | ON
|
| delayed_insert_limit | 100
|
| delayed_insert_timeout | 300
|
| delayed_queue_size | 1000
|
| div_precision_increment | 4
|
| keep_files_on_create | OFF
|
| engine_condition_pushdown | OFF
|
| expire_logs_days | 0
|
| flush | OFF
|
| flush_time | 0
|
| ft_boolean_syntax | + -><()~*:""&|
|
| ft_max_word_len | 84
|
| ft_min_word_len | 4
|
| ft_query_expansion_limit | 20
|
| ft_stopword_file | (built-in)
|
| group_concat_max_len | 1024
|
| have_archive | YES
|
| have_bdb | YES
|
| have_blackhole_engine | YES
|
| have_compress | YES
|
| have_crypt | YES
|
| have_csv | NO
|
| have_dynamic_loading | YES
|
| have_example_engine | NO
|
| have_federated_engine | NO
|
| have_geometry | YES
|
| have_innodb | YES
|
| have_isam | NO
|
| have_merge_engine | YES
|
| have_ndbcluster | NO
|
| have_openssl | DISABLED
|
| have_ssl | DISABLED
|
| have_query_cache | YES
|
| have_raid | NO
|
| have_rtree_keys | YES
|
| have_symlink | YES
|
| hostname | mbnote.rinet.net
|
| init_connect |
|
| init_file |
|
| init_slave |
|
| innodb_additional_mem_pool_size | 1048576
|
| innodb_autoextend_increment | 8
|
| innodb_buffer_pool_awe_mem_mb | 0
|
| innodb_buffer_pool_size | 8388608
|
| innodb_checksums | ON
|
| innodb_commit_concurrency | 0
|
| innodb_concurrency_tickets | 500
|
| innodb_data_file_path | ibdata1:10M:autoextend
|
| innodb_data_home_dir |
|
| innodb_adaptive_hash_index | ON
|
| innodb_doublewrite | ON
|
| innodb_fast_shutdown | 1
|
| innodb_file_io_threads | 4
|
| innodb_file_per_table | OFF
|
| innodb_flush_log_at_trx_commit | 1
|
| innodb_flush_method |
|
| innodb_force_recovery | 0
|
| innodb_lock_wait_timeout | 50
|
| innodb_locks_unsafe_for_binlog | OFF
|
| innodb_log_arch_dir |
|
| innodb_log_archive | OFF
|
| innodb_log_buffer_size | 1048576
|
| innodb_log_file_size | 5242880
|
| innodb_log_files_in_group | 2
|
| innodb_log_group_home_dir | ./
|
| innodb_max_dirty_pages_pct | 90
|
| innodb_max_purge_lag | 0
|
| innodb_mirrored_log_groups | 1
|
| innodb_open_files | 300
|
| innodb_rollback_on_timeout | OFF
|
| innodb_support_xa | ON
|
| innodb_sync_spin_loops | 20
|
| innodb_table_locks | ON
|
| innodb_thread_concurrency | 8
|
| innodb_thread_sleep_delay | 10000
|
| interactive_timeout | 28800
|
| join_buffer_size | 131072
|
| key_buffer_size | 8384512
|
| key_cache_age_threshold | 300
|
| key_cache_block_size | 1024
|
| key_cache_division_limit | 100
|
| language | /usr/share/mysql/english/
|
| large_files_support | ON
|
| large_page_size | 0
|
| large_pages | OFF
|
| lc_time_names | en_US
|
| license | GPL
|
| local_infile | ON
|
| locked_in_memory | OFF
|
| log | OFF
|
| log_bin | OFF
|
| log_bin_trust_function_creators | OFF
|
| log_error |
|
| log_queries_not_using_indexes | OFF
|
| log_slave_updates | OFF
|
| log_slow_queries | OFF
|
| log_warnings | 1
|
| long_query_time | 10
|
| low_priority_updates | OFF
|
| lower_case_file_system | OFF
|
| lower_case_table_names | 0
|
| max_allowed_packet | 1048576
|
| max_binlog_cache_size | 4294963200
|
| max_binlog_size | 1073741824
|
| max_connect_errors | 10
|
| max_connections | 100
|
| max_delayed_threads | 20
|
| max_error_count | 64
|
| max_heap_table_size | 16777216
|
| max_insert_delayed_threads | 20
|
| max_join_size | 18446744073709551615
|
| max_length_for_sort_data | 1024
|
| max_prepared_stmt_count | 16382
|
| max_relay_log_size | 0
|
| max_seeks_for_key | 4294967295
|
| max_sort_length | 1024
|
| max_sp_recursion_depth | 0
|
| max_tmp_tables | 32
|
| max_user_connections | 0
|
| max_write_lock_count | 4294967295
|
| multi_range_count | 256
|
| myisam_data_pointer_size | 6
|
| myisam_max_sort_file_size | 2146435072
|
| myisam_recover_options | OFF
|
| myisam_repair_threads | 1
|
| myisam_sort_buffer_size | 8388608
|
| myisam_stats_method | nulls_unequal
|
| net_buffer_length | 16384
|
| net_read_timeout | 30
|
| net_retry_count | 10
|
| net_write_timeout | 60
|
| new | OFF
|
| old_passwords | ON
|
| open_files_limit | 1024
|
| optimizer_prune_level | 1
|
| optimizer_search_depth | 62
|
| pid_file | /mysqld.pid
|
| plugin_dir |
|
| port | 0
|
| preload_buffer_size | 32768
|
| profiling | OFF
|
| profiling_history_size | 15
|
| protocol_version | 10
|
| query_alloc_block_size | 8192
|
| query_cache_limit | 1048576
|
| query_cache_min_res_unit | 4096
|
| query_cache_size | 0
|
| query_cache_type | ON
|
| query_cache_wlock_invalidate | OFF
|
| query_prealloc_size | 8192
|
| range_alloc_block_size | 4096
|
| read_buffer_size | 131072
|
| read_only | OFF
|
| read_rnd_buffer_size | 262144
|
| relay_log |
|
| relay_log_index |
|
| relay_log_info_file | relay-log.info
|
| relay_log_purge | ON
|
| relay_log_space_limit | 0
|
| rpl_recovery_rank | 0
|
| secure_auth | OFF
|
| secure_file_priv |
|
| server_id | 0
|
| skip_external_locking | ON
|
| skip_networking | ON
|
| skip_show_database | OFF
|
| slave_compressed_protocol | OFF
|
| slave_load_tmpdir | /tmp/
|
| slave_net_timeout | 3600
|
| slave_skip_errors | OFF
|
| slave_transaction_retries | 10
|
| slow_launch_time | 2
|
| socket | /mysql.sock
|
| sort_buffer_size | 2097144
|
| sql_big_selects | ON
|
| sql_mode |
|
| sql_notes | ON
|
| sql_warnings | OFF
|
| ssl_ca |
|
| ssl_capath |
|
| ssl_cert |
|
| ssl_cipher |
|
| ssl_key |
|
| storage_engine | MyISAM
|
| sync_binlog | 0
|
| sync_frm | ON
|
| system_time_zone | MSD
|
| table_cache | 64
|
| table_lock_wait_timeout | 50
|
| table_type | MyISAM
|
| thread_cache_size | 0
|
| thread_stack | 196608
|
| time_format | %H:%i:%s
|
| time_zone | SYSTEM
|
| timed_mutexes | OFF
|
| tmp_table_size | 33554432
|
| tmpdir | /tmp
|
| transaction_alloc_block_size | 8192
|
| transaction_prealloc_size | 4096
|
| tx_isolation | REPEATABLE-READ
|
| updatable_views_with_limit | YES
|
| version | 5.0.67
|
| version_bdb | Sleepycat Software: Berkeley DB
4.1.24: (August 4, 2008) |
| version_comment | ALT Linux MySQL RPM
|
| version_compile_machine | i586
|
| version_compile_os | alt-linux-gnu
|
| wait_timeout | 28800
|
+---------------------------------+-----------------------------------------------------------+
239 rows in set (0.08 sec)
M.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [sisyphus] странное и некрасивое поведение utf8 в паре rails/mysql
2009-06-24 16:31 [sisyphus] странное и некрасивое поведение utf8 в паре rails/mysql Michael Bykov
@ 2009-06-25 6:57 ` Anton V. Boyarshinov
2009-06-26 10:30 ` Michael Bykov
0 siblings, 1 reply; 6+ messages in thread
From: Anton V. Boyarshinov @ 2009-06-25 6:57 UTC (permalink / raw)
To: sisyphus
On Wed, 24 Jun 2009 20:31:40 +0400 Michael Bykov wrote:
> странное и некрасивое поведение utf8 в паре rails/mysql
> Вторая строка - корректный результат, первая загадочна:
>
> первая буква слова в поле wo_stress, по которому я ищу, ἰ = 0xF130, а
> в значении, которое mysql нашёл, ἱ = 0x1F31. То есть это разные
> строки!
Конкретно про MySQL не скажу, но про unicode вообще.. Ситуация на
первый взгляд, конечно, странная, но по своему корректная.. Дело в том,
что unicode это не кодировка в обычном смысле, а довольно сложная штука
(даже без учёта конечного автомата utf8). Многие символы можно записать
в unicode разными способами, и в ряде случаев они при этом должны
трактоваться как одинаковые.
Так, например, русская буква 'й' может быть записана двумя
равнозначными способами: как один глиф 'й' и как (два глифа) 'и' с
надстрочным символом (MacOS X использует второй способ, что порождает
порядочную кашу при переносе по крайней мере файлов, содержащих 'й' в
имени). Аналогично ё. Насчёт вашего примера в корректности работы
поиска не уверен, но вероятность того что в данному случае правильное
unicode сравнение должно работать именно так, оцениваю как высокое. При
unicode сравнении сравниваются не байты.
Антон
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [sisyphus] странное и некрасивое поведение utf8 в паре rails/mysql
2009-06-25 6:57 ` Anton V. Boyarshinov
@ 2009-06-26 10:30 ` Michael Bykov
2009-06-28 6:16 ` Mikhail Yakshin
0 siblings, 1 reply; 6+ messages in thread
From: Michael Bykov @ 2009-06-26 10:30 UTC (permalink / raw)
To: ALT Linux Sisyphus discussions
25 июня 2009 г. 10:57 пользователь Anton V. Boyarshinov
(boyarsh@altlinux.org) написал:
> On Wed, 24 Jun 2009 20:31:40 +0400 Michael Bykov wrote:
>
>> странное и некрасивое поведение utf8 в паре rails/mysql
>> Вторая строка - корректный результат, первая загадочна:
>>
>> первая буква слова в поле wo_stress, по которому я ищу, ἰ = 0xF130, а
>> в значении, которое mysql нашёл, ἱ = 0x1F31. То есть это разные
>> строки!
>
> Конкретно про MySQL не скажу, но про unicode вообще.. Ситуация на
> первый взгляд, конечно, странная, но по своему корректная.. Дело в том,
> что unicode это не кодировка в обычном смысле, а довольно сложная штука
> (даже без учёта конечного автомата utf8). Многие символы можно записать
> в unicode разными способами, и в ряде случаев они при этом должны
> трактоваться как одинаковые.
>
> Так, например, русская буква 'й' может быть записана двумя
> равнозначными способами: как один глиф 'й' и как (два глифа) 'и' с
> надстрочным символом (MacOS X использует второй способ, что порождает
> порядочную кашу при переносе по крайней мере файлов, содержащих 'й' в
> имени). Аналогично ё. Насчёт вашего примера в корректности работы
> поиска не уверен, но вероятность того что в данному случае правильное
> unicode сравнение должно работать именно так, оцениваю как высокое. При
> unicode сравнении сравниваются не байты.
>
> Антон
> _______________________________________________
> Sisyphus mailing list
> Sisyphus@lists.altlinux.org
> https://lists.altlinux.org/mailman/listinfo/sisyphus
MySQL продолжает упорствовать в своих заблуждениях.
show variables like '%character_set\_%';
+--------------------------+--------+
| Variable_name | Value |
+--------------------------+--------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
+--------------------------+--------+
7 rows in set (0.00 sec)
show variables like '%collation\_%';
+----------------------+-----------------+
| Variable_name | Value |
+----------------------+-----------------+
| collation_connection | utf8_unicode_ci |
| collation_database | utf8_general_ci |
| collation_server | utf8_unicode_ci |
+----------------------+-----------------+
3 rows in set (0.00 sec)
Dict.find_by_word "ᾆδω"
=> #<Dict id: 2622, parent_id: nil, group_id: nil, variant_id: nil, word: "ἄδω"
но "ᾆδω" это не "ἄδω" совсем.
Интересно, может быть постгрес будет проще настроить?
М.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [sisyphus] странное и некрасивое поведение utf8 в паре rails/mysql
2009-06-26 10:30 ` Michael Bykov
@ 2009-06-28 6:16 ` Mikhail Yakshin
2009-06-28 6:55 ` Michael Bykov
2009-06-28 8:41 ` Afanasov Dmitry
0 siblings, 2 replies; 6+ messages in thread
From: Mikhail Yakshin @ 2009-06-28 6:16 UTC (permalink / raw)
To: ALT Linux Sisyphus discussions
> MySQL продолжает упорствовать в своих заблуждениях.
>
[...]
> Dict.find_by_word "ᾆδω"
> => #<Dict id: 2622, parent_id: nil, group_id: nil, variant_id: nil, word: "ἄδω"
>
> но "ᾆδω" это не "ἄδω" совсем.
>
> Интересно, может быть постгрес будет проще настроить?
Это unicode case-insensitive (ci) collation, который вполне себе
корректно отрабатывает. С точки зрения unicode - это два символа,
которые равны по sort values - т.к. и "ᾆ", и "ἄ" равны просто "α":
mysql> select 'ᾆ'='α';
+------------+
| 'ᾆ'='α' |
+------------+
| 1 |
+------------+
Это в целом полезный механизм - например, пользователь может написать
"елка", и оно из-за этого case insensitivity смэтчится со словами
"ёлка", "Елка" или "Ёлка", которые найдутся в базе.
Более подробно об этом можно почитать в руководстве MySQL:
http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
Quick solution, если надо просто отключить любые case- и sort-
sensitivity - использовать тип BINARY (или collation utf8_bin). Их
можно поставить на БД целиком, на таблицы/поля/переменные или даже
индивидуальные сравнения:
mysql> select 'ᾆ' COLLATE utf8_bin='α';
+-----------------------------+
| 'ᾆ' COLLATE utf8_bin='α' |
+-----------------------------+
| 0 |
+-----------------------------+
Postgresql в данном случае будет вести себя точно так же - эти вещи
(классы эквивалентности по sort value для различных characters)
прописаны в стандарте unicode.
P.S. Вопрос, видимо, всё-таки не имеет отношения к sisyphus@ -
предлагаю переместиться в личную почту для дальнейших обсуждений, если
таковые будут иметь место.
--
WBR, Mikhail Yakshin
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [sisyphus] странное и некрасивое поведение utf8 в паре rails/mysql
2009-06-28 6:16 ` Mikhail Yakshin
@ 2009-06-28 6:55 ` Michael Bykov
2009-06-28 8:41 ` Afanasov Dmitry
1 sibling, 0 replies; 6+ messages in thread
From: Michael Bykov @ 2009-06-28 6:55 UTC (permalink / raw)
To: ALT Linux Sisyphus discussions
28 июня 2009 г. 10:16 пользователь Mikhail Yakshin
(greycat@altlinux.org) написал:
>> MySQL продолжает упорствовать в своих заблуждениях.
>>
> [...]
>
>> Dict.find_by_word "ᾆδω"
>> => #<Dict id: 2622, parent_id: nil, group_id: nil, variant_id: nil, word: "ἄδω"
>>
>> но "ᾆδω" это не "ἄδω" совсем.
>>
>> Интересно, может быть постгрес будет проще настроить?
>
> Это unicode case-insensitive (ci) collation, который вполне себе
> корректно отрабатывает. С точки зрения unicode - это два символа,
> которые равны по sort values - т.к. и "ᾆ", и "ἄ" равны просто "α":
>
> mysql> select 'ᾆ'='α';
> +------------+
> | 'ᾆ'='α' |
> +------------+
> | 1 |
> +------------+
>
> Это в целом полезный механизм - например, пользователь может написать
> "елка", и оно из-за этого case insensitivity смэтчится со словами
> "ёлка", "Елка" или "Ёлка", которые найдутся в базе.
>
> Более подробно об этом можно почитать в руководстве MySQL:
> http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
>
> Quick solution, если надо просто отключить любые case- и sort-
> sensitivity - использовать тип BINARY (или collation utf8_bin). Их
> можно поставить на БД целиком, на таблицы/поля/переменные или даже
> индивидуальные сравнения:
>
> mysql> select 'ᾆ' COLLATE utf8_bin='α';
> +-----------------------------+
> | 'ᾆ' COLLATE utf8_bin='α' |
> +-----------------------------+
> | 0 |
> +-----------------------------+
>
> Postgresql в данном случае будет вести себя точно так же - эти вещи
> (классы эквивалентности по sort value для различных characters)
> прописаны в стандарте unicode.
>
> P.S. Вопрос, видимо, всё-таки не имеет отношения к sisyphus@ -
> предлагаю переместиться в личную почту для дальнейших обсуждений, если
> таковые будут иметь место.
>
Да, спасибо, Михаил, я уже разобрался, всё перевел в utf8 и прописал
collation. Теперь у меня настройки такие:
mysql> show variables like '%collation\_%'
+----------------------+----------+
| Variable_name | Value |
+----------------------+----------+
| collation_connection | utf8_bin |
| collation_database | utf8_bin |
| collation_server | utf8_bin |
+----------------------+----------+
3 rows in set (0.00 sec)
mysql> show variables like '%character_set\_%';
+--------------------------+--------+
| Variable_name | Value |
+--------------------------+--------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
+--------------------------+--------+
7 rows in set (0.00 sec)
и выполнил после создания базы:
ALTER TABLE dicts MODIFY wo_stress varchar(255) CHARACTER SET utf8
COLLATE utf8_bin;
Всё работает корректно. Вопрос остался скорее теоретический - почему
character_set utf8 мы не используем по-умолчанию, сильно ли это снизит
эффективность? Тут с полгода назад это уже обсуждалось. На глаз
скорость работы не меняется, всё летает.
М.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [sisyphus] странное и некрасивое поведение utf8 в паре rails/mysql
2009-06-28 6:16 ` Mikhail Yakshin
2009-06-28 6:55 ` Michael Bykov
@ 2009-06-28 8:41 ` Afanasov Dmitry
1 sibling, 0 replies; 6+ messages in thread
From: Afanasov Dmitry @ 2009-06-28 8:41 UTC (permalink / raw)
To: sisyphus
[-- Attachment #1: Type: text/plain, Size: 582 bytes --]
On Sun, Jun 28, 2009 at 10:16:19AM +0400, Mikhail Yakshin wrote:
> > MySQL продолжает упорствовать в своих заблуждениях.
> >
> Это unicode case-insensitive (ci) collation, который вполне себе
> корректно отрабатывает. С точки зрения unicode - это два символа,
> которые равны по sort values - т.к. и "???", и "???" равны просто "??":
...
> P.S. Вопрос, видимо, всё-таки не имеет отношения к sisyphus@ -
> предлагаю переместиться в личную почту для дальнейших обсуждений, если
> таковые будут иметь место.
не надо, это же интересно.
--
С уважением
Афанасов Дмитрий
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2009-06-28 8:41 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-24 16:31 [sisyphus] странное и некрасивое поведение utf8 в паре rails/mysql Michael Bykov
2009-06-25 6:57 ` Anton V. Boyarshinov
2009-06-26 10:30 ` Michael Bykov
2009-06-28 6:16 ` Mikhail Yakshin
2009-06-28 6:55 ` Michael Bykov
2009-06-28 8:41 ` Afanasov Dmitry
ALT Linux Sisyphus discussions
This inbox may be cloned and mirrored by anyone:
git clone --mirror http://lore.altlinux.org/sisyphus/0 sisyphus/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 sisyphus sisyphus/ http://lore.altlinux.org/sisyphus \
sisyphus@altlinux.ru sisyphus@altlinux.org sisyphus@lists.altlinux.org sisyphus@lists.altlinux.ru sisyphus@lists.altlinux.com sisyphus@linuxteam.iplabs.ru sisyphus@list.linux-os.ru
public-inbox-index sisyphus
Example config snippet for mirrors.
Newsgroup available over NNTP:
nntp://lore.altlinux.org/org.altlinux.lists.sisyphus
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git