bitbot-irc / bitbot Goto Github PK
View Code? Open in Web Editor NEWhttps://bitbot.dev | Python3 event-driven modular IRCv3 bot 🤖
License: GNU General Public License v2.0
https://bitbot.dev | Python3 event-driven modular IRCv3 bot 🤖
License: GNU General Public License v2.0
Greetings,
Whats main purpose of this bot. Usage examples?
More than just auto op/voice, there should be a way to give users permissions within a channel (!kick
, !ban
, !channelset
etc) that don't require them to actively have +o
I'd like to have a command that collects the nicknames of all the people in the current channel that have +o or above and says them in-channel to ping admins (for use in e.g. spam floods)
this should be an opt-in feature using a BoolSetting, an example of which can be seen here:
https://github.com/jesopo/bitbot/blob/51bed87b6019911b9471a2273c81dade70570945/modules/sed.py#L10-L11
you need to get a list of all users in a channel:
https://github.com/jesopo/bitbot/blob/51bed87b6019911b9471a2273c81dade70570945/src/IRCChannel.py#L20
and you need to check they have +o-or-above:
https://github.com/jesopo/bitbot/blob/51bed87b6019911b9471a2273c81dade70570945/src/IRCChannel.py#L198
This causes a lot of issues, especially for relay.py (causes relaying of relayed message which would cause a loop if both sides of the relay had echo-message
without labeled-response
)
This will be caused by a bug in the CAP dependency algo, located here: https://github.com/jesopo/bitbot/blob/fa1e9cbb5812db9e09a48fdb8b13bf68d5b4380c/modules/line_handler/ircv3.py#L19
echo-message
is marked as dependent on labeled-response
here: https://github.com/jesopo/bitbot/blob/fa1e9cbb5812db9e09a48fdb8b13bf68d5b4380c/modules/ircv3_echo_message.py#L3
draft/labeled-response-0.2
is marked as having the alias labeled-response
here, as well is marking it as dependent on batch
: https://github.com/jesopo/bitbot/blob/fa1e9cbb5812db9e09a48fdb8b13bf68d5b4380c/modules/ircv3_labeled_responses.py#L4-L5
This gives a summary of per-channel statistics using a combined total of all participating users on that network such as [Ducks] #channel has befriended # and trapped # ducks (#,#)
.
If a user doesn't !bef
or !trap
a duck within a certain amount of time (ex: 60, 120, or 240 seconds), the duck, that duck could "time out" and BitBot prints that The duck flies away ・。。・゜゜\_o-
.
Optionally, this could be added into the above suggestion as a part of the per-channel statistics.
Apparently BitBot correctly titles sites if the DNS points to a localhost address, say 0.0.0.0
, it titles for localhost
instead of erroring or ignoring, might want to extend the localhost block to that.
Localhost block also not implemented for the most part for localhost IP ranges
127.*.*.*
0.*.*.*
Also maybe add the local network ranges
10.*.*.*
192.168.*.*
to an optional ignore list, as these aren't accessible from the internet, so may also leak services
A command like !rss <url> [<numentries>]
would be nice for checking that Bitbot is able to read and understand a particular feed without having to add it to IRC.
<url> would be the feed to test and <numentries> how many entries are wanted from there to check. However there may be a spam danger there, unless it respects !mores.
Fairly simple: add a timeout between automatically turning urls/refs in to info (auto-github)
We can leverage self.bot.cache.temporary_cache
for this. We still need to event.eat()
when we decide to not auto-github because otherwise github urls will fall through in to title.py
.
The cooldown timeout still needs to be decided. 5 mins?
You can currently run ./start.py -R <server>
to delete a server while bitbot is running out of the same database. Should probably introduce a pid file or database lock of some sort to prevent this.
BitBot suffers noticeable minutely lag when he's off checking a bunch of RSS feeds because it is done in-serial - if each request takes half a second and there's 20 urls it's going to take longer than is acceptable
I propose making this work by using async http requests (I've laid the groundwork here 15e143f)
Jul 08 16:17:19 relpda python3[8127]: 2019-07-08T16:17:19.753Z [ERROR] failed to call event "timer.rss"
Jul 08 16:17:19 relpda python3[8127]: Traceback (most recent call last):
Jul 08 16:17:19 relpda python3[8127]: File "/home/bitbot/bitbot/src/EventManager.py", line 169, in _call
Jul 08 16:17:19 relpda python3[8127]: returned = hook.call(event)
Jul 08 16:17:19 relpda python3[8127]: File "/home/bitbot/bitbot/src/EventManager.py", line 41, in call
Jul 08 16:17:19 relpda python3[8127]: return self.function(event)
Jul 08 16:17:19 relpda python3[8127]: File "/home/bitbot/bitbot/modules/rss.py", line 46, in timer
Jul 08 16:17:19 relpda python3[8127]: pages = utils.http.request_many(hooks.keys())
Jul 08 16:17:19 relpda python3[8127]: File "/home/bitbot/bitbot/src/utils/http.py", line 135, in request_many
Jul 08 16:17:19 relpda python3[8127]: loop.run_until_complete(task)
Jul 08 16:17:19 relpda python3[8127]: File "/home/bitbot/.linuxbrew/Cellar/python/3.7.3/lib/python3.7/asyncio/base_events.py", line 563, in run_until_complete
Jul 08 16:17:19 relpda python3[8127]: future = tasks.ensure_future(future, loop=self)
Jul 08 16:17:19 relpda python3[8127]: File "/home/bitbot/.linuxbrew/Cellar/python/3.7.3/lib/python3.7/asyncio/tasks.py", line 587, in ensure_future
Jul 08 16:17:19 relpda python3[8127]: raise ValueError('loop argument must agree with Future')
Jul 08 16:17:19 relpda python3[8127]: ValueError: loop argument must agree with Future
Jul 09 14:13:23 relpda python3[14289]: 2019-07-09T14:13:23.038Z [INFO] freenode##mikaela | <@Mikaela> !dns mikaela.info any
Jul 09 14:13:23 relpda python3[14289]: 2019-07-09T14:13:23.043Z [ERROR] failed to call event "received.message.channel"
Jul 09 14:13:23 relpda python3[14289]: Traceback (most recent call last):
Jul 09 14:13:23 relpda python3[14289]: File "/home/bitbot/bitbot/src/EventManager.py", line 169, in _call
Jul 09 14:13:23 relpda python3[14289]: returned = hook.call(event)
Jul 09 14:13:23 relpda python3[14289]: File "/home/bitbot/bitbot/src/EventManager.py", line 41, in call
Jul 09 14:13:23 relpda python3[14289]: return self.function(event)
Jul 09 14:13:23 relpda python3[14289]: File "/home/bitbot/bitbot/modules/commands/__init__.py", line 289, in channel_message
Jul 09 14:13:23 relpda python3[14289]: command_prefix=command_prefix)
Jul 09 14:13:23 relpda python3[14289]: File "/home/bitbot/bitbot/modules/commands/__init__.py", line 234, in command
Jul 09 14:13:23 relpda python3[14289]: hook.call(new_event)
Jul 09 14:13:23 relpda python3[14289]: File "/home/bitbot/bitbot/src/EventManager.py", line 41, in call
Jul 09 14:13:23 relpda python3[14289]: return self.function(event)
Jul 09 14:13:23 relpda python3[14289]: File "/home/bitbot/bitbot/modules/ip_addresses.py", line 54, in dns
Jul 09 14:13:23 relpda python3[14289]: query_result = resolver.query(hostname, record_type_strip)
Jul 09 14:13:23 relpda python3[14289]: File "/home/bitbot/.linuxbrew/Cellar/python/3.7.3/lib/python3.7/site-packages/dns/resolver.py", line 1102, in query
Jul 09 14:13:23 relpda python3[14289]: lifetime)
Jul 09 14:13:23 relpda python3[14289]: File "/home/bitbot/.linuxbrew/Cellar/python/3.7.3/lib/python3.7/site-packages/dns/resolver.py", line 852, in query
Jul 09 14:13:23 relpda python3[14289]: raise NoMetaqueries
Jul 09 14:13:23 relpda python3[14289]: dns.resolver.NoMetaqueries: DNS metaqueries are not allowed.
Works fine through Chrome etc but curl shows this:
2019-06-17 16:42:19 (7.15 MB/s) - Read error at byte 151344 (The TLS connection was non- properly terminated.).Retrying.
a warning in general would be nice but also it gives a confusing "unknown command" message.
09:48 <jesopo> !identify
09:48 <+BitBot> jesopo: Unknown command. Did you mean !identify?
Currently, BitBot appears to stop entirely in response to most exceptions.
This ticket is to consider possibilities for error recovery:
2019-05-12T19:05:26.706Z [CRITICAL] Unhandled exception: 'bitbottest'
Traceback (most recent call last):
File "./start.py", line 97, in <module>
bot.run()
File "/home/cloud/src/python/bitbot/src/IRCBot.py", line 237, in run
sock.parse_data(piece)
File "/home/cloud/src/python/bitbot/src/IRCServer.py", line 212, in parse_data
self.check_users()
File "/home/cloud/src/python/bitbot/src/IRCServer.py", line 216, in check_users
self.remove_user(user)
File "/home/cloud/src/python/bitbot/src/IRCServer.py", line 181, in remove_user
del self.users[user.nickname_lower]
KeyError: 'bitbottest'
Maybe I'm just to stupid or dumb 🤷♂️
I can't seem to find any docs related to the payload URL that we need to specify in the webhook.
I was just trying to test it with my personal repo in my network and I've completely failed.
As discussed on freenode in ##ircv3-offtopic as friendly reminder so it won't be forgotten
01:52:24 <e> jesopo: ur bot doesn't know about playlists
01:52:26 <e> plz fix
01:52:31 <jesopo> make an issue pls
01:52:36 <jesopo> or I'll forget
If you do e.g. !channelset github-hook [repo]
and then try to do !channelsetadd github-hook [repo]
, you'll get a AttributeError: 'str' object has no attribute 'append'
; there should be a way (with exports) to mark a setting as array-only.
Can either make this a "reconnect on failure" or "crash bot on failure".
"reconnect on failure" will be a lot easier (just a .get_setting
check after the above line) but I think "crash on failure" is probably a better idea - otherwise we'll just get caught in a reconnection loop if the SASL never succeeds.
Maybe we can make it disconnect a server (not reconnect) if the bot is already running but make it crash the bot if it's the first connection on bot startup?
I'm trying to authenticate for the first time with a masterpass. I've run the appropriate command and have the pass, but when I authenticate I don't get anything back from BitBot and this is spat out in the console:
2019-07-06T04:07:54.720Z [ERROR] failed to call event "received.message.private"
Traceback (most recent call last):
File "/home/fosslinux/packages/bitbot-opers/src/EventManager.py", line 169, in _call
returned = hook.call(event)
File "/home/fosslinux/packages/bitbot-opers/src/EventManager.py", line 41, in call
return self.function(event)
File "/home/fosslinux/packages/bitbot-opers/modules/commands/__init__.py", line 333, in private_message
args_split, event["tags"], hook, command_prefix="")
File "/home/fosslinux/packages/bitbot-opers/modules/commands/__init__.py", line 189, in command
command_method = self._command_method(target, server)
File "/home/fosslinux/packages/bitbot-opers/modules/commands/__init__.py", line 92, in _command_method
self.bot.set_setting(COMMAND_METHOD, "PRIVMSG"))).upper()
AttributeError: 'NoneType' object has no attribute 'upper'
What's going on here?
I am a chanop and have a spam problem, how can I fix it without affecting Matrix users?
You have likely attempted to use mode +r or similar which prevents unidentified users from joining the channel also affecting Matrix users. It's not the only way and you may wish to think about some other modes:
...
MODE +m & setting a bot to autovoice everyone with some delay from joining to the channel. This would likely require you to host something by yourself and it would also prevent using of quiet instead of ban, but would be the easiest solution for your users.
from https://github.com/matrix-org/matrix-appservice-irc/wiki/End-user-FAQ#i-am-a-chanop-and-have-a-spam-problem-how-can-i-fix-it-without-affecting-matrix-users and I have found it a nice feature in general when there is a spambot wave on a network.
Caused by this line
We want /me
to not work for prefixed commands (e.g. !help
) and not work for things like karma (jesopo++
) but want it to work for auto-youtube
. Maybe need to add a kwarg on to the event hooks like ignore-action
that defaults to True
?
<BitBot> [Github] (w0rp/ale) w0rp edited a release: %s - https://git.io/fjWnN
Proposal: Show individual commits if there's 3 or less commits in one go, otherwise crunch it down to a commit diff range
<[redacted> https://www.youtube.com/watch?v=C6nonNRoF7g
<@BitBot> [Title] This is How Google’s Phone Enhances Your Photos - YouTube
Perhaps UTF8 being decoded as latin-1?
>>> "’".encode("utf8").decode("iso-8859-1")
'â\x80\x99'
bitbot assumes that the editor of a comment is the original author, e.g.,
(04:48:54 PM) BitBot: (oragono/oragono) [issue #387] slingamn edited a comment on: upgrade message-tags and msgid to non-draft versions - https://git.io/fhNnc
whereas the actual editor of that comment, as per the link, is not slingamn but DanielOaks
This is either going to have to still require the user has the required mode in the specified channel or have some other way of authenticating the user's permission to do so (caching them having had +o
in the specified channel?)
Currently the hook text is just "submitted a review on [issuenum]", this can be improved by looking at the review state. State can be stuff like approved
changes_requested
See: https://developer.github.com/v4/enum/pullrequestreviewstate/
Suggested wording:
APPROVED -> "approved changes on [issuenum]"
CHANGES_REQUESTED -> "requested changes on [issuenum]"
COMMENTED -> "commented on [issuenum]"
DISMISSED -> "dismissed a review on [issuenum]"
PENDING -> n/a you won't get hooks for this
I was looking for !version for a more accurate issue, but I didn't find it.
I guess I would expect it to say "Bitbot tagheremaybe 078681e on lsb_release -sd
/ Python x.y.z" or something similar that could easily be pasted to an issue.
E.g. in "commit by" message: +0 ∆1 -0 could be green/yellow/red. Some color for repo name, some color for org name, some color for the commiter author/email. Just to make them more visually distinct.
In the "commented"/"merged" messages, the username should be probably the same color as commiter in "commit by"
Summarizing investigation thus far:
draft/resume-0.5
, which technically doesn't exist yet, but the behavior changes shouldn't affect bitbot so you can just bump your own version number if you feel comfortable with that.)2019-05-30T15:47:09.220Z [ERROR] Failed to write to darwin
2019-05-30T15:47:09.220Z [CRITICAL] Unhandled exception: EOF occurred in violation of protocol (_ssl.c:2341)
Traceback (most recent call last):
File "start.py", line 97, in <module>
bot.run()
File "/opt/bitbot/src/IRCBot.py", line 241, in run
sock._send()
File "/opt/bitbot/src/IRCServer.py", line 263, in _send
lines = self.socket._send()
File "/opt/bitbot/src/IRCSocket.py", line 135, in _send
bytes_written_i = self._socket.send(self._write_buffer)
File "/usr/lib/python3.7/ssl.py", line 984, in send
return self._sslobj.write(data)
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:2341)
[pid 29616] 16:49:54.117934 writev(55, [{iov_base="@time=2019-05-30T20:49:54.117Z :irc.darwin.network 001 BitBot :Welcome to the Internet Relay Network BitBot\r\n", iov_len=109}, {iov_base="@time=2019-05-30T20:49:54.117Z :irc.darwin.network 002 BitBot :Your host is irc.darwin.network, running version oragono-1.1.0-unreleased\r\n", iov_len=138}, {iov_base="@time=2019-05-30T20:49:54.117Z :irc.darwin.network 003 BitBot :This server was created Mon, 27 May 2019 10:19:18 UTC\r\n", iov_len=118}, {iov_base="@time=2019-05-30T20:49:54.117Z :irc.darwin.network 004 BitBot irc.darwin.network oragono-1.1.0-unreleased BioRsE bEeIikmntRsl\r\n", iov_len=127}], 4) = 492
[redacted writes of registration burst lines]
[pid 2328] 16:49:54.122621 read(55, 0xc0003ae000, 7168) = -1 EAGAIN (Resource temporarily unavailable)
[redacted writes of registration burst lines]
[pid 29616] 16:49:54.123349 writev(20, [{iov_base=":[email protected] JOIN #bitbot\r\n", iov_len=40}], 1) = 40
[pid 4712] 16:49:54.395443 read(55, "", 7168) = 0
[pid 4712] 16:49:54.395629 write(2, "\33[38;5;243m2019-05-30T20:49:54.395Z\33[0m \33[38;5;8m:\33[0m \33[38;5;117minfo\33[0m \33[38;5;8m:\33[0m \33[38;5;229mlocalconnect-ip\33[0m \33[38;5;8m:\33[0m disconnecting session of BitBot from 2a00:d880:5:3a:4::1\n", 193) = 193
[pid 4712] 16:49:54.395895 write(55, ":[email protected] QUIT :connection closed\r\nERROR :connection closed\r\n", 77) = -1 EPIPE (Broken pipe)
[pid 4712] 16:49:54.395945 --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=29602, si_uid=112} ---
[pid 4712] 16:49:54.396061 close(55) = 0
The important thing here is the read(2)
call that returns 0; oragono is seeing an EOF as well as bitbot.
The issue also reproduces when bitbot is connected directly to a native TLS listener of oragono's, bypassing stunnel:
[pid 29615] 16:55:52.984143 write(56, "\27\3\3\0r\0\0\0\0\0\0\0\31\251\214\tq\332\250\336G\272`\1\20\372ll2\36\220\254w7M\31\t\302\343\243\342\244\302N\6I\262u\237\303\5\242h\217r\33N\343\325\0035\325x!\332zK\353\224\3729\313\332\317]\7\17x|KghZ\20\306\250Uz?zW\25\354\270\355\1f\t\2609|i\234dc\356\201\256\202\216\336\270\365\361\347\271\231\242\245", 119) = 119
[pid 29615] 16:55:52.984237 read(56, 0xc0003e0000, 2435) = -1 EAGAIN (Resource temporarily unavailable)
[redacted JOIN lines sent to other clients]
[pid 4712] 16:55:53.225746 read(56, 0xc0003e0000, 2435) = -1 ECONNRESET (Connection reset by peer)
[pid 4712] 16:55:53.225936 write(2, "\33[38;5;243m2019-05-30T20:55:53.225Z\33[0m \33[38;5;8m:\33[0m \33[38;5;117minfo\33[0m \33[38;5;8m:\33[0m \33[38;5;229mlocalconnect-ip\33[0m \33[38;5;8m:\33[0m disconnecting session of BitBot from 2a00:d880:5:3a:4::1\n", 193) = 193
[pid 4712] 16:55:53.226532 write(56, "\27\3\3\0e\0\0\0\0\0\0\0\32\250\261\347\352\3062\266\3\314\26\330(\332\205\263*N\227\217\312\260\313]0\35\277\362\362\226\265*\323\260\17\325\306\312\345\303\315?\274\272\341\232\342uT\257qo\206&R\202\2566\335\264\236\235\2\363<b\204{Bo\233\375\256\30y'\351\4_I\2249a%\263\3\355\251\225**\3102\276", 106) = -1 EPIPE (Broken pipe)
[pid 4712] 16:55:53.226664 --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=29602, si_uid=112} ---
[pid 4712] 16:55:53.226861 write(56, "\25\3\3\0\32\0\0\0\0\0\0\0\33\347\226\263\n\251\271\272\334H\3366\216\255\212\314\215[\370", 31) = -1 EPIPE (Broken pipe)
[pid 4712] 16:55:53.226983 --- SIGPIPE {si_signo=SIGPIPE, si_code=SI_USER, si_pid=29602, si_uid=112} ---
[pid 29616] 16:55:53.227208 close(56) = 0
Here, instead of read(2)
returning 0, it fails and returns ECONNRESET
, but the behavior is the same.
The issue appears not to reproduce when bitbot speaks plaintext to a client-side stunnel, which then speaks TLS to darwin.
Sometimes instead of the video title, BitBot instead says [Title] YouTube
, using the title
command after that does give the correct title though.
Haven't found any relation to title or content or anything else so far.
quote <category>
gives no hint to how it's used
also qadd
might be best to allow per-channel limiting, so if people don't want them being quoted, it can be turned off on those channels, but not off globally (maybe setting it "on"/"ops only"/"self only"/"off"
? idk)
2019-06-08T00:56:05.657Z [DEBUG] tilde (raw recv) | @time=2019-06-07T23:56:05.000Z :thunix.tilde.chat CAP BitBot NEW :sts
2019-06-08T00:56:05.695Z [DEBUG] tilde (raw recv) | @time=2019-06-07T23:56:05.000Z :thunix.tilde.chat CAP BitBot DEL :sts
2019-06-08T00:56:05.699Z [DEBUG] tilde (raw recv) | @time=2019-06-07T23:56:05.000Z :thunix.tilde.chat CAP BitBot NEW :sts=duration=2592000,preload
2019-06-08T00:56:05.704Z [DEBUG] tilde (raw recv) | @time=2019-06-07T23:56:05.000Z :thunix.tilde.chat CAP BitBot NEW :multi-prefix
2019-06-08T00:56:05.709Z [DEBUG] tilde (raw recv) | @time=2019-06-07T23:56:05.000Z :thunix.tilde.chat CAP BitBot NEW :tls
2019-06-08T00:56:05.713Z [DEBUG] tilde (raw recv) | @time=2019-06-07T23:56:05.000Z :thunix.tilde.chat CAP BitBot NEW :userhost-in-names
2019-06-08T00:56:05.719Z [DEBUG] tilde (raw send) | CAP REQ multi-prefix
2019-06-08T00:56:05.719Z [DEBUG] tilde (raw send) | CAP REQ multi-prefix
2019-06-08T00:56:05.719Z [DEBUG] tilde (raw send) | CAP REQ :multi-prefix userhost-in-names
2019-06-08T00:56:05.821Z [DEBUG] tilde (raw recv) | @time=2019-06-07T23:56:05.000Z :thunix.tilde.chat CAP BitBot ACK :multi-prefix
2019-06-08T00:56:05.825Z [DEBUG] tilde (raw recv) | @time=2019-06-07T23:56:05.000Z :thunix.tilde.chat CAP BitBot ACK :multi-prefix
Jul 08 16:10:08 relpda python3[8127]: 2019-07-08T16:10:08.490Z [INFO] pirateirc#cz-feed | <@MikaelaSuomalainen> !rss add https://www.irozhlas.cz/rss/irozhlas Jul 08 16:10:10 relpda python3[8127]: 2019-07-08T16:10:10.692Z [ERROR] failed to call event "received.message.channel" Jul 08 16:10:10 relpda python3[8127]: Traceback (most recent call last): Jul 08 16:10:10 relpda python3[8127]: File "/home/bitbot/bitbot/src/EventManager.py", line 169, in _call Jul 08 16:10:10 relpda python3[8127]: returned = hook.call(event) Jul 08 16:10:10 relpda python3[8127]: File "/home/bitbot/bitbot/src/EventManager.py", line 41, in call Jul 08 16:10:10 relpda python3[8127]: return self.function(event) Jul 08 16:10:10 relpda python3[8127]: File "/home/bitbot/bitbot/modules/commands/__init__.py", line 289, in channel_message Jul 08 16:10:10 relpda python3[8127]: command_prefix=command_prefix) Jul 08 16:10:10 relpda python3[8127]: File "/home/bitbot/bitbot/modules/commands/__init__.py", line 234, in command Jul 08 16:10:10 relpda python3[8127]: hook.call(new_event) Jul 08 16:10:10 relpda python3[8127]: File "/home/bitbot/bitbot/src/EventManager.py", line 41, in call Jul 08 16:10:10 relpda python3[8127]: return self.function(event) Jul 08 16:10:10 relpda python3[8127]: File "/home/bitbot/bitbot/modules/rss.py", line 121, in rss
Jul 08 16:10:10 relpda python3[8127]: seen_ids = self._check_url(url)
Jul 08 16:10:10 relpda python3[8127]: File "/home/bitbot/bitbot/modules/rss.py", line 94, in _check_url Jul 08 16:10:10 relpda python3[8127]: return [entry["id"] for entry in feed["entries"]]
Jul 08 16:10:10 relpda python3[8127]: File "/home/bitbot/bitbot/modules/rss.py", line 94, in <listcomp> Jul 08 16:10:10 relpda python3[8127]: return [entry["id"] for entry in feed["entries"]]
Jul 08 16:10:10 relpda python3[8127]: File "/home/bitbot/.linuxbrew/Cellar/python/3.7.3/lib/python3.7/site-packages/feedparser.py", line 356, i$ __getitem__ Jul 08 16:10:10 relpda python3[8127]: return dict.__getitem__(self, key)
There isn't even an error about failure to add the feed, only this in terminal
This is the main newspaper of Finnish Greens Party and the latest topic is about them being on holiday, but regardless their latest topics were printed to a channel a few times at night.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.