def run(self, event): # Get server object server_obj = event.server # If no arguments given, turn the password for current channel off. line_clean = event.command_args.strip() if line_clean == "": event.channel.password = None return event.create_response("Channel password disabled.") # If line has 1 argument, set password for current channel line_split = line_clean.split() if len(line_split) == 1: # Check if null was specified input_null = Commons.is_string_null(line_split[0]) if input_null: event.channel.password = None return event.create_response("Channel password disabled.") else: event.channel.password = line_split[0] return event.create_response("Channel password set.") # Otherwise line has 2 or more arguments. # Assume first is channel, and second is password. input_null = Commons.is_string_null(line_split[1]) target_channel_name = line_split[0] target_channel = server_obj.get_channel_by_name(target_channel_name) if input_null: target_channel.password = None return event.create_response( "Channel password disabled for {}.".format( target_channel.name)) else: target_channel.password = line_split[1] return event.create_response("Channel password set for {}.".format( target_channel.name))
def run(self, event): if event.command_args.count(" ") == 0: number = event.command_args lang = "american" elif event.command_args.split()[1].lower() in ["british", "english"]: number = event.command_args.split()[0] lang = "english" elif event.command_args.split()[1].lower() in ["european", "french"]: number = event.command_args.split()[0] lang = "european" else: number = event.command_args.split()[0] lang = "american" if Commons.check_numbers(number): number = number elif Commons.check_calculation(number): function_dispatcher = event.server.hallo.function_dispatcher calc_func = function_dispatcher.get_function_by_name("calc") calc_obj = function_dispatcher.get_function_object( calc_func) # type: Calculate number = calc_obj.process_calculation(number) else: return event.create_response( "Error, you must enter a valid number or calculation.") return event.create_response(self.number_word(number, lang) + ".")
def update_from_cryptonator_data(self, repo): """ Updates the value of conversion cryptocurrencies using cryptonator data. :type repo: ConvertRepo """ # Get currency ConvertType currency_type = repo.get_type_by_name("currency") # Pull json data from preev website, combine into 1 dict currency_codes = [ "LTC", "BTC", "BCH", "DOGE", "XMR", "ETH", "ETC", "DASH" ] for code in currency_codes: # Get data try: data = Commons.load_url_json( "https://api.cryptonator.com/api/ticker/{}-eur".format( code)) except Exception as e: # If it fails, because it failed to parse the JSON, give it another go # Cryptonator API returns HTML sometimes. I don't know why. if "Expecting value:" in str(e): time.sleep(5) data = Commons.load_url_json( "https://api.cryptonator.com/api/ticker/{}-eur".format( code)) else: raise e # Get the ConvertUnit object for the currency reference currency_unit = currency_type.get_unit_by_name(code) if currency_unit is None: continue # Update the value currency_unit.update_value(data["ticker"]["price"])
def run(self, event): word_list = Commons.read_file_to_list("store/ouija_wordlist.txt") num_words = Commons.get_random_int(1, 3)[0] rand_words = Commons.get_random_choice(word_list, num_words) output_string = "I'm getting a message from the other side... {}.".format( " ".join(rand_words) ) return event.create_response(output_string)
def run(self, event): url = "https://type.fit/api/quotes" # Get api response json_dict = Commons.load_url_json(url) # Select a random quote from response quote = Commons.get_random_choice(json_dict)[0] # Construct response quote_text = quote["text"] author = quote["author"] output = '"{}" - {}'.format(quote_text, author) return event.create_response(output)
def _get_api_data(self, path: str, needs_cookie: bool = False) -> Union[Dict, List]: fa_api_url = os.getenv("FA_API_URL", "https://faexport.spangle.org.uk") url = "{}/{}".format(fa_api_url, path) if needs_cookie: cookie_string = "b=" + self.b + "; a=" + self.a return Commons.load_url_json(url, [["FA_COOKIE", cookie_string]]) return Commons.load_url_json(url)
def run(self, event): input_clean = event.command_args.strip().lower() url = "https://api.randomuser.me/0.6/?nat=gb&format=json" # Get api response json_dict = Commons.load_url_json(url) user_dict = json_dict["results"][0]["user"] # Construct response name = "{} {} {}".format( user_dict["name"]["title"], user_dict["name"]["first"], user_dict["name"]["last"], ).title() email = user_dict["email"] address = "{}, {}, {}".format( user_dict["location"]["street"].title(), user_dict["location"]["city"].title(), user_dict["location"]["postcode"], ) username = user_dict["username"] password = user_dict["password"] date_of_birth = Commons.format_unix_time(int(user_dict["dob"])) phone_home = user_dict["phone"] phone_mob = user_dict["cell"] national_insurance = user_dict["NINO"] pronoun = "he" if user_dict["gender"] == "male" else "she" pronoun_possessive = "his" if user_dict["gender"] == "male" else "her" if input_clean not in ["more", "full", "verbose", "all"]: output = "I have generated this person: Say hello to {}. {} was born at {}.".format( name, pronoun.title(), date_of_birth ) return event.create_response(output) output = ( "I have generated this person: Say hello to {}. " "{} was born at {} and lives at {}. " '{} uses the email {}, the username {} and usually uses the password "{}". ' "{} home number is {} but {} mobile number is {}. " "{} national insurance number is {}.".format( name, pronoun.title(), date_of_birth, address, pronoun.title(), email, username, password, pronoun_possessive.title(), phone_home, pronoun_possessive, phone_mob, pronoun_possessive.title(), national_insurance, ) ) return event.create_response(output)
def run(self, event): # Get server object server_obj = event.server # If no arguments given, toggle caps lock in current destination line_clean = event.command_args.strip() if line_clean == "": event.channel.use_caps_lock = not event.channel.use_caps_lock return event.create_response("Caps lock toggled.") # If line has 1 argument, line_split = line_clean.split() if len(line_split) == 1: # Check if a boolean was specified input_bool = Commons.string_to_bool(line_split[0]) if input_bool is not None: event.channel.use_caps_lock = input_bool return event.create_response("Caps lock set {}.".format({ False: "off", True: "on" }[input_bool])) # Check if a channel was specified target_channel = server_obj.get_channel_by_name(line_split[0]) if target_channel.in_channel: target_channel.use_caps_lock = not target_channel.use_caps_lock return event.create_response("Caps lock toggled in {}.".format( target_channel.name)) # Otherwise input unknown return event.create_response( "Error, I don't understand your input, " + "please specify a channel and whether to turn caps lock on or off." ) # Otherwise line has 2 or more arguments. # Check if first argument is boolean input_bool = Commons.string_to_bool(line_split[0]) target_channel_name = line_split[1] if input_bool is None: input_bool = Commons.string_to_bool(line_split[1]) target_channel_name = line_split[0] if input_bool is None: return event.create_response( "Error, I don't understand your input, please specify a channel and " + "whether to turn caps lock on or off.") target_channel = server_obj.get_channel_by_name(target_channel_name) if target_channel is None or not target_channel.in_channel: return event.create_response("Error, I'm not in that channel.") target_channel.use_caps_lock = input_bool return event.create_response("Caps lock set {} in {}.".format({ False: "off", True: "on" }[input_bool], target_channel.name))
def test_load_url_string(): url1 = "https://httpbin.org/get" data1 = Commons.load_url_string(url1) data1split = data1.split("\n") assert data1split[0] == "{", "First line incorrect." assert data1split[1] == ' "args": {}, ', "String response incorrect." url2 = "https://httpbin.org/headers" headers2 = [["User-Agent", "Example data"]] data2 = Commons.load_url_string(url2, headers2) data2split = data2.split("\n") assert data2split[0] == "{", "First line incorrect." assert data2split[1] == ' "headers": {', "String response incorrect." assert '"User-Agent": "Example data"' in data2, "Headers missing from request."
def run_dice_format(self, num_dice, num_sides): """Rolls numDice number of dice, each with numSides number of sides""" if num_dice == 0 or num_dice > 100: return "Invalid number of dice." if num_sides == 0 or num_sides > 1000000: return "Invalid number of sides." if num_dice == 1: rand = Commons.get_random_int(1, num_sides)[0] return "I roll {}!!!".format(rand) else: dice_rolls = Commons.get_random_int(1, num_sides, num_dice) output_string = "I roll {}. The total is {}.".format( ", ".join([str(x) for x in dice_rolls]), sum(dice_rolls)) return output_string
def test_load_url_json(): url1 = "https://httpbin.org/get" data1 = Commons.load_url_json(url1) assert "args" in data1, "Element missing from json dict response." assert "headers" in data1, "Element missing from json dict response." assert "origin" in data1, "Element missing from json dict response." assert "url" in data1, "Element missing from json dict response." assert data1["url"] == url1, "JSON data incorrect." url2 = "https://httpbin.org/headers" headers2 = [["User-Agent", "Example data"]] data2 = Commons.load_url_json(url2, headers2) assert "headers" in data2, "Element missing from json response dict." assert "User-Agent" in data2["headers"], "Header missing from request." assert (data2["headers"]["User-Agent"] == "Example data" ), "Header data missing from request."
def run(self, event): rgb_list = Commons.get_random_int(0, 255, 3) hex_code = "{}{}{}".format( hex(rgb_list[0])[2:].zfill(2), hex(rgb_list[1])[2:].zfill(2), hex(rgb_list[2])[2:].zfill(2), ).upper() url = "https://www.thecolorapi.com/id?hex={}".format(hex_code) human_url = "{}&format=html".format(url) colour_data = Commons.load_url_json(url) colour_name = colour_data["name"]["value"] output = "Randomly chosen colour is: {} #{} or rgb({},{},{}) {}".format( colour_name, hex_code, rgb_list[0], rgb_list[1], rgb_list[2], human_url ) return event.create_response(output)
def run(self, event): # Check for server name in input line line = event.command_args server_name = Commons.find_parameter("server", line) if server_name is None: server_obj = event.server else: server_obj = event.server.hallo.get_server_by_name(server_name) line = line.replace("server={}".format(server_name), "").strip() if server_obj is None: return event.create_response("Invalid server specified.") # Get channel name channel_name = line.split()[0].lower() # Check for channel password channel_password = None if channel_name != line: channel_password = line[len(channel_name):] # Get channel object, set password channel_obj = server_obj.get_channel_by_name(channel_name) channel_obj.password = channel_password # Join channel if not already in channel. if channel_obj.in_channel: return event.create_response("I'm already in that channel.") server_obj.join_channel(channel_obj) return event.create_response("Joined {}.".format(channel_name))
def run(self, event): line_clean = event.command_args.lower().split() # Load XML doc = minidom.parse("store/pokemon/pokemon.xml") pokemon_list_elem = doc.getElementsByTagName("pokemon_list")[0] # Loop through pokemon, searching for the specified pokemon selected_pokemon_elem = None for pokemon_elem in pokemon_list_elem.getElementsByTagName("pokemon"): pokemon_name = pokemon_elem.getElementsByTagName("name")[ 0 ].firstChild.data.lower() pokemon_number = pokemon_elem.getElementsByTagName("dex_number")[ 0 ].firstChild.data if line_clean == pokemon_name or line_clean == pokemon_number: selected_pokemon_elem = pokemon_elem break # If pokemon couldn't be found, return a message to the user if selected_pokemon_elem is None: return event.create_response("No available pokedex data.") # Select a random pokedex entry pokedex_entry_list_elem = selected_pokemon_elem.getElementsByTagName( "dex_entry_list" ) pokedex_entry_elem = Commons.get_random_choice( pokedex_entry_list_elem.getElementsByTagName("dex_entry") )[0] pokedex_entry_text = pokedex_entry_elem.firstChild.data return event.create_response(pokedex_entry_text)
def get_youtube_playlist(self, playlist_id, page_token=None): """Returns a list of video information for a youtube playlist.""" list_videos = [] # Get API key api_key = self.hallo_obj.get_api_key("youtube") if api_key is None: raise Exception("Youtube API key missing.") # Find API url api_fields = "nextPageToken,items(snippet/title,snippet/resourceId/videoId)" api_url = ( "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId={}" "&fields={}&key={}".format(playlist_id, urllib.parse.quote(api_fields), api_key)) if page_token is not None: api_url += "&pageToken={}".format(page_token) # Load API response (in json). api_dict = Commons.load_url_json(api_url) for api_item in api_dict["items"]: new_video = { "title": api_item["snippet"]["title"], "video_id": api_item["snippet"]["resourceId"]["videoId"], } list_videos.append(new_video) # Check if there's another page to add if "nextPageToken" in api_dict: list_videos.extend( self.get_youtube_playlist(playlist_id, api_dict["nextPageToken"])) # Return list return list_videos
def test_reply_mfw(hallo_getter): hallo, test_server, test_channel, test_user = hallo_getter({"silly"}) reply_func = hallo.function_dispatcher.get_function_by_name("reply") reply_obj = hallo.function_dispatcher.get_function_object( reply_func) # type: Reply # Check MFW produces response response = reply_obj.passive_run( EventMessage(test_server, test_channel, test_user, "MFW"), hallo) assert "http" in response.text # Check multiple times for _ in range(10): response = reply_obj.passive_run( EventMessage(test_server, test_channel, test_user, "MFW"), hallo) assert "http" in response.text response_url = "http" + response.text.split("http")[1] page_request = urllib.request.Request(response_url) page_opener = urllib.request.build_opener() resp_data = page_opener.open(page_request).read() assert len(resp_data) > 0 # Check upper case url response_url_upper = Commons.upper(response_url) page_request = urllib.request.Request(response_url_upper) page_opener = urllib.request.build_opener() resp_data_upper = page_opener.open(page_request).read() assert len(resp_data_upper) > 0
def site_youtube(self, url_address, page_opener, page_request): """Handling for youtube links""" # Find video id if "youtu.be" in url_address: video_id = url_address.split("/")[-1].split("?")[0] else: video_id = url_address.split("/")[-1].split("=")[1].split("&")[0] # Find API url api_key = self.hallo_obj.get_api_key("youtube") if api_key is None: return None api_url = ("https://www.googleapis.com/youtube/v3/videos?id={}" "&part=snippet,contentDetails,statistics&key={}".format( video_id, api_key)) # Load API response (in json). api_dict = Commons.load_url_json(api_url) # Get video data from API response. video_title = api_dict["items"][0]["snippet"]["title"] video_duration = api_dict["items"][0]["contentDetails"]["duration"][ 2:].lower() video_views = api_dict["items"][0]["statistics"]["viewCount"] # Create output output = "Youtube video> Title: {} | Length {} | Views: {}.".format( video_title, video_duration, video_views) return output
def site_imgur(self, url_address, page_opener, page_request): """Handling imgur links""" # Hand off imgur album links to a different handler function. if "/a/" in url_address: return self.site_imgur_album(url_address, page_opener, page_request) # Handle individual imgur image links imgur_id = url_address.split("/")[-1].split(".")[0] api_url = "https://api.imgur.com/3/image/{}".format(imgur_id) # Load API response (in json) using Client-ID. api_key = self.hallo_obj.get_api_key("imgur") if api_key is None: return None api_dict = Commons.load_url_json(api_url, [["Authorization", api_key]]) # Get title, width, height, size, and view count from API data image_title = str(api_dict["data"]["title"]) image_width = str(api_dict["data"]["width"]) image_height = str(api_dict["data"]["height"]) image_size = int(api_dict["data"]["size"]) image_size_string = self.file_size_to_string(image_size) image_views = api_dict["data"]["views"] # Create output and return output = "Imgur> Title: {} | Size: {}x{} | Filesize: {} | Views: {:,}.".format( image_title, image_width, image_height, image_size_string, image_views) return output
def run(self, event): # Load XML doc = minidom.parse("store/cocktail_list.xml") cocktail_list_elem = doc.getElementsByTagName("cocktail_list")[0] random_cocktail_elem = Commons.get_random_choice( cocktail_list_elem.getElementsByTagName("cocktail"))[0] random_cocktail_name = random_cocktail_elem.getElementsByTagName( "name")[0].firstChild.data random_cocktail_instructions = random_cocktail_elem.getElementsByTagName( "instructions")[0].firstChild.data output_string = "Randomly selected cocktail is: {}. The ingredients are: ".format( random_cocktail_name) ingredient_list = [] for ingredient_elem in random_cocktail_elem.getElementsByTagName( "ingredients"): ingredient_amount = ingredient_elem.getElementsByTagName( "amount")[0].firstChild.data ingredient_name = ingredient_elem.getElementsByTagName( "name")[0].firstChild.data ingredient_list.append(ingredient_amount + ingredient_name) output_string += (", ".join(ingredient_list) + ". The recipe is: " + random_cocktail_instructions) if output_string[-1] != ".": output_string += "." return event.create_response(output_string)
def update_from_european_bank_data(self, repo): """ Updates the value of conversion currency units using The European Bank data. :type repo: ConvertRepo """ # Get currency ConvertType currency_type = repo.get_type_by_name("currency") # Pull xml data from european bank website url = "https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml" xml_string = Commons.load_url_string(url) # Parse data doc = minidom.parseString(xml_string) root = doc.getElementsByTagName("gesmes:Envelope")[0] cube_one_elem = root.getElementsByTagName("Cube")[0] cube_two_elem = cube_one_elem.getElementsByTagName("Cube")[0] for cube_three_elem in cube_two_elem.getElementsByTagName("Cube"): # Get currency code from currency Attribute currency_code = cube_three_elem.getAttributeNode( "currency").nodeValue # Get value from rate attribute and get reciprocal. currency_value = 1 / float( cube_three_elem.getAttributeNode("rate").nodeValue) # Get currency unit currency_unit = currency_type.get_unit_by_name(currency_code) # If unrecognised currency, SKIP if currency_unit is None: continue # Set Value currency_unit.update_value(currency_value)
def update_from_forex_data(self, repo): """ Updates the value of conversion currency units using Forex data. :type repo: ConvertRepo """ # Get currency ConvertType currency_type = repo.get_type_by_name("currency") # Pull xml data from forex website url = "https://rates.fxcm.com/RatesXML3" xml_string = Commons.load_url_string(url) # Parse data doc = minidom.parseString(xml_string) rates_elem = doc.getElementsByTagName("Rates")[0] for rate_elem in rates_elem.getElementsByTagName("Rate"): # Get data from element symbol_data = rate_elem.getElementsByTagName( "Symbol")[0].firstChild.data if not symbol_data.startswith("EUR"): continue bid_data = float( rate_elem.getElementsByTagName("Bid")[0].firstChild.data) ask_data = float( rate_elem.getElementsByTagName("Ask")[0].firstChild.data) # Get currency code and value from data currency_code = symbol_data[3:] currency_value = 1 / (0.5 * (bid_data + ask_data)) # Get currency unit currency_unit = currency_type.get_unit_by_name(currency_code) # If unrecognised code, skip if currency_unit is None: continue # Set Value currency_unit.update_value(currency_value)
def run(self, event): # Check for server name in input line line = event.command_args server_name = Commons.find_parameter("server", line) if server_name is None: server_obj = event.server else: server_obj = event.server.hallo.get_server_by_name(server_name) line = line.replace("server={}".format(server_name), "").strip() if server_obj is None: return event.create_response("Error, invalid server specified.") # Find channel object if line.strip() != "": channel_name = line.split()[0].lower() channel_obj = server_obj.get_channel_by_name(channel_name) else: if event.channel is not None: channel_name = event.channel.name channel_obj = event.channel else: return event.create_response( "Error, I cannot leave a private chat.") # Leave channel, provided hallo is in channel. if not channel_obj.in_channel: return event.create_response("Error, I'm not in that channel.") server_obj.leave_channel(channel_obj) return event.create_response("Left {}.".format(channel_name))
def test_read_file_to_list(): data = Commons.read_file_to_list("hallo/test/inc/test.txt") assert len(data) == 5 assert data[0] == "test1" assert data[1] == "test2" assert data[2] == "test3" assert data[3] == "test4" assert data[4] == "test5"
def run(self, event): line_clean = event.command_args.strip().lower() # Useful object hallo_obj = event.server.hallo # See if a server was specified. server_name = Commons.find_parameter("server", event.command_args) # Get server object. If invalid, use current if server_name is None: server_obj = event.server else: server_obj = hallo_obj.get_server_by_name(server_name) if server_obj is None: return event.create_response( "I don't recognise that server name.") # Remove server name from line and trim line_clean = line_clean.replace("server={}".format(server_name), "").strip() # See if channel was specified with equals syntax channel_name = Commons.find_parameter( "channel", line_clean) or Commons.find_parameter( "chan", line_clean) # If not specified with equals syntax, check if just said. if channel_name is None: channel_name = line_clean if channel_name == "": if event.channel is None: return event.create_response( "I don't recognise that channel name.") channel_name = event.channel.name # If they've specified all channels, display the server list. if channel_name in ["*", "all"]: user_list = server_obj.user_list output_string = "Users on {}: {}.".format( server_obj.name, ", ".join([user.name for user in user_list if user.online]), ) return event.create_response(output_string) # Get channel object channel_obj = server_obj.get_channel_by_name(channel_name) # Get user list user_list = channel_obj.get_user_list() # Output output_string = "Users in {}: {}.".format( channel_name, ", ".join([user.name for user in user_list])) return event.create_response(output_string)
def run(self, event): api_key = event.server.hallo.get_api_key("thecatapi") if api_key is None: return event.create_response("No API key loaded for cat api.") url = "http://thecatapi.com/api/images/get?format=json&api_key={}&type=gif".format( api_key) cat_obj = Commons.load_url_json(url)[0] cat_url = cat_obj["url"] return event.create_response(cat_url)
def run(self, event): output_lines = ["High scores:"] for game_name in self.high_scores: score = self.high_scores[game_name]["score"] player = self.high_scores[game_name]["player"] date = self.high_scores[game_name]["date"] output_lines.append("{}> Score: {}, Player: {}, Date: {}".format( game_name, score, player, Commons.format_unix_time(date))) return event.create_response("\n".join(output_lines))
def run(self, event): responses = ( EightBall.RESPONSES_YES_TOTALLY + EightBall.RESPONSES_YES_PROBABLY + EightBall.RESPONSES_MAYBE + EightBall.RESPONSES_NO ) resp = Commons.get_random_choice(responses)[0] return event.create_response("{}.".format(resp))
def check_response(self, input_line, user_obj, destination_obj): """Checks if this reply message will respond, and which response to use.""" if self.prompt.search(input_line): # Pick a response response = Commons.get_random_choice(self.response_list)[0] response = response.replace("{USER}", user_obj.name) response = response.replace("{CHANNEL}", destination_obj.name) response = response.replace("{SERVER}", user_obj.server.name) return response return None
def run(self, event): choices = re.compile(", (?:or )?| or,? ", re.IGNORECASE).split(event.command_args) numchoices = len(choices) if numchoices == 1: return event.create_response( "Please present me with more than 1 thing to choose from!") else: choice = Commons.get_random_choice(choices)[0] return event.create_response('I choose "{}".'.format(choice))
def run(self, event): """ Hallo will tell you which channels he is in, ops only. Format: "channels" for channels on current server, "channels all" for all channels on all servers. """ line_clean = event.command_args.strip().lower() hallo_obj = event.server.hallo # If they ask for all channels, give them all channels. if line_clean in self.HALLO_NAMES: output_string = "On all servers, I am on these channels: " server_list = hallo_obj.server_list channel_title_list = [] for server_obj in server_list: server_name = server_obj.name in_channel_name_list = self.get_in_channel_names_list( server_obj) channel_title_list += [ server_name + "-" + channel_name for channel_name in in_channel_name_list ] output_string += ", ".join(channel_title_list) output_string += "." return event.create_response(output_string) # If nothing specified, or "server", then output current server channel list if line_clean == "" or line_clean in self.SERVER_NAMES: server_obj = event.server in_channel_name_list = self.get_in_channel_names_list(server_obj) output_string = "On this server, I'm in these channels: " output_string += ", ".join(in_channel_name_list) + "." return event.create_response(output_string) # If a server is specified, get that server's channel list if Commons.find_any_parameter(self.SERVER_NAMES, line_clean): server_name = line_clean.split("=")[1] server_obj = hallo_obj.get_server_by_name(server_name) if server_obj is None: return event.create_response( "I don't recognise that server name.") in_channel_name_list = self.get_in_channel_names_list(server_obj) output_string = "On {} server, I'm in these channels: ".format( server_obj.name) output_string += ", ".join(in_channel_name_list) + "." return event.create_response(output_string) # Check if whatever input they gave is a server server_obj = hallo_obj.get_server_by_name(line_clean) if server_obj is None: # Otherwise, return an error output_string = ( "I don't understand your input, please specify a server, or hallo, " "or no input to get the current server's list") return event.create_response(output_string) in_channel_name_list = self.get_in_channel_names_list(server_obj) output_string = "On {} server, I'm in these channels: ".format( server_obj.name) output_string += ", ".join(in_channel_name_list) + "." return event.create_response(output_string)