#!/usr/bin/env python3 from subprocess import Popen, PIPE import re def cmd(args): proc = Popen(args, stdout=PIPE) while True: line = proc.stdout.readline() if line: try: yield str(line[:-1], 'utf-8', 'ignore') except: pass else: break def irc(chan): global trigger fdir = '/home/zgrep/offtopiabday/irc.freenode.net/' + chan fin = fdir + '/in' fout = fdir + '/out' for line in cmd(['tail', '-n', '0', '-f', fout]): date, time, nick, line = line.split(' ', 3) print(line) m = re.match(r'(?i)(?:happy|hate)bot[:,]\s+([0-9]+)\s+(fractrand?)\s+([0-9]+/[0-9]+(?:,?\s+[0-9]+/[0-9]+)*)$', line) if m: n, f, fs = m.group(1), m.group(2), m.group(3) print('Matched!', n, f, fs) trigger = True r = doit(f, n, fs) trigger = False r = '\u200b' + r print('Result!', r) with open(fin, 'w') as fh: fh.write(r + '\n') from fractions import Fraction from random import choice import signal trigger = False class TimeoutException(Exception): pass def signal_handler(signum, frame): global trigger if trigger: raise TimeoutException("Timed out!") def fractran(n, fracs): vals = [n] signal.alarm(1) try: while True: for frac in fracs: n2 = n*frac if n2.denominator == 1: n = n2.numerator if n in vals: i = vals.index(n) return 'Infinite loop: ..., ' + ', '.join(map(str, vals[i:])) vals.append(n) break else: if len(vals) > 12: beg = ', '.join(map(str, vals[:2])) end = ', '.join(map(str, vals[-10:])) return f'{beg}, ..., {end}' else: return ', '.join(map(str, vals)) except TimeoutException: if len(vals) > 12: beg = ', '.join(map(str, vals[:10])) end = ', '.join(map(str, vals[-2:])) return f'Timed out: {beg}, ..., {end}, ...' else: return 'Timed out: ', + ', '.join(map(str, vals)) def random_unordered_fractran(n, fracs): vals = [n] signal.alarm(1) try: while True: ns = [ n * frac for frac in fracs ] ns = [ m for m in ns if m.denominator == 1 ] if not ns: if len(vals) > 12: beg = ', '.join(map(str, vals[:2])) end = ', '.join(map(str, vals[-10:])) return f'{beg}, ..., {end}' else: return ', '.join(map(str, vals)) n = choice(ns) vals.append(n) except TimeoutException: if len(vals) > 12: beg = ', '.join(map(str, vals[:10])) end = ', '.join(map(str, vals[-2:])) return f'Timed out: {beg}, ..., {end}, ...' else: return 'Timed out: ', + ', '.join(map(str, vals)) def main(): from sys import argv if len(argv) == 2: # IRC mode. irc(argv[1]) elif len(argv) == 4: # cli mode. print(doit(argv[1], argv[2], argv[3])) else: print('Wrong number of arguments.') exit(1) def doit(func, inp, args): n, fracs = None, None try: n = int(inp) except: return 'Input is not an integer?' try: fracs = [Fraction(*map(int, x.split('/', 1))) for x in args.replace(',', '').split()] except: return 'Could not parse fraction list.' if func == 'fractran': func = fractran elif func == 'fractrand': func = random_unordered_fractran else: return f'Invalid function: {func}' signal.signal(signal.SIGALRM, signal_handler) try: return func(n, fracs) except TimeoutException: return 'Timed out.' except Exception as e: return 'Some error occurred: ' + str (e) return 'Something went wrong.' if __name__ == '__main__': main()