Skip to content

Sourcery refactored master branch#65

Open
sourcery-ai[bot] wants to merge 1 commit intomasterfrom
sourcery/master
Open

Sourcery refactored master branch#65
sourcery-ai[bot] wants to merge 1 commit intomasterfrom
sourcery/master

Conversation

@sourcery-ai
Copy link
Contributor

@sourcery-ai sourcery-ai bot commented Jul 19, 2020

Branch master refactored by Sourcery.

If you're happy with these changes, merge this Pull Request using the Squash and merge strategy.

See our documentation here.

Run Sourcery locally

Reduce the feedback loop during development by using the Sourcery editor plugin:

Review changes via command line

To manually merge these changes, make sure you're on the master branch, then run:

git fetch origin sourcery/master
git merge --ff-only FETCH_HEAD
git reset HEAD^

Copy link
Contributor Author

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to GitHub API limits, only the first 60 comments can be shown.

imported_module.__mod_name__ = imported_module.__name__

if not imported_module.__mod_name__.lower() in IMPORTED:
if imported_module.__mod_name__.lower() not in IMPORTED:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 75-75 refactored with the following changes:

  • Simplify logical expression using De Morgan identities (de-morgan)

Comment on lines -245 to +249
if excp.message == "Message is not modified":
pass
elif excp.message == "Query_id_invalid":
pass
elif excp.message == "Message can't be deleted":
pass
else:
if (
excp.message != "Message is not modified"
and excp.message != "Query_id_invalid"
and excp.message != "Message can't be deleted"
):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function help_button refactored with the following changes:

  • Merge duplicate blocks in conditional (merge-duplicate-blocks)
  • Remove redundant conditional (remove-redundant-if)
  • Swap if/else to remove empty if body (remove-pass-body)

Comment on lines -382 to +384
if excp.message == "Message is not modified":
pass
elif excp.message == "Query_id_invalid":
pass
elif excp.message == "Message can't be deleted":
pass
else:
if (
excp.message != "Message is not modified"
and excp.message != "Query_id_invalid"
and excp.message != "Message can't be deleted"
):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function settings_button refactored with the following changes:

  • Merge duplicate blocks in conditional (merge-duplicate-blocks)
  • Remove redundant conditional (remove-redundant-if)
  • Swap if/else to remove empty if body (remove-pass-body)

return log_message

if user_member.status == 'administrator' or user_member.status == 'creator':
if user_member.status in ['administrator', 'creator']:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function promote refactored with the following changes:

  • Hoist repeated code outside conditional statement (hoist-statement-from-if)
  • Replace multiple comparisons of same variable with in operator (merge-comparisons)

Comment on lines -107 to +105
if not user_member.status == 'administrator':
if user_member.status != 'administrator':
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function demote refactored with the following changes:

  • Simplify logical expression using De Morgan identities (de-morgan)

else:
message += '\n'.join(users)

message += '\n'.join(users) if users else "Noone is being ignored as of yet."
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function bl_users refactored with the following changes:

  • Ensure first condition in if is positive (swap-if-else-branches)
  • Replace if statement with if expression (assign-if-exp)

else:
CMD_STARTERS = '/'

CMD_STARTERS = ('/', '!') if ALLOW_EXCL else '/'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines 13-17 refactored with the following changes:

  • Replace if statement with if expression (assign-if-exp)

Comment on lines -46 to +58
message = update.effective_message
if chat.get_member(bot.id).can_delete_messages and sql.is_enabled(chat.id):
message = update.effective_message

if chat.get_member(bot.id).can_delete_messages:
if sql.is_enabled(chat.id):
fst_word = message.text.strip().split(None, 1)[0]
fst_word = message.text.strip().split(None, 1)[0]

if len(fst_word) > 1 and any(fst_word.startswith(start)
for start in CMD_STARTERS):
if len(fst_word) > 1 and any(fst_word.startswith(start)
for start in CMD_STARTERS):

command = fst_word[1:].split('@')
chat = update.effective_chat
command = fst_word[1:].split('@')
chat = update.effective_chat

ignored = sql.is_command_ignored(chat.id, command[0])
if ignored:
return
ignored = sql.is_command_ignored(chat.id, command[0])
if ignored:
return

if command[0] not in command_list:
message.delete()
if command[0] not in command_list:
message.delete()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function clean_blue_text_must_click refactored with the following changes:

  • Move assignments closer to their usage (move-assign)
  • Merge nested if conditions (merge-nested-ifs)

Comment on lines -94 to +89
if clean_status:
clean_status = "Enabled"
else:
clean_status = "Disabled"
clean_status = "Enabled" if clean_status else "Disabled"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function set_blue_text_must_click refactored with the following changes:

  • Replace if statement with if expression (assign-if-exp)

Comment on lines -218 to +229
if excp.message == "Unsupported url protocol":
message.reply_text(
"You seem to be trying to use an unsupported url protocol. Telegram "
"doesn't support buttons for some protocols, such as tg://. Please try "
"again, or ask @Aman_Ahmed for help.")
elif excp.message == "Reply message not found":
if excp.message == "Reply message not found":
bot.send_message(
chat.id,
filt.reply,
parse_mode=ParseMode.MARKDOWN,
disable_web_page_preview=True,
reply_markup=keyboard)
elif excp.message == "Unsupported url protocol":
message.reply_text(
"You seem to be trying to use an unsupported url protocol. Telegram "
"doesn't support buttons for some protocols, such as tg://. Please try "
"again, or ask @Aman_Ahmed for help.")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function reply_filter refactored with the following changes:

  • Simplify conditional into switch-like form (switch)

Comment on lines -43 to +52
pass

try:
progress_message.delete()
except Exception as e:
print(e)
pass

if not remove:
return kicked_chats
else:
if remove:
for muted_chat in chat_list:
sleep(0.1)
user_sql.rem_chat(muted_chat)
return kicked_chats

return kicked_chats
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function get_invalid_chats refactored with the following changes:

  • Remove redundant pass statement (remove-redundant-pass)
  • Hoist repeated code outside conditional statement (hoist-statement-from-if)
  • Swap if/else to remove empty if body (remove-pass-body)

gban_sql.ungban_user(user_id)
return ungbanned_users

return ungbanned_users
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function get_invalid_gban refactored with the following changes:

  • Remove redundant pass statement (remove-redundant-pass)
  • Hoist repeated code outside conditional statement (hoist-statement-from-if)
  • Swap if/else to remove empty if body (remove-pass-body)

progress_bar, chat_id, progress_message.message_id)
except Exception as e:
print(e)
pass
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function get_muted_chats refactored with the following changes:

  • Remove redundant pass statement (remove-redundant-pass)
  • Hoist repeated code outside conditional statement (hoist-statement-from-if)
  • Swap if/else to remove empty if body (remove-pass-body)

Comment on lines -190 to +197
if query_type == "db_leave_chat":
if query.from_user.id in admin_list:
bot.editMessageText(
"Leaving chats ...",
chat_id,
message.message_id)
chat_count = get_muted_chats(bot, update, True)
bot.sendMessage(chat_id, f"Left {chat_count} chats.")
else:
query.answer("You are not allowed to use this.")
if query_type == "db_leave_chat" and query.from_user.id in admin_list:
bot.editMessageText(
"Leaving chats ...",
chat_id,
message.message_id)
chat_count = get_muted_chats(bot, update, True)
bot.sendMessage(chat_id, f"Left {chat_count} chats.")
elif (
query_type == "db_leave_chat"
or query_type == "db_cleanup"
and query.from_user.id not in admin_list
):
query.answer("You are not allowed to use this.")
elif query_type == "db_cleanup":
if query.from_user.id in admin_list:
bot.editMessageText(
"Cleaning up DB ...",
chat_id,
message.message_id)
invalid_chat_count = get_invalid_chats(bot, update, True)
invalid_gban_count = get_invalid_gban(bot, update, True)
reply = "Cleaned up {} chats and {} gbanned users from db.".format(
invalid_chat_count, invalid_gban_count)
bot.sendMessage(chat_id, reply)
else:
query.answer("You are not allowed to use this.")
bot.editMessageText(
"Cleaning up DB ...",
chat_id,
message.message_id)
invalid_chat_count = get_invalid_chats(bot, update, True)
invalid_gban_count = get_invalid_gban(bot, update, True)
reply = "Cleaned up {} chats and {} gbanned users from db.".format(
invalid_chat_count, invalid_gban_count)
bot.sendMessage(chat_id, reply)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function callback_button refactored with the following changes:

  • Merge duplicate blocks in conditional (merge-duplicate-blocks)
  • Remove redundant conditional (remove-redundant-if)

return False
else:
return True
return not sql.is_command_disabled(chat.id, self.friendly)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function DisableAbleMessageHandler.check_update refactored with the following changes:

  • Simplify conditional into return statement (return-identity)

Comment on lines -188 to +194
if user.id in SUDO_USERS:
pass
else:
if user.id not in SUDO_USERS:
for admin in administrators:
status = admin.status
if status == "creator":
if str(admin.user.id) == str(user.id):
pass
else:
message.reply_text(
"Only group creators can use this command!")
return
if status == "creator" and str(admin.user.id) != str(user.id):
message.reply_text(
"Only group creators can use this command!")
return
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function join_fed refactored with the following changes:

  • Merge nested if conditions (merge-nested-ifs)
  • Swap if/else to remove empty if body (remove-pass-body)

Comment on lines -249 to +246
if get_fedlog:
if eval(get_fedlog):
bot.send_message(
get_fedlog, "Chat *{}* has left the federation *{}*".format(
chat.title, fed_info['fname']), parse_mode="markdown")
if get_fedlog and eval(get_fedlog):
bot.send_message(
get_fedlog, "Chat *{}* has left the federation *{}*".format(
chat.title, fed_info['fname']), parse_mode="markdown")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function leave_fed refactored with the following changes:

  • Merge nested if conditions (merge-nested-ifs)

Comment on lines -284 to +283
elif not message.reply_to_message and (not args or (
len(args) >= 1 and not args[0].startswith("@") and not args[0].isdigit() and not message.parse_entities(
[MessageEntity.TEXT_MENTION]))):
elif (
not message.reply_to_message
and len(args) >= 1
and not args[0].startswith("@")
and not args[0].isdigit()
and not message.parse_entities([MessageEntity.TEXT_MENTION])
):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function user_join_fed refactored with the following changes:

  • Remove redundant conditional (remove-redundant-if)

Comment on lines -338 to +341
elif not message.reply_to_message and (not args or (
len(args) >= 1 and not args[0].startswith("@") and not args[0].isdigit() and not message.parse_entities(
[MessageEntity.TEXT_MENTION]))):
elif (
not message.reply_to_message
and len(args) >= 1
and not args[0].startswith("@")
and not args[0].isdigit()
and not message.parse_entities([MessageEntity.TEXT_MENTION])
):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function user_demote_fed refactored with the following changes:

  • Remove redundant conditional (remove-redundant-if)

message = update.effective_message
if args:
fed_id = args[0]
info = sql.get_fed_info(fed_id)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function fed_info refactored with the following changes:

  • Hoist repeated code outside conditional statement (hoist-statement-from-if)

Comment on lines -607 to +619
if get_fedlog:
if int(get_fedlog) != int(chat.id):
bot.send_message(get_fedlog,
"<b>FedBan reason updated</b>"
"\n<b>Federation:</b> {}"
"\n<b>Federation Admin:</b> {}"
"\n<b>User:</b> {}"
"\n<b>User ID:</b> <code>{}</code>"
"\n<b>Reason:</b> {}".format(fed_name,
mention_html(user.id,
user.first_name),
user_target,
fban_user_id,
reason),
parse_mode="HTML")
if get_fedlog and int(get_fedlog) != int(chat.id):
bot.send_message(get_fedlog,
"<b>FedBan reason updated</b>"
"\n<b>Federation:</b> {}"
"\n<b>Federation Admin:</b> {}"
"\n<b>User:</b> {}"
"\n<b>User ID:</b> <code>{}</code>"
"\n<b>Reason:</b> {}".format(fed_name,
mention_html(user.id,
user.first_name),
user_target,
fban_user_id,
reason),
parse_mode="HTML")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function fed_ban refactored with the following changes:

  • Merge nested if conditions (merge-nested-ifs)

Comment on lines -928 to +936
if get_fedlog:
if int(get_fedlog) != int(chat.id):
bot.send_message(get_fedlog,
"<b>Un-FedBan</b>"
"\n<b>Federation:</b> {}"
"\n<b>Federation Admin:</b> {}"
"\n<b>User:</b> {}"
"\n<b>User ID:</b> <code>{}</code>".format(info['fname'],
mention_html(user.id,
user.first_name),
user_target,
fban_user_id),
parse_mode="HTML")
if get_fedlog and int(get_fedlog) != int(chat.id):
bot.send_message(get_fedlog,
"<b>Un-FedBan</b>"
"\n<b>Federation:</b> {}"
"\n<b>Federation Admin:</b> {}"
"\n<b>User:</b> {}"
"\n<b>User ID:</b> <code>{}</code>".format(info['fname'],
mention_html(user.id,
user.first_name),
user_target,
fban_user_id),
parse_mode="HTML")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function unfban refactored with the following changes:

  • Remove redundant pass statement (remove-redundant-pass)
  • Merge nested if conditions (merge-nested-ifs)

"*{}* has updated federation rules for fed *{}*".format(
user.first_name,
getfed['fname']),
parse_mode="markdown")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function set_frules refactored with the following changes:

  • Merge nested if conditions (merge-nested-ifs)

Comment on lines -1541 to +1539
if get_fedlog:
if eval(get_fedlog):
teks = "Fed *{}* has successfully imported data. {} banned.".format(
getfed['fname'], success)
if failed >= 1:
teks += " {} Failed to import.".format(failed)
bot.send_message(get_fedlog, teks, parse_mode="markdown")
if get_fedlog and eval(get_fedlog):
teks = "Fed *{}* has successfully imported data. {} banned.".format(
getfed['fname'], success)
if failed >= 1:
teks += " {} Failed to import.".format(failed)
bot.send_message(get_fedlog, teks, parse_mode="markdown")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function fed_import_bans refactored with the following changes:

  • Merge nested if conditions (merge-nested-ifs)

Comment on lines -1650 to -1657
if args:
if args[0].isdigit():
user_id = args[0]
else:
user_id = extract_user(message, args)
if args and args[0].isdigit():
user_id = args[0]
else:
user_id = extract_user(message, args)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function fed_stat_user refactored with the following changes:

  • Merge duplicate blocks in conditional (merge-duplicate-blocks)

Comment on lines -288 to +280
if bool(random.getrandbits(1)):
reply_text += c.upper()
else:
reply_text += c.lower()
reply_text += c.upper() if bool(random.getrandbits(1)) else c.lower()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function copypasta refactored with the following changes:

  • Replace if statement with if expression (assign-if-exp)

if excp.message in UNGBAN_ERRORS:
pass
else:
if excp.message not in UNGBAN_ERRORS:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function ungban refactored with the following changes:

  • Swap if/else to remove empty if body (remove-pass-body)

Comment on lines -375 to -381
return
else:
return
return
except Exception as e:
print(e)
pass

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function check_and_ban refactored with the following changes:

  • Remove redundant pass statement (remove-redundant-pass)
  • Hoist repeated code outside conditional statement (hoist-statement-from-if)

Comment on lines -394 to +408
if sql.does_chat_gban(
update.effective_chat.id) and update.effective_chat.get_member(
bot.id).can_restrict_members:
user = update.effective_user
chat = update.effective_chat
msg = update.effective_message
if (
not sql.does_chat_gban(update.effective_chat.id)
or not update.effective_chat.get_member(bot.id).can_restrict_members
):
return
user = update.effective_user
chat = update.effective_chat
msg = update.effective_message

if user and not is_user_admin(chat, user.id):
check_and_ban(update, user.id)
if user and not is_user_admin(chat, user.id):
check_and_ban(update, user.id)

if msg.new_chat_members:
new_members = update.effective_message.new_chat_members
for mem in new_members:
check_and_ban(update, mem.id)
if msg.new_chat_members:
new_members = update.effective_message.new_chat_members
for mem in new_members:
check_and_ban(update, mem.id)

if msg.reply_to_message:
user = msg.reply_to_message.from_user
if user and not is_user_admin(chat, user.id):
check_and_ban(update, user.id, should_message=False)
if msg.reply_to_message:
user = msg.reply_to_message.from_user
if user and not is_user_admin(chat, user.id):
check_and_ban(update, user.id, should_message=False)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function enforce_gban refactored with the following changes:

  • Add guard clause (last-if-guard)

Comment on lines -418 to +414
if len(args) > 0:
if args:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function gbanstat refactored with the following changes:

  • Simplify sequence comparison (simplify-len-comparison)

@sourcery-ai
Copy link
Contributor Author

sourcery-ai bot commented Jul 19, 2020

Sourcery Code Quality Report (beta)

✅  Merging this PR will increase code quality in the affected files by 0.05 out of 10.

Quality metrics Before After Change
Complexity 6.37 6.01 -0.36 🔵
Method Length 89.60 88.73 -0.87 🔵
Quality 7.70 7.75 0.05 🔵
Other metrics Before After Change
Lines 13513 13307 -206
Changed files Quality Before Quality After Quality Change
lynda/main.py 6.70 6.73 0.03 🔵
lynda/modules/admin.py 7.15 7.18 0.03 🔵
lynda/modules/anime.py 7.52 7.53 0.01 🔵
lynda/modules/antiflood.py 7.99 8.00 0.01 🔵
lynda/modules/bans.py 6.67 6.68 0.01 🔵
lynda/modules/blacklist.py 7.84 7.86 0.02 🔵
lynda/modules/blacklist_stickers.py 6.59 6.61 0.02 🔵
lynda/modules/blacklistusers.py 7.78 7.81 0.03 🔵
lynda/modules/cleaner.py 7.35 7.42 0.07 🔵
lynda/modules/cust_filters.py 7.45 7.45 0.00
lynda/modules/dbcleanup.py 7.33 7.41 0.08 🔵
lynda/modules/disable.py 8.34 8.38 0.04 🔵
lynda/modules/disasters.py 7.42 7.42 0.00
lynda/modules/extra.py 6.49 6.51 0.02 🔵
lynda/modules/feds.py 6.10 6.18 0.08 🔵
lynda/modules/fun.py 8.28 8.30 0.02 🔵
lynda/modules/global_bans.py 7.16 7.22 0.06 🔵
lynda/modules/gtranslator.py 6.48 6.50 0.02 🔵
lynda/modules/lastfm.py 8.24 8.24 0.00
lynda/modules/locks.py 7.98 8.02 0.04 🔵
lynda/modules/log_channel.py 8.17 8.34 0.17 🔵
lynda/modules/misc.py 7.58 7.60 0.02 🔵
lynda/modules/modules.py 6.82 6.82 0.00
lynda/modules/muting.py 7.08 7.12 0.04 🔵
lynda/modules/notes.py 8.12 8.12 0.00
lynda/modules/ping.py 8.23 8.29 0.06 🔵
lynda/modules/reporting.py 7.18 7.18 0.00
lynda/modules/rss.py 6.94 6.97 0.03 🔵
lynda/modules/rules.py 9.01 9.01 0.00
lynda/modules/sed.py 6.86 6.97 0.11 🔵
lynda/modules/special.py 8.36 8.41 0.05 🔵
lynda/modules/stickers.py 7.03 7.03 0.00
lynda/modules/userinfo.py 7.58 7.62 0.04 🔵
lynda/modules/users.py 8.45 8.46 0.01 🔵
lynda/modules/welcome.py 6.93 6.93 0.00
lynda/modules/helper_funcs/chat_status.py 8.40 8.42 0.02 🔵
lynda/modules/helper_funcs/extraction.py 7.65 7.68 0.03 🔵
lynda/modules/helper_funcs/handlers.py 8.50 8.53 0.03 🔵
lynda/modules/helper_funcs/msg_types.py 5.77 5.87 0.10 🔵
lynda/modules/helper_funcs/string_handling.py 7.42 7.56 0.14 🔵
lynda/modules/helper_funcs/telethn/chatstatus.py 9.20 9.39 0.19 🔵
lynda/modules/sql/chatbot_sql.py 9.27 9.30 0.03 🔵
lynda/modules/sql/cleaner_sql.py 8.88 8.90 0.02 🔵
lynda/modules/sql/feds_sql.py 8.41 8.49 0.08 🔵

Here are some functions in these files that still need a tune-up:

File Function Complexity Length Overall Recommendation
lynda/modules/feds.py fed_ban 135 895.27 0.05 Split out functionality. Reduce complexity
lynda/modules/feds.py fed_import_bans 125 785.27 0.07 Split out functionality. Reduce complexity
lynda/modules/stickers.py kang 76 791.95 0.46 Split out functionality. Reduce complexity
lynda/modules/gtranslator.py totranslate 75 492.22 0.55 Split out functionality. Reduce complexity
lynda/modules/welcome.py new_member 71 577.45 0.58 Split out functionality. Reduce complexity

Please see our documentation here for details on how these metrics are calculated.

We are actively working on this report - lots more documentation and extra metrics to come!

Let us know what you think of it via email or our Gitter!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants