开源新闻组软件 INN在Ubuntu上的安装配置指南
INN的安装,真的是太有趣了!还是挺怀念当前的新帆新闻组啊!INN新闻组,在AI爆发的2026年,估计会迎来新的应用机会!
INN(InterNetNews)是历史悠久的开源 Usenet/NNTP 服务器软件,用于接收、存储和分发新闻组文章。它适合从小型私有新闻组到大型公共 Usenet 节点的多种场景,稳定、伸缩性好、可高度定制,至今仍由社区持续维护。
本次实践在一台192.168.1.12地址的Ubuntu22.04 服务器(FreeBSD下开的linux jail虚拟容器)
安装软件
INN(InterNetNews)在Ubuntu有软件包,直接apt 安装即可。这次选了inn2版本的进行安装。
安装INN
#!/bin/bash
# 更新系统包列表
sudo apt update
# 安装INN服务器
sudo apt install -y inn2
# 启动INN服务
sudo systemctl start inn2
# 设置开机自启
sudo systemctl enable inn2
echo "INN安装完成!"
用service启动服务
sudo service inn2 start
启动服务成功
sudo service inn2 start
* Starting news server innd
用sudo service --status-all可以看到inn2服务已经启动
sudo service --status-all
[ - ] apache-htcacheclean
[ - ] apache2
[ - ] atd
[ ? ] binfmt-support
[ - ] console-setup.sh
[ - ] cron
[ - ] dbus
[ - ] gdomap
[ ? ] hwclock.sh
[ + ] inn2
sudo innstat看看具体情况
sudo innstat
Server status:
Server running
Allowing remote connections
Parameters c 10 i 50 (0) l 1000000 o 1010 t 300 H 2 T 60 X 0 normal specified
Not reserved
Readers follow enabled
Perl filtering enabled
Python filtering disabled
Disk usage:
/etc/news 152224284 Kbytes available (95.0%)
/var/lib/news 152224284 Kbytes available (95.0%)
/var/log/news 152224284 Kbytes available (95.0%)
/var/spool/news/archive 152224284 Kbytes available (95.0%)
/var/spool/news/articles 152224284 Kbytes available (95.0%)
/var/spool/news/incoming 152224284 Kbytes available (95.0%)
/var/spool/news/incoming/tmp 152224284 Kbytes available (95.0%)
/var/spool/news/outgoing 152224284 Kbytes available (95.0%)
/var/spool/news/overview 152224284 Kbytes available (95.0%)
Batch file sizes (in Kbytes):
Log file sizes (in Kbytes):
ls: cannot access '*.log': No such file or directory
5 errlog 1 news 1 news.crit 1 news.err 1 news.notice
Lock files:
LOCK.innwatch
Server connections:
TOTAL: 0 0
netstat可以看到端口在侦听
netstat -an |grep 119
tcp4 0 0 192.168.1.12.119 *.* LISTEN
配置INN
修改/etc/readers.conf文件
auth "local" {
hosts: "192.168.0.0/16, 127.0.0.1, ::1"
default: "anonymous"
}
access "local" {
users: "anonymous"
newsgroups: "*"
posting: true
}
这个配置允许来自 192.168.0.0/16 网段、本地回环地址的匿名用户访问所有新闻组并允许发布文章。这个配置是ai提供的。
服务器的实际配置是这个:
auth "localhost" {
hosts: "192.168.0.0/16, localhost, 127.0.0.1, ::1, stdin"
default: "<localhost>"
}
# Grant that specific identity access to read and post to any newsgroup
# and allow it to post articles with Approved: headers to moderated
# groups.
access "localhost" {
users: "<localhost>"
newsgroups: "*"
access: RPA
}
这个配置是软件安装后自动的配置,我只是在hosts里面加了本地网段:192.168.0.0/16,以便本地网段都可以访问inn服务器。
这个配置为本地主机提供了更详细的访问控制,其中 access: RPA 表示读取(Read)、发布(Post)和批准(Approve)权限。
修改/etc/inn.conf文件
domain: local.lan
pathhost: news.local.lan
server: 192.168.1.10 # 本机 LAN 地址
domain和pathhost只是标识,不要求 DNS 能解析。server填你这台机器的局域网 IP,这样 INN 只在该地址监听 119/563 端口,避免暴露在公网。
我这台服务器,只保证了server是填了本机ip地址,其它domain 和 pathhost都是乱填的(即没有公网域名解析,也没有内网域名解析)
真正的/etc/inn.conf文件是这样的:
server: 192.168.1.12
放开2个端口119和563
sudo ufw allow from 192.168.0.0/16 to any port 119
sudo ufw allow from 192.168.0.0/16 to any port 563
实际这台服务器我好像没有配置防火墙....
重启服务
sudo service inn2 restart
连通测试
使用telnet进行连通性测试
telnet 192.168.1.12 119
能看到一些信息
telnet 192.168.1.12 119
Trying 192.168.1.12...
Connected to 192.168.1.12.
Escape character is '^]'.
200 ubjail1.airoot.org InterNetNews NNRP server INN 2.6.4 ready (posting ok)
Connection closed by foreign host.
出现这句话:200 ubjail1.airoot.org InterNetNews NNRP server INN 2.6.4 ready (posting ok) ,就证明119端口连通正常了。
看一看到这里的域名,就是在inn.conf文件中配置的域名,它只起到展示的作用。
python脚本测试
这个不行:
from nntplib import NNTP
s = NNTP('192.168.1.12', 119, user='anonymous', password='')
resp, ct, fst, lst, name = s.group('lan.test')
print('组里共有', ct, '篇文章')
s.quit()
没成功,错误提示:nntplib.NNTPTemporaryError: 483 Encryption required
来个完成的测试:
import nntplib
import time
import uuid
from io import BytesIO
SERVER = "192.168.1.12"
PORT = 119
# 注意:你的服务器上似乎没有'test'组,但有'local.test'。我们用这个。
TEST_NEWSGROUP = "local.test"
POSTER_EMAIL = "tester@example.com"
def run_test():
server = None
print(f"--- 开始测试 INN 服务器 ({SERVER}:{PORT}) ---")
try:
print(f"\n[步骤 1/6] 正在连接到 {SERVER}:{PORT}...")
server = nntplib.NNTP(SERVER, PORT, timeout=10)
print("✅ 连接成功!服务器响应:")
print(f" {server.getwelcome().strip()}")
print(f"\n[步骤 2/6] 正在获取新闻组列表...")
resp, groups = server.list()
print(f"✅ 成功获取 {len(groups)} 个新闻组。")
print(f"\n[步骤 3/6] 正在选择新闻组 '{TEST_NEWSGROUP}'...")
try:
resp, count, first, last, name = server.group(TEST_NEWSGROUP)
print(f"✅ 成功选择新闻组 '{name}'. 文章数量: {count}")
except nntplib.NNTPTemporaryError as e:
print(f"❌ 错误: 新闻组 '{TEST_NEWSGROUP}' 不存在或无法访问。")
return
print(f"\n[步骤 4/6] 正在读取新闻组中的文章头...")
if int(count) > 0:
start_article = max(int(first), int(last) - 4)
resp, overviews = server.xover(str(start_article), last)
print(f"✅ 成功读取 {len(overviews)} 篇文章头。最新一篇示例:")
if overviews:
print(f" 服务器返回的原始概览数据: {overviews[-1]}")
article_info = overviews[-1]
# 更健壮地处理,无论返回多少字段都只打印前两个
print(f" - #{article_info[0]} - {article_info[1]}")
else:
print("ℹ️ 新闻组为空,跳过读取。")
print(f"\n[步骤 5/6] 正在尝试发布一篇新文章到 '{TEST_NEWSGROUP}'...")
unique_id = uuid.uuid4()
subject = f"Python Test Post - {unique_id}"
article_body = f"From: {POSTER_EMAIL}\nNewsgroups: {TEST_NEWSGROUP}\nSubject: {subject}\n\nTest post."
article_bytes = article_body.encode('utf-8')
article_file = BytesIO(article_bytes)
try:
resp = server.post(article_file)
print(f"✅ 文章发布请求已发送。服务器响应: {resp.strip()}")
except Exception as e:
print(f"❌ 发布失败! {e}")
return
print(f"\n[步骤 6/6] 正在验证文章是否已出现在服务器上...")
time.sleep(2)
resp, count, first, last, name = server.group(TEST_NEWSGROUP)
resp, overviews = server.xover(last, last)
if overviews:
last_article_info = overviews[-1]
last_subject = last_article_info[1]
# print(f"==== last_subject={last_subject} subject={subject}")
last_subject = last_subject.get('subject')
if subject == last_subject:
print(f"✅ 验证成功!在文章 #{last_article_info[0]} 中找到了我们发布的帖子。")
else:
print(f"⚠️ 验证失败!最新文章的主题与我们发布的不匹配。")
else:
print("❌ 验证失败!无法获取最新文章。")
except Exception as e:
print(f"\n❌ 发生错误: {e}")
import traceback
traceback.print_exc()
finally:
if server:
print("\n--- 测试结束,正在断开连接 ---")
server.quit()
if __name__ == "__main__":
run_test()
测试输出:
--- 开始测试 INN 服务器 (192.168.1.12:119) ---
[步骤 1/6] 正在连接到 192.168.1.12:119...
✅ 连接成功!服务器响应:
200 ubjail1.airoot.org InterNetNews NNRP server INN 2.6.4 ready (posting ok)
[步骤 2/6] 正在获取新闻组列表...
✅ 成功获取 9 个新闻组。
[步骤 3/6] 正在选择新闻组 'local.test'...
✅ 成功选择新闻组 'local.test'. 文章数量: 8
[步骤 4/6] 正在读取新闻组中的文章头...
✅ 成功读取 5 篇文章头。最新一篇示例:
服务器返回的原始概览数据: (8, {'subject': 'Python Test Post - c492dd58-21f6-4f44-8be5-ac9678d74415', 'from': 'tester@example.com', 'date': 'Mon, 9 Feb 2026 03:09:47 -0000 (UTC)', 'message-id': '<10mbj5r$166v$1@ubjail1.ubjail1.airoot.org>', 'references': '', ':bytes': '589', ':lines': '1', 'xref': 'ubjail1.airoot.org local.test:8'})
- #8 - {'subject': 'Python Test Post - c492dd58-21f6-4f44-8be5-ac9678d74415', 'from': 'tester@example.com', 'date': 'Mon, 9 Feb 2026 03:09:47 -0000 (UTC)', 'message-id': '<10mbj5r$166v$1@ubjail1.ubjail1.airoot.org>', 'references': '', ':bytes': '589', ':lines': '1', 'xref': 'ubjail1.airoot.org local.test:8'}
[步骤 5/6] 正在尝试发布一篇新文章到 'local.test'...
✅ 文章发布请求已发送。服务器响应: 240 Article received <10mbja0$18ll$1@ubjail1.ubjail1.airoot.org>
[步骤 6/6] 正在验证文章是否已出现在服务器上...
✅ 验证成功!在文章 #9 中找到了我们发布的帖子。
--- 测试结束,正在断开连接 ---
ok,测试已通过!
用Mozilla thunderbird软件测试
Thunderbird is a free and open source email, newsfeed, chat, and calendaring client, that’s easy to set up and customize. One of the core principles of Thunderbird is the use and promotion of open standards - this focus is a rejection of our world of closed platforms and services that can’t communicate with each other. We want our users to have freedom and choice in how they communicate.
- 打开 Thunderbird → 账户设置 → 新闻组账户。
- 输入:
- 服务器:
192.168.x.x(服务器局域网 IP) - 端口:
119
- 服务器:
- 订阅新闻组(如
local.test)。
配置需要邮箱,给自己开个邮箱吧。咱们一步步来进行测试。
配置INN客户端Mozilla thunderbird进行连通测试
准备一个邮箱
给自己开了一个私域邮箱 skywalk@example.local ,具体参见:https://skywalk.blog.csdn.net/article/details/157730768
如果自己有公域的邮箱,也可以用,但是inn是配置了私有域名,估计公域邮箱无法向私域inn服务器发邮件。所以建议公网inn配公域邮箱,私域INN配私域邮箱。
thunderbird配置账户
启动thunderbird邮件软件,配置新账户:

配置完成,进入新闻组页面如下:

查看新闻组,并勾选订阅:

发帖测试
在新闻组里发第一篇帖子:

第一个帖子刷出来了:

哇,这就是新闻组啊,怀念当年的新帆新闻组啊!
往junk(垃圾)组发邮件,报错:

Sending of the message failed.
The message could not be posted because connecting to the news server failed. The server may be unavailable or is refusing connections. Please verify that your news server settings are correct and try again.
后来得知说那个组就是不允许发帖。
在INN配置、添加更多组
向 INN (InterNetNews) 服务器添加新的新闻组有两种主要方法,推荐使用 ctlinnd 命令(最安全),也可以手动编辑配置文件(需要谨慎操作)。以下是详细步骤:
方法一:使用 ctlinnd 命令(推荐)
这是官方推荐的安全方式,不需要重启服务。
-
连接到服务器执行命令
# 创建新的可发帖新闻组 ctlinnd newgroup <组名> # 示例:创建名为 comp.test 的组 ctlinnd newgroup comp.test # 创建只读新闻组(不可发帖) ctlinnd newgroup <组名> -m n # 示例:创建只读的 announce.important 组 ctlinnd newgroup announce.important -m n -
验证是否成功
grep '<组名>' /var/lib/news/active # 成功时会显示类似:comp.test 0000000000 0000000001 y # 末尾 "y" 表示可发帖,"n" 表示只读
方法二:手动编辑配置文件(备用)
适用于无法使用 ctlinnd 的情况,需谨慎操作。
-
编辑 active 文件
sudo nano /var/lib/news/active
在文件末尾添加新行:
<组名> 0000000000 0000000001 <权限标志>
- 权限标志:
y:允许发帖(默认)n:只读组m:需审核的组x:禁用组
- 示例:
linux.general 0000000000 0000000001 y
- 权限标志:
-
通知 INN 重新加载配置
ctlinnd reload active "Added new group"
后续必要步骤
无论使用哪种方法,都需要:
-
添加组描述(可选但推荐)
sudo nano /var/lib/news/newsgroups
添加格式:
<组名> <描述文本>
示例:
comp.test 测试技术讨论组
-
刷新客户端
- 在 Thunderbird 中:右键点击新闻组账户 → 刷新新闻组
- 或重启客户端
-
验证新组可用性
telnet localhost 119 LIST
应在返回列表中看到新组名
常见问题解决
-
组不显示:
- 检查
/var/lib/news/active文件权限:chown news:news /var/lib/news/active
- 重启 INN 服务:
sudo systemctl restart inn2
- 检查
-
无法发帖到新组:
- 确认
readers.conf包含新组权限:access "all-groups" { users: "*" newsgroups: "*" access: RP # R=读取, P=发帖 } - 重载配置:
ctlinnd reload readers.conf
- 确认
-
组层级限制: 若需创建新顶层组(如
company.*),在inn.conf添加:hierarchies: company,comp,news
关键文件说明
| 文件路径 | 作用 |
|---|---|
/var/lib/news/active |
所有新闻组列表及权限 |
/var/lib/news/newsgroups |
组描述信息(客户端可见) |
/etc/news/readers.conf |
客户端访问控制规则 |
/etc/news/inn.conf |
主配置文件(层级设置等) |
建议优先使用 ctlinnd newgroup 命令,这是最安全且实时生效的方式。手动编辑仅作为备用方案。
实践(见文档)
见文档:https://skywalk.blog.csdn.net/article/details/157870015
总结
INN的安装,真的是太有趣了!还是挺怀念当前的新帆新闻组啊!
INN新闻组,在AI爆发的2026年,估计会迎来新的应用机会!
调试
安装inn2报错
sudo apt install -y inn2
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
inn2 is already the newest version (2.6.4-2build4).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
1 not fully installed or removed.
After this operation, 0 B of additional disk space will be used.
Setting up inn2 (2.6.4-2build4) ...
innconfval: hostname does not resolve or domain not set in inn.conf
dpkg: error processing package inn2 (--configure):
installed inn2 package post-installation script subprocess returned error exit status 1
Errors were encountered while processing:
inn2
E: Sub-process /usr/bin/dpkg returned an error code (1)
修改/etc/hosts文件,加入域名
修改/etc/news/inn.conf文件,加入domain等配置,
domain: ubjail1.airoot.org
#innflags:
mailcmd: /usr/lib/news/bin/innmail
server: ubjail1.airoot.org
就ok了
Installing initial content for /var/lib/news/active
Installing initial content for /var/lib/news/newsgroups
Building history database in /var/lib/news... makehistory: tradspool: mapping file /var/spool/news/tradspool.map not found
done.
Adding alias for pseudo-user usenet to /etc/aliases.
invoke-rc.d: could not determine current runlevel
Created symlink /etc/systemd/system/multi-user.target.wants/inn2.service → /lib/systemd/system/inn2.service.
python登录报错nntplib.NNTPTemporaryError: 483 Encryption required
>>> s = NNTP('192.168.1.12', 119, user='anonymous', password='')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.11/nntplib.py", line 343, in __init__
self.login(user, password, usenetrc)
File "/usr/local/lib/python3.11/nntplib.py", line 960, in login
resp = self._shortcmd('authinfo user ' + user)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/nntplib.py", line 543, in _shortcmd
return self._getresp()
^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/nntplib.py", line 486, in _getresp
raise NNTPTemporaryError(resp)
nntplib.NNTPTemporaryError: 483 Encryption required
尝试一下用ssl
s = nntplib.NNTP_SSL('192.168.1.12', 119, user='anonymous', password='')
用ssl报错
s = nntplib.NNTP_SSL('192.168.1.12', 119, user='anonymous', password='')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.11/nntplib.py", line 1028, in __init__
super().__init__(host, port, user, password, readermode,
File "/usr/local/lib/python3.11/nntplib.py", line 337, in __init__
self.sock = self._create_socket(timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/nntplib.py", line 1034, in _create_socket
sock = _encrypt_on(sock, self.ssl_context, self.host)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/nntplib.py", line 295, in _encrypt_on
return context.wrap_socket(sock, server_hostname=hostname)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/ssl.py", line 517, in wrap_socket
return self.sslsocket_class._create(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/ssl.py", line 1104, in _create
self.do_handshake()
File "/usr/local/lib/python3.11/ssl.py", line 1382, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1016)
尝试用563端口
s = nntplib.NNTP_SSL('192.168.1.12', 563, user='anonymous', password='')
直接报错:
s = nntplib.NNTP_SSL('192.168.1.12', 563, user='anonymous', password='')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.11/nntplib.py", line 1028, in __init__
super().__init__(host, port, user, password, readermode,
File "/usr/local/lib/python3.11/nntplib.py", line 337, in __init__
self.sock = self._create_socket(timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/nntplib.py", line 1032, in _create_socket
sock = super()._create_socket(timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/nntplib.py", line 402, in _create_socket
return socket.create_connection((self.host, self.port), timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/socket.py", line 863, in create_connection
raise exceptions[0]
File "/usr/local/lib/python3.11/socket.py", line 848, in create_connection
sock.connect(sa)
ConnectionRefusedError: [Errno 61] Connection refused
看了一下,563端口没起来
不用python了,用thunderbird试试。后来thunderbird测试通过。
(后来是让AI给重新写了测试语句)
thunderbird无法向junk组发邮件信息
已经用INN部署了本地内部的新闻组服务器,使用thunderbird登录,可以浏览新闻组列表,可以向local.test组发邮件,但是无法向junk组发邮件,发邮件显示:news account 192.168.1.12: Postings to "junk" are not allowed here
还有提示:Sending of the message failed.
The message could not be posted because connecting to the news server failed. The server may be unavailable or is refusing connections. Please verify that your news server settings are correct and try again.
AI回答:
结论先说:在 INN 里“junk”是保留用的特殊组,不是给用户发帖的正常分组。Thunderbird 的提示“Postings to 'junk' are not allowed here”正是服务器按规则拒绝了向该组发帖;这不是网络连接问题。建议不要向“junk”发帖,改用你自己的测试或讨论组(例如 local.test、local.junk)。如果希望用户端不再看到“junk”,可以在 readers.conf 里把它从可读列表里排除。
为什么会这样
- INN 的 active 文件每个分组有一个标志位:y(可本地发帖)、m(经版主审稿)、n(不允许本地发帖)、j(已废弃/不应使用,收到的文章会被丢到 junk)。
- “junk”是 INN 内部丢弃/归类无效文章的特殊组,通常被标记为 j 或 n。客户端能看到它,但服务器会拒绝向它发帖,所以出现该错误。
- Thunderbird 后面那条“connecting to the news server failed”多半是通用失败提示(服务器在拒绝发帖后主动断开了连接),不是你的 NNTP 基础连接真的坏了——你能发到 local.test 就说明连接本身是好的。
你可以怎么做
- 最推荐:不要向 junk 发帖。改用已有的 local.test,或新建你自己的“垃圾/测试”分组,例如 local.junk。
- 以 news 用户执行:ctlinnd newgroup local.junk y
- 客户端订阅 local.junk 后即可发帖。
- 隐藏 junk 避免误用:在 readers.conf 中限制可读/可发分组,把 junk 和 control* 排除。
- 示例(按你的网段改写 hosts/users;语法基于 INN 2.x):
- auth "lan" { hosts: "192.168.1.*"; default: "" }
- access "lan" { users: ""; read: ",!junk,!control,!control"; post: "local.,.test,!control*,!junk"; }
- 改完后重载 nnrpd/INN(通常是 rc.news stop/start 或系统服务)。
- 示例(按你的网段改写 hosts/users;语法基于 INN 2.x):
- 若你强烈需要一个名为 junk 的“正常可发”组(不推荐):
- 把 active 中 junk 的标志改为 y:ctlinnd changegroup junk y
- 同时检查 storage.conf 的匹配规则,确保 junk 没被映射到“丢弃/垃圾”类(有些示例里会用 !junk 来避免存储到默认类)。必要时为 junk 单独指定存储类。
- 警告:把 junk 当普通组使用可能与 INN 的“丢弃”语义冲突,混杂无效文章与用户文章,不利于维护。
如何确认当前状态/排错
- 查看 active 中的 junk 标志(路径因发行版不同,常见为 /var/lib/news/active 或 /usr/local/news/db/active):
- grep '^junk ' /var/lib/news/active
- 末尾若是 j 或 n,客户端本地发帖会被拒绝,这是预期行为。
- 看 nnrpd 日志(news.notice/news.err)验证拒绝原因:
- 典型记录会写明“post to junk not allowed”或权限匹配结果。
- 用命令行重现(便于看到 NNTP 返回码):
- telnet 你的服务器 119,输入 MODE READER;POST;构造一篇 Newsgroups: junk 的文章;
- 你可能会收到 441 或 440/480 类拒绝码,印证问题与权限/组标志有关,而非连接故障。
小结
- 你的部署是正常的,INN 默认就不允许向“junk”发帖。
- 采用 local.* 或 .test 作为用户可发的分组;在 readers.conf 隐藏 junk、control 等内部组。
- 若仍需定制具体策略或给出 readers.conf/storage.conf 片段,我可以基于你当前配置文件提供精确修改示例。
更多推荐



所有评论(0)