<commit_before>#!/usr/bin/env python
"""
regexbot: IRC-based regular expression evaluation tool.
Copyright 2010 - 2012 Michael Farrell <http://micolous.id.au>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

import regex, asyncore, threading, inspect, ctypes, time
from datetime import datetime, timedelta
from configparser import RawConfigParser
from sys import argv, exit
from ircasync import *
from subprocess import Popen, PIPE
from copy import copy
from string import maketrans, translate

DEFAULT_CONFIG = {
	'regexbot': {
		'server': 'localhost',
		'port': DEFAULT_PORT,
		'ipv6': 'no',
		'nick': 'regexbot',
		'channels': '#test',
		'channel_flood_cooldown': 5,
		'global_flood_cooldown': 1,
		'max_messages': 25,
		'max_message_size': 200,
		'version': 'regexbot; https://github.com/micolous/ircbots/',
	}
}

config = RawConfigParser()
config.read_dict(DEFAULT_CONFIG)
try:
	config.readfp(open(argv[1]))
except:
	try:
		config.readfp(open('regexbot.ini'))
	except:
		print "Syntax:"
		print "  %s [config]" % argv[0]
		print ""
		print "If no configuration file is specified or there was an error, it will default to `regexbot.ini'."
		print "If there was a failure reading the configuration, it will display this message."
		exit(1)

# read config
SERVER = config.get('regexbot', 'server')
PORT = config.getint('regexbot', 'port')
IPV6 = config.getboolean('regexbot', 'ipv6')
NICK = str(config.get('regexbot', 'nick'))
CHANNELS = str(config.get('regexbot', 'channels')).split()
VERSION = str(config.get('regexbot', 'version')) + '; %s'
try: VERSION = VERSION % Popen(["git","branch","-v","--contains"], stdout=PIPE).communicate()[0].strip()
except: VERSION = VERSION % 'unknown'
del Popen, PIPE

CHANNEL_FLOOD_COOLDOWN = timedelta(seconds=config.getint('regexbot', 'channel_flood_cooldown'))
GLOBAL_FLOOD_COOLDOWN = timedelta(seconds=config.getint('regexbot', 'global_flood_cooldown'))
MAX_MESSAGES = config.getint('regexbot', 'max_messages')
MAX_MESSAGE_SIZE = config.getint('regexbot', 'max_message_size')
try: NICKSERV_PASS = str(config.get('regexbot', 'nickserv_pass'))
except: NICKSERV_PASS = None

message_buffer = {}
last_message = datetime.now()
last_message_times = {}
flooders = {}
ignore_list = []
channel_list = []

if config.has_section('ignore'):
	for k,v in config.items('ignore'):
		try:
			ignore_list.append(regex.compile(str(v), regex.I))
		except Exception, ex:
			print "Error compiling regular expression in ignore list (%s):" % k
			print "  %s" % v
			print ex
			exit(1)

for channel in CHANNELS:
	c = channel.lower()
	message_buffer[c] = []
	last_message_times[c] = last_message
	channel_list.append(c)

# main code

def flood_control(channel, when):
	"Implements flood controls.  Returns True if the message should be handled, returns False if the floods are in."
	global last_message, last_message_times
	# get delta
	channel_delta = when - last_message_times[channel]
	global_delta = when - last_message

	# update times
	last_message = last_message_times[channel] = when

	# think global
	if global_delta < GLOBAL_FLOOD_COOLDOWN:
		print "Global flood protection hit, %s of %s seconds were waited" % (global_delta.seconds, GLOBAL_FLOOD_COOLDOWN.seconds)
		return False

	# act local
	if channel_delta < CHANNEL_FLOOD_COOLDOWN:
		print "Local %s flood protection hit, %s of %s seconds were waited" % (channel, channel_delta.seconds, CHANNEL_FLOOD_COOLDOWN.seconds)
		return False

	# we're cool.
	return True

def handle_ctcp(event, match):
	channel = event.channel.lower()
	global message_buffer, MAX_MESSAGES, channel_list
	if channel in channel_list:
		if event.args[0] == "ACTION":
			message_buffer[channel].append([event.nick, event.text[:MAX_MESSAGE_SIZE], True])
			message_buffer[channel] = message_buffer[channel][-MAX_MESSAGES:]
			return

def handle_msg(event, match):
	global message_buffer, MAX_MESSAGES, last_message, last_message_times, flooders, channel_list
	msg = event.text
	channel = event.channel.lower()

	if channel not in channel_list:
		# ignore messages not from our channels
		return

	if msg.startswith(NICK):
		lmsg = msg.lower()

		if 'help' in lmsg or 'info' in lmsg or '?' in lmsg:
			# now flood protect!
			if not flood_control(channel, event.when):
				return

			# give information
			event.reply('%s: I am regexbot, the interactive IRC regular expression tool, originally written by micolous.  Source/docs/version: %s' % (event.nick, VERSION))
			return

	str_replace = False
	str_translate = False

	if msg.startswith('s'):
		str_replace = True
	if msg.startswith('y'):
		str_translate = True

	valid_separators = ['@','#','%',':',';','/','\xe1']
	separator = '/'
	if (str_replace or str_translate) and len(msg) > 1 and msg[1] in valid_separators:
		separator = msg[1]
	else:
		str_replace = False
		str_translate = False

	if (str_replace or str_translate) and msg[1] == separator:
		for item in ignore_list:
			if item.search(event.origin) != None:
				# ignore list item hit
				print "Ignoring message from %s because of: %s" % (event.origin, item.pattern)
				return

		if not flood_control(channel, event.when):
			return

		if len(message_buffer[channel]) == 0:
			event.reply('%s: message buffer is empty' % event.nick)
			return

		# parse string to escape separators
		indexes = []
		escaping = False
		for i in xrange(0,len(msg)):
			c = msg[i]
			if c == '\\':
				# toggle between true and false
				escaping = (escaping != True)
			elif c == separator and not escaping:
				# this is a nonescaped separator
				indexes.append(i)
			else:
				# this is an escaped separator
				escaping = False

		# standardise string, so trailing separator doesn't matter
		if len(indexes) == 2:
			indexes.append(len(msg) - 1)

		if len(indexes) != 3:
			event.reply('%s: invalid expression, not the right amount of separators' % event.nick)
			return

		regexp = msg[indexes[0] + 1 : indexes[1]]
		replacement = msg[indexes[1] + 1 : indexes[2]]
		options = msg[indexes[2] + 1 : ]

		# find messages matching the string
		if len(regexp) == 0:
			event.reply('%s: original string is empty' % event.nick)
			return
		if str_replace:
			ignore_case = 'i' in options
			e = None
			try:
				if ignore_case:
					e = regex.compile(regexp, regex.I)
				else:
					e = regex.compile(regexp)
			except Exception, ex:
				event.reply('%s: failure compiling regular expression: %s' % (event.nick, ex))
				return

			# now we have a valid regular expression matcher!
			timeout = time.time() + 10
			for x in range(len(message_buffer[channel])-1, -1, -1):
				if time.time() > timeout: break
				result = [None,None]
				thread = RegexThread(e,replacement,message_buffer[channel][x][1],result)
				thread.start()
				try:
					thread.join(0.1)
					while thread.isAlive():
						thread.raiseExc(TimeoutException)
						time.sleep(0.1)

					if result[0] == None or result[1] == None:
						continue

				except Exception, ex:
					event.reply('%s: failure replacing: %s' % (event.nick, ex))
					return

				new_message = []
				# replace the message in the buffer
				new_message = [message_buffer[channel][x][0], result[1].replace('\n','').replace('\r','')[:MAX_MESSAGE_SIZE], message_buffer[channel][x][2]]
				for c in new_message[1]:
					if ord(c) < 0x20:
						event.reply('%s: hiiii rails' % (event.nick,))
						return

				del message_buffer[channel][x]
				message_buffer[channel].append(new_message)

				# now print the new text
				print new_message
				if new_message[2]:
					# action
					event.reply((' * %s %s' % (new_message[0], new_message[1]))[:MAX_MESSAGE_SIZE])
				else:
					# normal message
					event.reply(('<%s> %s' % (new_message[0], new_message[1]))[:MAX_MESSAGE_SIZE])
				return

		if str_translate:
			if len(regexp) != len(replacement) or len(regexp) < 1:
				event.reply('%s: Translation is different length!'% event.nick)
				return
			# make translation table
			table = maketrans(regexp, replacement)

			for num in xrange(len(message_buffer[channel])-1, -1, -1):
				# make new message, test if changes occur; if not, continue
				result = translate(message_buffer[channel][num][1], table)
				if result == message_buffer[channel][num][1]:
					continue

				# build new message, and insert into buffer
				new_message = [message_buffer[channel][num][0], result.replace('\n','').replace('\r','')[:MAX_MESSAGE_SIZE], message_buffer[channel][num][2]]
				for c in new_message[1]:
					if ord(c) < 0x20:
						event.reply('%s: hiiii rails' % (event.nick,))
						return

				del message_buffer[channel][num]
				message_buffer[channel].append(new_message)

				# print new message and send to server
				print new_message
				if new_message[2]:
					# action
					event.reply((' * %s %s' % (new_message[0], new_message[1]))[:MAX_MESSAGE_SIZE])
				else:
					# normal message
					event.reply(('<%s> %s' % (new_message[0], new_message[1]))[:MAX_MESSAGE_SIZE])
				return

		# no match found
		event.reply('%s: no match found' % event.nick)

	else:
		# add to buffer
		message_buffer[channel].append([event.nick, msg[:MAX_MESSAGE_SIZE], False])

	# trim the buffer
	message_buffer[channel] = message_buffer[channel][-MAX_MESSAGES:]

def handle_welcome(event, match):
	global NICKSERV_PASS
	# Compliance with most network's rules to set this mode on connect.
	event.connection.usermode("+B")
	if NICKSERV_PASS != None:
		event.connection.todo(['NickServ', 'identify', NICKSERV_PASS])

# from http://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python/325528#325528
def _async_raise(tid, exctype):
	'''Raises an exception in the threads with id tid'''
	if not inspect.isclass(exctype):
		raise TypeError("Only types can be raised (not instances)")
	res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
												  ctypes.py_object(exctype))
	if res == 0:
		raise ValueError("invalid thread id")
	elif res != 1:
		# "if it returns a number greater than one, you're in trouble,
		# and you should call it again with exc=NULL to revert the effect"
		ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
		raise SystemError("PyThreadState_SetAsyncExc failed")

class RegexThread(threading.Thread):
	def __init__(self,regex,replace,message,result):
		threading.Thread.__init__(self)
		self.regex = regex
		self.replace = replace
		self.message = message
		self.result = result

	def run(self):
		try:
			self.result[0] = self.regex.search(self.message)
		except MemoryError:
			self.result[0] = None
			return
		if self.result[0] != None:
			self.result[1] = self.regex.sub(self.replace,self.message)

	def raiseExc(self, exctype):
		if not self.isAlive():
			raise threading.ThreadError("the thread is not active")
		_async_raise( self.ident, exctype )

class TimeoutException(Exception):
	pass

irc = IRC(nick=NICK, start_channels=CHANNELS, version=VERSION)
irc.bind(handle_msg, PRIVMSG)
irc.bind(handle_welcome, RPL_WELCOME)
irc.bind(handle_ctcp, CTCP_REQUEST)

irc.make_conn(SERVER, PORT, ipv6=IPV6)
asyncore.loop()

<commit_msg>Regexbot: Exponential timeout for users.<commit_after>#!/usr/bin/env python
"""
regexbot: IRC-based regular expression evaluation tool.
Copyright 2010 - 2012 Michael Farrell <http://micolous.id.au>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

import regex, asyncore, threading, inspect, ctypes, time
from datetime import datetime, timedelta
from configparser import RawConfigParser
from sys import argv, exit
from ircasync import *
from subprocess import Popen, PIPE
from copy import copy
from string import maketrans, translate

DEFAULT_CONFIG = {
	'regexbot': {
		'server': 'localhost',
		'port': DEFAULT_PORT,
		'ipv6': 'no',
		'nick': 'regexbot',
		'channels': '#test',
		'channel_flood_cooldown': 5,
		'global_flood_cooldown': 1,
		'max_messages': 25,
		'max_message_size': 200,
		'version': 'regexbot; https://github.com/micolous/ircbots/',
	}
}

config = RawConfigParser()
config.read_dict(DEFAULT_CONFIG)
try:
	config.readfp(open(argv[1]))
except:
	try:
		config.readfp(open('regexbot.ini'))
	except:
		print "Syntax:"
		print "  %s [config]" % argv[0]
		print ""
		print "If no configuration file is specified or there was an error, it will default to `regexbot.ini'."
		print "If there was a failure reading the configuration, it will display this message."
		exit(1)

# read config
SERVER = config.get('regexbot', 'server')
PORT = config.getint('regexbot', 'port')
IPV6 = config.getboolean('regexbot', 'ipv6')
NICK = str(config.get('regexbot', 'nick'))
CHANNELS = str(config.get('regexbot', 'channels')).split()
VERSION = str(config.get('regexbot', 'version')) + '; %s'
try: VERSION = VERSION % Popen(["git","branch","-v","--contains"], stdout=PIPE).communicate()[0].strip()
except: VERSION = VERSION % 'unknown'
del Popen, PIPE

CHANNEL_FLOOD_COOLDOWN = timedelta(seconds=config.getint('regexbot', 'channel_flood_cooldown'))
GLOBAL_FLOOD_COOLDOWN = timedelta(seconds=config.getint('regexbot', 'global_flood_cooldown'))
MAX_MESSAGES = config.getint('regexbot', 'max_messages')
MAX_MESSAGE_SIZE = config.getint('regexbot', 'max_message_size')
try: NICKSERV_PASS = str(config.get('regexbot', 'nickserv_pass'))
except: NICKSERV_PASS = None

message_buffer = {}
last_message = datetime.now()
last_message_times = {}
flooders = {}
ignore_list = []
channel_list = []

if config.has_section('ignore'):
	for k,v in config.items('ignore'):
		try:
			ignore_list.append(regex.compile(str(v), regex.I))
		except Exception, ex:
			print "Error compiling regular expression in ignore list (%s):" % k
			print "  %s" % v
			print ex
			exit(1)

for channel in CHANNELS:
	c = channel.lower()
	message_buffer[c] = []
	last_message_times[c] = last_message
	channel_list.append(c)

# main code

def flood_control(channel, when):
	"Implements flood controls.  Returns True if the message should be handled, returns False if the floods are in."
	global last_message, last_message_times
	# get delta
	channel_delta = when - last_message_times[channel]
	global_delta = when - last_message

	# update times
	last_message = last_message_times[channel] = when

	# think global
	if global_delta < GLOBAL_FLOOD_COOLDOWN:
		print "Global flood protection hit, %s of %s seconds were waited" % (global_delta.seconds, GLOBAL_FLOOD_COOLDOWN.seconds)
		return False

	# act local
	if channel_delta < CHANNEL_FLOOD_COOLDOWN:
		print "Local %s flood protection hit, %s of %s seconds were waited" % (channel, channel_delta.seconds, CHANNEL_FLOOD_COOLDOWN.seconds)
		return False

	# we're cool.
	return True

def handle_ctcp(event, match):
	channel = event.channel.lower()
	global message_buffer, MAX_MESSAGES, channel_list
	if channel in channel_list:
		if event.args[0] == "ACTION":
			message_buffer[channel].append([event.nick, event.text[:MAX_MESSAGE_SIZE], True])
			message_buffer[channel] = message_buffer[channel][-MAX_MESSAGES:]
			return

def handle_msg(event, match):
	global message_buffer, MAX_MESSAGES, last_message, last_message_times, flooders, channel_list
	msg = event.text
	channel = event.channel.lower()

	if channel not in channel_list:
		# ignore messages not from our channels
		return

	if msg.startswith(NICK):
		lmsg = msg.lower()

		if 'help' in lmsg or 'info' in lmsg or '?' in lmsg:
			# now flood protect!
			if not flood_control(channel, event.when):
				return

			# give information
			event.reply('%s: I am regexbot, the interactive IRC regular expression tool, originally written by micolous.  Source/docs/version: %s' % (event.nick, VERSION))
			return

	str_replace = False
	str_translate = False

	if msg.startswith('s'):
		str_replace = True
	if msg.startswith('y'):
		str_translate = True

	valid_separators = ['@','#','%',':',';','/','\xe1']
	separator = '/'
	if (str_replace or str_translate) and len(msg) > 1 and msg[1] in valid_separators:
		separator = msg[1]
	else:
		str_replace = False
		str_translate = False

	if (str_replace or str_translate) and msg[1] == separator:
		for item in ignore_list:
			if item.search(event.origin) != None:
				# ignore list item hit
				print "Ignoring message from %s because of: %s" % (event.origin, item.pattern)
				return

		if not flood_control(channel, event.when):
			return

		# remove all old entries
		while not user_timeout.empty() and user_timeout.queue[0][0] < datetime.now():
			user_timeout.get()

		for item in user_timeout.queue:
			user = item['user']
			timeout = item['timeout']
			user_timeout.queue.remove(item)

			if user != event.nick:
				continue

			timeout = timeout + 1
			# make the maximum timeout ~30 minutes
			if timeout > 11:
				timeout = 11
			time = datetime.now() + timedelta(seconds=2**timeout)

			new_item = (time, {})
			new_item[1]['uesr'] = user
			new_item[1]['timeout'] = timeout
			user_timeout.put(new_item)

			print "Ignoring message from %s because of a timeout" % (event.nick)

			return

		if len(message_buffer[channel]) == 0:
			event.reply('%s: message buffer is empty' % event.nick)
			return

		# parse string to escape separators
		indexes = []
		escaping = False
		for i in xrange(0,len(msg)):
			c = msg[i]
			if c == '\\':
				# toggle between true and false
				escaping = (escaping != True)
			elif c == separator and not escaping:
				# this is a nonescaped separator
				indexes.append(i)
			else:
				# this is an escaped separator
				escaping = False

		# standardise string, so trailing separator doesn't matter
		if len(indexes) == 2:
			indexes.append(len(msg) - 1)

		if len(indexes) != 3:
			event.reply('%s: invalid expression, not the right amount of separators' % event.nick)
			return

		regexp = msg[indexes[0] + 1 : indexes[1]]
		replacement = msg[indexes[1] + 1 : indexes[2]]
		options = msg[indexes[2] + 1 : ]

		# find messages matching the string
		if len(regexp) == 0:
			event.reply('%s: original string is empty' % event.nick)
			return
		if str_replace:
			ignore_case = 'i' in options
			e = None
			try:
				if ignore_case:
					e = regex.compile(regexp, regex.I)
				else:
					e = regex.compile(regexp)
			except Exception, ex:
				event.reply('%s: failure compiling regular expression: %s' % (event.nick, ex))
				return

			# now we have a valid regular expression matcher!
			timeout = time.time() + 10
			for x in range(len(message_buffer[channel])-1, -1, -1):
				if time.time() > timeout: break
				result = [None,None]
				thread = RegexThread(e,replacement,message_buffer[channel][x][1],result)
				thread.start()
				try:
					thread.join(0.1)
					while thread.isAlive():
						thread.raiseExc(TimeoutException)
						time.sleep(0.1)

					if result[0] == None or result[1] == None:
						continue

				except Exception, ex:
					event.reply('%s: failure replacing: %s' % (event.nick, ex))
					return

				new_message = []
				# replace the message in the buffer
				new_message = [message_buffer[channel][x][0], result[1].replace('\n','').replace('\r','')[:MAX_MESSAGE_SIZE], message_buffer[channel][x][2]]
				for c in new_message[1]:
					if ord(c) < 0x20:
						event.reply('%s: hiiii rails' % (event.nick,))
						return

				del message_buffer[channel][x]
				message_buffer[channel].append(new_message)

				# now print the new text
				print new_message
				if new_message[2]:
					# action
					event.reply((' * %s %s' % (new_message[0], new_message[1]))[:MAX_MESSAGE_SIZE])
				else:
					# normal message
					event.reply(('<%s> %s' % (new_message[0], new_message[1]))[:MAX_MESSAGE_SIZE])
				return

		if str_translate:
			if len(regexp) != len(replacement) or len(regexp) < 1:
				event.reply('%s: Translation is different length!'% event.nick)
				return
			# make translation table
			table = maketrans(regexp, replacement)

			for num in xrange(len(message_buffer[channel])-1, -1, -1):
				# make new message, test if changes occur; if not, continue
				result = translate(message_buffer[channel][num][1], table)
				if result == message_buffer[channel][num][1]:
					continue

				# build new message, and insert into buffer
				new_message = [message_buffer[channel][num][0], result.replace('\n','').replace('\r','')[:MAX_MESSAGE_SIZE], message_buffer[channel][num][2]]
				for c in new_message[1]:
					if ord(c) < 0x20:
						event.reply('%s: hiiii rails' % (event.nick,))
						return

				del message_buffer[channel][num]
				message_buffer[channel].append(new_message)

				# print new message and send to server
				print new_message
				if new_message[2]:
					# action
					event.reply((' * %s %s' % (new_message[0], new_message[1]))[:MAX_MESSAGE_SIZE])
				else:
					# normal message
					event.reply(('<%s> %s' % (new_message[0], new_message[1]))[:MAX_MESSAGE_SIZE])
				return

		# no match found
		event.reply('%s: no match found' % event.nick)

	else:
		# add to buffer
		message_buffer[channel].append([event.nick, msg[:MAX_MESSAGE_SIZE], False])

	# trim the buffer
	message_buffer[channel] = message_buffer[channel][-MAX_MESSAGES:]

def handle_welcome(event, match):
	global NICKSERV_PASS
	# Compliance with most network's rules to set this mode on connect.
	event.connection.usermode("+B")
	if NICKSERV_PASS != None:
		event.connection.todo(['NickServ', 'identify', NICKSERV_PASS])

# from http://stackoverflow.com/questions/323972/is-there-any-way-to-kill-a-thread-in-python/325528#325528
def _async_raise(tid, exctype):
	'''Raises an exception in the threads with id tid'''
	if not inspect.isclass(exctype):
		raise TypeError("Only types can be raised (not instances)")
	res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
												  ctypes.py_object(exctype))
	if res == 0:
		raise ValueError("invalid thread id")
	elif res != 1:
		# "if it returns a number greater than one, you're in trouble,
		# and you should call it again with exc=NULL to revert the effect"
		ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
		raise SystemError("PyThreadState_SetAsyncExc failed")

class RegexThread(threading.Thread):
	def __init__(self,regex,replace,message,result):
		threading.Thread.__init__(self)
		self.regex = regex
		self.replace = replace
		self.message = message
		self.result = result

	def run(self):
		try:
			self.result[0] = self.regex.search(self.message)
		except MemoryError:
			self.result[0] = None
			return
		if self.result[0] != None:
			self.result[1] = self.regex.sub(self.replace,self.message)

	def raiseExc(self, exctype):
		if not self.isAlive():
			raise threading.ThreadError("the thread is not active")
		_async_raise( self.ident, exctype )

class TimeoutException(Exception):
	pass

irc = IRC(nick=NICK, start_channels=CHANNELS, version=VERSION)
irc.bind(handle_msg, PRIVMSG)
irc.bind(handle_welcome, RPL_WELCOME)
irc.bind(handle_ctcp, CTCP_REQUEST)

irc.make_conn(SERVER, PORT, ipv6=IPV6)
asyncore.loop()

<|endoftext|>


<commit_before>import re
import time
import random
import collections
import sys
import parsedatetime.parsedatetime as pdt
from sleekxmpp.xmlstream import scheduler
from datetime import datetime,timedelta
from pytz import timezone
from dateutil import tz
import sqlite3

class RemindMe():
    def __init__(self, mucbot):
        self.mucbot = mucbot

        self.mucbot.scheduler.add("check_reminders", 1, self.check_reminders, repeat=True)

    def check_reminders(self):
        nowUtc = time.gmtime()
        nowDb = int(time.mktime(nowUtc))

        db = sqlite3.connect('db.sq3')
        res = db.execute('SELECT sender, nick, msg FROM reminders WHERE time = ?', [nowDb])
        while True:
            row = res.fetchone()
            if (row):
                if row[2] == '':
                    body = "%s: This is a reminder!" % row[1]
                else:
                    body = "%s: Remember to %s!" % (row[1], row[2])

                self.mucbot.send_message(mto=row[0],
                    mbody=body,
                    mtype='groupchat')

            else:
                break

        db.execute('DELETE FROM reminders WHERE time <= ?', [nowDb]);
        db.commit();
        db.close()

    def handle(self, msg):
        if msg['body'][:7] == "!remind":
            req = msg['body'][8:]
            req = req.split("\n")[0]

            # get user
            reqUser = req.split(" ")[0]
            req = req[len(reqUser)+1:]

            if reqUser.lower() == 'me':
                reqUser = msg['mucnick']

            # get message
            reqMsg = ""
            idx = 0
            msgSearch = re.search('(["].{0,9999}["])', req)
            if msgSearch:
               reqMsg = msgSearch.group()[1:-1]
               idx = msgSearch.start(0)

            # get time
	    reqTime = req
            if idx > 0:
                reqTime = req[:idx-1]

            if reqUser == '' or reqTime == '':
                body = "Need user and time, see !help for usage"
            else:
                try:
                    body = ""
                    # convert human time to python time
                    cal = pdt.Calendar()
                    if cal.parse(reqTime)[1] == 0:
                        body = "For being a dick, the reminder was set for 15 minutes!"
                        reqMsg = "not be a dick anymore"
                        reqUser = msg['mucnick']
                        holdTime = cal.parse("15 minutes", datetime.now(timezone('UTC')))
                    else:
                        holdTime = cal.parse(reqTime, datetime.now(timezone('UTC')))

                    # utc to db and local (for reply)
                    dbTime = int(time.mktime(holdTime[0]))
                    utcTime = datetime.fromtimestamp(dbTime)
                    utcTime = utcTime.replace(tzinfo = tz.tzutc())
                    localTime = utcTime.astimezone(tz.tzlocal())

                    nowTime = datetime.now(tz.tzlocal())
                    if localTime > nowTime:
                        db = sqlite3.connect('db.sq3')
                        db.execute('INSERT INTO reminders (sender, nick, time, msg) VALUES (?, ?, ?, ?)', (msg['from'].bare, reqUser, dbTime, reqMsg) )
                        db.commit()
                        db.close()

                        if body == "":
                            body = "Ok, reminder set for %s :D" % localTime.strftime('%Y-%m-%d %H:%M:%S')
                    elif localTime == nowTime:
                        body = "You can probably remember that long, %s..." % msg['mucnick']
                    else:
                        body = "Stop living in the past, %s!" % msg['mucnick']
                except:
                    body = "Time out of range"

            self.mucbot.send_message(mto=msg['from'].bare,
                mbody=body,
                mtype='groupchat')

    def help(self):
        ret = ""
        ret = ret + "remind - add a reminder, format: '!remind <user> <time> \"[message]\"'\n"
        ret = ret + "        user - nick or 'me'\n"
        ret = ret + "        time - human-readable time, for example '10 minutes', '1 hour 30 minutes'\n"
        ret = ret + "        message (optional) - what to say when the time comes"
        return [ret]

class SchedulerMock():
    def add(self, name, seconds, callback, repeat=False):
        return

class MUCBotMock():
    def __init__(self):
        self.scheduler = SchedulerMock()

    def send_message(self, mto, mbody, mtype):
        print "MUCBotMock:", mto, mbody, mtype

class FromMock():
    def __init__(self, _from):
        self.bare = _from

def do_test():
    x = RemindMe(MUCBotMock())
    msg = {"from" : FromMock("channel@example.com"), "mucnick" : "kallsse", "body" : "!remind me 1 hour"}
    x.handle(msg)

    msg = {"from" : FromMock("channel@example.com"), "mucnick" : "kallsse", "body" : "!remind frazz 10 seconds \"do a thing\""}
    x.handle(msg)

if __name__ == "__main__":
    do_test()
<commit_msg>Remindme fixes<commit_after>import re
import time
import random
import collections
import sys
import parsedatetime.parsedatetime as pdt
from sleekxmpp.xmlstream import scheduler
from datetime import datetime,timedelta
from pytz import timezone
from dateutil import tz
import sqlite3

class RemindMe():
    def __init__(self, mucbot):
        self.mucbot = mucbot

        self.mucbot.scheduler.add("check_reminders", 1, self.check_reminders, repeat=True)

    def check_reminders(self):
        nowUtc = time.gmtime()
        nowDb = int(time.mktime(nowUtc))

        db = sqlite3.connect('db.sq3')
        res = db.execute('SELECT sender, nick, msg FROM reminders WHERE time = ?', [nowDb])
        while True:
            row = res.fetchone()
            if (row):
                if row[2] == '':
                    body = "%s: This is a reminder!" % row[1]
                else:
                    body = "%s: Remember to %s!" % (row[1], row[2])

                self.mucbot.send_message(mto=row[0],
                    mbody=body,
                    mtype='groupchat')

            else:
                break

        db.execute('DELETE FROM reminders WHERE time <= ?', [nowDb]);
        db.commit();
        db.close()

    def handle(self, msg):
        if msg['body'][:7] == "!remind":
            req = msg['body'][8:]
            req = req.split("\n")[0]

            # get user
            reqUser = req.split(" ")[0]
            req = req[len(reqUser)+1:]

            if reqUser.lower() == 'me':
                reqUser = msg['mucnick']

            # get message
            reqMsg = ""
            idx = 0
            msgSearch = re.search('(["].{0,9999}["])', req)
            if msgSearch:
               reqMsg = msgSearch.group()[1:-1]
               idx = msgSearch.start(0)

            # get time
	    reqTime = req
            if idx > 0:
                reqTime = req[:idx-1]

            if reqUser == '' or reqTime == '':
                body = "Need user and time, see !help for usage"
            else:
                body = ""
                # convert human time to python time
                try:
                    cal = pdt.Calendar()
                    if cal.parse(reqTime)[1] == 0:
                        body = "For being a dick, the reminder was set for 15 minutes!"
                        reqMsg = "not be a dick anymore"
                        reqUser = msg['mucnick']
                        holdTime = cal.parse("15 minutes", datetime.now(tz.tzlocal()))
                    else:
                        holdTime = cal.parse(reqTime, datetime.now(tz.tzlocal()))
                except:
                    body = "Time out of range"
                else:
                    # local to utc (for db)
                    localTime = datetime.fromtimestamp(int(time.mktime(holdTime[0])))
                    localTime = localTime.replace(tzinfo = tz.tzlocal())
                    nowTime = datetime.now(tz.tzlocal())

                    if localTime > nowTime:
                        utcTime = localTime.astimezone(tz.tzutc())
                        dbTime = int(time.mktime(utcTime.timetuple()))
                        db = sqlite3.connect('db.sq3')
                        db.execute('INSERT INTO reminders (sender, nick, time, msg) VALUES (?, ?, ?, ?)', (msg['from'].bare, reqUser, dbTime, reqMsg) )
                        db.commit()
                        db.close()

                        if body == "":
                            body = "Ok, reminder set for %s :D" % localTime.strftime('%Y-%m-%d %H:%M:%S')
                    elif localTime == nowTime:
                        body = "You can probably remember that long, %s..." % msg['mucnick']
                    else:
                        body = "Stop living in the past, %s!" % msg['mucnick']

            self.mucbot.send_message(mto=msg['from'].bare,
                mbody=body,
                mtype='groupchat')

    def help(self):
        ret = ""
        ret = ret + "remind - add a reminder, format: '!remind <user> <time> \"[message]\"'\n"
        ret = ret + "        user - nick or 'me'\n"
        ret = ret + "        time - human-readable time, for example '10 minutes', '1 hour 30 minutes'\n"
        ret = ret + "        message (optional) - what to say when the time comes"
        return [ret]

class SchedulerMock():
    def add(self, name, seconds, callback, repeat=False):
        return

class MUCBotMock():
    def __init__(self):
        self.scheduler = SchedulerMock()

    def send_message(self, mto, mbody, mtype):
        print "MUCBotMock:", mto, mbody, mtype

class FromMock():
    def __init__(self, _from):
        self.bare = _from

def do_test():
    x = RemindMe(MUCBotMock())
    msg = {"from" : FromMock("channel@example.com"), "mucnick" : "kallsse", "body" : "!remind me 1 hour"}
    x.handle(msg)

    msg = {"from" : FromMock("channel@example.com"), "mucnick" : "kallsse", "body" : "!remind frazz 10 seconds \"do a thing\""}
    x.handle(msg)

if __name__ == "__main__":
    do_test()
<|endoftext|>


<commit_before>from C4CApplication.page_objects.MyCare4CarePage import MyCare4CarePage
from selenium.webdriver.common.by import By

class ListMessagesPage(MyCare4CarePage):<commit_msg>To pull<commit_after>from C4CApplication.page_objects.MyCare4CarePage import MyCare4CarePage
from selenium.webdriver.common.by import By

class ListMessagesPage(MyCare4CarePage):

    def __init__(self, driver):
        super().__init__(driver)
        self.switch_button = None
        self.new_message_button = None
        self.read_more_buttons = None<|endoftext|>


<commit_before>import os

import tornado
import tornado.web
import tornado.wsgi
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
import tornado_xstatic as tornado_xstatic
from terminado import TermSocket

from app.api.models.LXCContainer import LXCContainer
from app.lib.termmanager import NamedTermManager
from app.api.utils import mappings

TEMPLATE_DIR = os.path.dirname(__file__).replace('/api/controllers','/ui/templates/')
STATIC_DIR = os.path.dirname(__file__).replace('/api/controllers','/ui/static/')

from app.api.utils.authentication import jwt_decode_handler

def findShellTypeOfContainer(container):
    containerImage = container.info()['config']['image.os'].lower()
    for image in mappings.OS_SHELL_MAPPINGS:
        if image in containerImage:
            return mappings.OS_SHELL_MAPPINGS[image]
    return 'bash'

def checkAuthentication(token):
    try:
        return jwt_decode_handler(token)
    except Exception as e:
        return False

class TerminalPageHandler(tornado.web.RequestHandler):
    """Render the /ttyX pages"""
    def get(self, term_name, token):
        if not checkAuthentication(token):
            raise tornado.web.HTTPError(403)
        return self.render("termpage.html",static=self.static_url,
                           xstatic=self.application.settings['xstatic_url'],
                           ws_url_path="/_websocket/"+term_name)

class NewTerminalHandler(tornado.web.RequestHandler):
    """Redirect to an unused terminal name"""
    def get(self, name='new', token=None):
        if not checkAuthentication(token):
            raise tornado.web.HTTPError(403)
        shellType = findShellTypeOfContainer(LXCContainer({'name': name}))
        shell = ['bash', '-c', 'lxc exec {} -- /bin/{}'.format(name, shellType)]
        name, terminal = self.application.settings['term_manager'].new_named_terminal(shell_command=shell)
        self.redirect("/terminal/open/" + name+'/'+token, permanent=False)

def terminal(app, port, debug=False):
    term_manager = NamedTermManager(shell_command=None, max_terminals=100)
    wrapped_app = WSGIContainer(app)
    handlers = [
                (r"/_websocket/(\w+)", TermSocket,
                     {'term_manager': term_manager}),
                (r"/terminal/new/([a-zA-Z\-0-9\.]+)/(.*)/?", NewTerminalHandler),
                (r"/terminal/open/([a-zA-Z\-0-9\.]+)/(.*)/?", TerminalPageHandler),
                (r"/xstatic/(.*)", tornado_xstatic.XStaticFileHandler),
                ("/(.*)", tornado.web.FallbackHandler, {'fallback': wrapped_app}),
               ]

    tornado_app = tornado.web.Application(handlers, static_path=STATIC_DIR,
                              template_path=TEMPLATE_DIR,
                              xstatic_url=tornado_xstatic.url_maker('/xstatic/'),
                              term_manager=term_manager,
                              debug=debug)
    http_server = HTTPServer(tornado_app)
    http_server.listen(port, '0.0.0.0')
    IOLoop.instance().start()<commit_msg>Fix: KeyError: 'image.os' when container hasn't 'image.os'<commit_after>import os

import tornado
import tornado.web
import tornado.wsgi
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
import tornado_xstatic as tornado_xstatic
from terminado import TermSocket

from app.api.models.LXCContainer import LXCContainer
from app.lib.termmanager import NamedTermManager
from app.api.utils import mappings

TEMPLATE_DIR = os.path.dirname(__file__).replace('/api/controllers','/ui/templates/')
STATIC_DIR = os.path.dirname(__file__).replace('/api/controllers','/ui/static/')

from app.api.utils.authentication import jwt_decode_handler

def findShellTypeOfContainer(container):
    containerImage = container.info()['config'].get('image.os')
    if containerImage:
        for image in mappings.OS_SHELL_MAPPINGS:
            if image in containerImage.lower():
                return mappings.OS_SHELL_MAPPINGS[image]
    return 'bash'

def checkAuthentication(token):
    try:
        return jwt_decode_handler(token)
    except Exception as e:
        return False

class TerminalPageHandler(tornado.web.RequestHandler):
    """Render the /ttyX pages"""
    def get(self, term_name, token):
        if not checkAuthentication(token):
            raise tornado.web.HTTPError(403)
        return self.render("termpage.html",static=self.static_url,
                           xstatic=self.application.settings['xstatic_url'],
                           ws_url_path="/_websocket/"+term_name)

class NewTerminalHandler(tornado.web.RequestHandler):
    """Redirect to an unused terminal name"""
    def get(self, name='new', token=None):
        if not checkAuthentication(token):
            raise tornado.web.HTTPError(403)
        shellType = findShellTypeOfContainer(LXCContainer({'name': name}))
        shell = ['bash', '-c', 'lxc exec {} -- /bin/{}'.format(name, shellType)]
        name, terminal = self.application.settings['term_manager'].new_named_terminal(shell_command=shell)
        self.redirect("/terminal/open/" + name+'/'+token, permanent=False)

def terminal(app, port, debug=False):
    term_manager = NamedTermManager(shell_command=None, max_terminals=100)
    wrapped_app = WSGIContainer(app)
    handlers = [
                (r"/_websocket/(\w+)", TermSocket,
                     {'term_manager': term_manager}),
                (r"/terminal/new/([a-zA-Z\-0-9\.]+)/(.*)/?", NewTerminalHandler),
                (r"/terminal/open/([a-zA-Z\-0-9\.]+)/(.*)/?", TerminalPageHandler),
                (r"/xstatic/(.*)", tornado_xstatic.XStaticFileHandler),
                ("/(.*)", tornado.web.FallbackHandler, {'fallback': wrapped_app}),
               ]

    tornado_app = tornado.web.Application(handlers, static_path=STATIC_DIR,
                              template_path=TEMPLATE_DIR,
                              xstatic_url=tornado_xstatic.url_maker('/xstatic/'),
                              term_manager=term_manager,
                              debug=debug)
    http_server = HTTPServer(tornado_app)
    http_server.listen(port, '0.0.0.0')
    IOLoop.instance().start()<|endoftext|>


<commit_before>"""
The default unit symbol lookup table.

"""

#-----------------------------------------------------------------------------
# Copyright (c) 2013, yt Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------

from yt.units import dimensions
from yt.utilities.physical_ratios import \
    cm_per_pc, cm_per_ly, cm_per_au, cm_per_rsun, \
    mass_sun_grams, sec_per_year, sec_per_day, sec_per_hr, \
    sec_per_min, temp_sun_kelvin, luminosity_sun_ergs_per_sec, \
    metallicity_sun, erg_per_eV, amu_grams, mass_electron_grams, \
    cm_per_ang, jansky_cgs
import numpy as np

# Lookup a unit symbol with the symbol string, and provide a tuple with the
# conversion factor to cgs and dimensionality.

default_unit_symbol_lut = {
    # base
    "g":  (1.0, dimensions.mass),
    #"cm": (1.0, length, r"\rm{cm}"),  # duplicate with meter below...
    "s":  (1.0, dimensions.time),
    "K":  (1.0, dimensions.temperature),
    "radian": (1.0, dimensions.angle),
    "Zfrac": (1.0, dimensions.metallicity),

    # "code" units, default to CGS conversion.
    # These default values are overridden in the code frontends
    "code_length" : (1.0, dimensions.length),
    "unitary"   : (1.0, dimensions.length),
    "code_mass" : (1.0, dimensions.mass),
    "code_time" : (1.0, dimensions.time),
    "code_velocity" : (1.0, dimensions.velocity),
    "code_magnetic" : (1.0, dimensions.magnetic_field),
    "code_temperature" : (1.0, dimensions.temperature),
    "code_metallicity" : (1.0, dimensions.dimensionless),

    # other cgs
    "dyne": (1.0, dimensions.force),
    "erg":  (1.0, dimensions.energy),
    "esu":  (1.0, dimensions.charge),
    "gauss": (1.0, dimensions.magnetic_field),

    # some SI
    "m": (1.0e2, dimensions.length),
    "J": (1.0e7, dimensions.energy),
    "W": (1.0e7, dimensions.power),
    "Hz": (1.0, dimensions.rate),

    # Imperial units
    "ft": (30.48, dimensions.length),
    "mile": (160934, dimensions.length),

    # dimensionless stuff
    "h": (1.0, dimensions.dimensionless), # needs to be added for rho_crit_now
    "dimensionless": (1.0, dimensions.dimensionless),

    # times
    "min": (sec_per_min, dimensions.time),
    "hr":  (sec_per_hr, dimensions.time),
    "day": (sec_per_day, dimensions.time),
    "yr":  (sec_per_year, dimensions.time),

    # Solar units
    "Msun": ( mass_sun_grams, dimensions.mass),
    "msun": ( mass_sun_grams, dimensions.mass),
    "Rsun": ( cm_per_rsun, dimensions.length),
    "rsun": ( cm_per_rsun, dimensions.length),
    "Lsun": ( luminosity_sun_ergs_per_sec, dimensions.power),
    "Tsun": ( temp_sun_kelvin, dimensions.temperature),
    "Zsun": (metallicity_sun, dimensions.dimensionless),

    # astro distances
    "AU": (cm_per_au, dimensions.length),
    "au": (cm_per_au, dimensions.length),
    "ly": (cm_per_ly, dimensions.length),
    "pc": (cm_per_pc, dimensions.length),

    # angles
    "degree": (np.pi/180., dimensions.angle), # degrees
    "arcmin": (np.pi/10800., dimensions.angle), # arcminutes
    "arcsec": (np.pi/648000., dimensions.angle), # arcseconds
    "mas": (np.pi/648000000., dimensions.angle), # millarcseconds
    "steradian": (1.0, dimensions.solid_angle),

    # misc
    "eV": (erg_per_eV, dimensions.energy),
    "amu": (amu_grams, dimensions.mass),
    "me": (mass_electron_grams, dimensions.mass),
    "angstrom": (cm_per_ang, dimensions.length),
    "Jy": (jansky_cgs, dimensions.specific_flux)

}

# Add LaTeX representations for units with trivial representations.
latex_symbol_lut = {
    "unitary" : "",
    "code_length" : "\\rm{code}\/\\rm{length}",
    "code_time" : "\\rm{code}\/\\rm{time}",
    "code_mass" : "\\rm{code}\/\\rm{mass}",
    "code_temperature" : "\\rm{code}\/\\rm{temperature}",
    "code_metallicity" : "\\rm{code}\/\\rm{metallicity}",
    "code_velocity" : "\\rm{code}\/\\rm{velocity}",
    "Msun" : "\\rm{M}_\\odot",
    "msun" : "\\rm{M}_\\odot",
    "Rsun" : "\\rm{R}_\\odot",
    "rsun" : "\\rm{R}_\\odot",
    "Lsun" : "\\rm{L}_\\odot",
    "Tsun" : "\\rm{T}_\\odot",
    "Zsun" : "\\rm{Z}_\\odot",
}
for key in default_unit_symbol_lut:
    if key not in latex_symbol_lut:
        latex_symbol_lut[key] = "\\rm{" + key + "}"

# This dictionary formatting from magnitude package, credit to Juan Reyero.
unit_prefixes = {
    'Y': 1e24,   # yotta
    'Z': 1e21,   # zetta
    'E': 1e18,   # exa
    'P': 1e15,   # peta
    'T': 1e12,   # tera
    'G': 1e9,    # giga
    'M': 1e6,    # mega
    'k': 1e3,    # kilo
    'd': 1e1,    # deci
    'c': 1e-2,   # centi
    'm': 1e-3,   # mili
    'u': 1e-6,   # micro
    'n': 1e-9,   # nano
    'p': 1e-12,  # pico
    'f': 1e-15,  # femto
    'a': 1e-18,  # atto
    'z': 1e-21,  # zepto
    'y': 1e-24,  # yocto
}

prefixable_units = (
    "m",
    "pc",
    "mcm",
    "pccm",
    "g",
    "eV",
    "s",
    "yr",
    "K",
    "dyne",
    "erg",
    "esu",
    "J",
    "Hz",
    "W",
    "gauss",
    "Jy",
)

cgs_base_units = {
    dimensions.mass:'g',
    dimensions.length:'cm',
    dimensions.time:'s',
    dimensions.temperature:'K',
    dimensions.angle:'radian',
}
<commit_msg>Reverting this change<commit_after>"""
The default unit symbol lookup table.

"""

#-----------------------------------------------------------------------------
# Copyright (c) 2013, yt Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------

from yt.units import dimensions
from yt.utilities.physical_ratios import \
    cm_per_pc, cm_per_ly, cm_per_au, cm_per_rsun, \
    mass_sun_grams, sec_per_year, sec_per_day, sec_per_hr, \
    sec_per_min, temp_sun_kelvin, luminosity_sun_ergs_per_sec, \
    metallicity_sun, erg_per_eV, amu_grams, mass_electron_grams, \
    cm_per_ang, jansky_cgs
import numpy as np

# Lookup a unit symbol with the symbol string, and provide a tuple with the
# conversion factor to cgs and dimensionality.

default_unit_symbol_lut = {
    # base
    "g":  (1.0, dimensions.mass),
    #"cm": (1.0, length, r"\rm{cm}"),  # duplicate with meter below...
    "s":  (1.0, dimensions.time),
    "K":  (1.0, dimensions.temperature),
    "radian": (1.0, dimensions.angle),

    # "code" units, default to CGS conversion.
    # These default values are overridden in the code frontends
    "code_length" : (1.0, dimensions.length),
    "unitary"   : (1.0, dimensions.length),
    "code_mass" : (1.0, dimensions.mass),
    "code_time" : (1.0, dimensions.time),
    "code_velocity" : (1.0, dimensions.velocity),
    "code_magnetic" : (1.0, dimensions.magnetic_field),
    "code_temperature" : (1.0, dimensions.temperature),
    "code_metallicity" : (1.0, dimensions.dimensionless),

    # other cgs
    "dyne": (1.0, dimensions.force),
    "erg":  (1.0, dimensions.energy),
    "esu":  (1.0, dimensions.charge),
    "gauss": (1.0, dimensions.magnetic_field),

    # some SI
    "m": (1.0e2, dimensions.length),
    "J": (1.0e7, dimensions.energy),
    "W": (1.0e7, dimensions.power),
    "Hz": (1.0, dimensions.rate),

    # Imperial units
    "ft": (30.48, dimensions.length),
    "mile": (160934, dimensions.length),

    # dimensionless stuff
    "h": (1.0, dimensions.dimensionless), # needs to be added for rho_crit_now
    "dimensionless": (1.0, dimensions.dimensionless),

    # times
    "min": (sec_per_min, dimensions.time),
    "hr":  (sec_per_hr, dimensions.time),
    "day": (sec_per_day, dimensions.time),
    "yr":  (sec_per_year, dimensions.time),

    # Solar units
    "Msun": ( mass_sun_grams, dimensions.mass),
    "msun": ( mass_sun_grams, dimensions.mass),
    "Rsun": ( cm_per_rsun, dimensions.length),
    "rsun": ( cm_per_rsun, dimensions.length),
    "Lsun": ( luminosity_sun_ergs_per_sec, dimensions.power),
    "Tsun": ( temp_sun_kelvin, dimensions.temperature),
    "Zsun": (metallicity_sun, dimensions.dimensionless),

    # astro distances
    "AU": (cm_per_au, dimensions.length),
    "au": (cm_per_au, dimensions.length),
    "ly": (cm_per_ly, dimensions.length),
    "pc": (cm_per_pc, dimensions.length),

    # angles
    "degree": (np.pi/180., dimensions.angle), # degrees
    "arcmin": (np.pi/10800., dimensions.angle), # arcminutes
    "arcsec": (np.pi/648000., dimensions.angle), # arcseconds
    "mas": (np.pi/648000000., dimensions.angle), # millarcseconds
    "steradian": (1.0, dimensions.solid_angle),

    # misc
    "eV": (erg_per_eV, dimensions.energy),
    "amu": (amu_grams, dimensions.mass),
    "me": (mass_electron_grams, dimensions.mass),
    "angstrom": (cm_per_ang, dimensions.length),
    "Jy": (jansky_cgs, dimensions.specific_flux)

}

# Add LaTeX representations for units with trivial representations.
latex_symbol_lut = {
    "unitary" : "",
    "code_length" : "\\rm{code}\/\\rm{length}",
    "code_time" : "\\rm{code}\/\\rm{time}",
    "code_mass" : "\\rm{code}\/\\rm{mass}",
    "code_temperature" : "\\rm{code}\/\\rm{temperature}",
    "code_metallicity" : "\\rm{code}\/\\rm{metallicity}",
    "code_velocity" : "\\rm{code}\/\\rm{velocity}",
    "Msun" : "\\rm{M}_\\odot",
    "msun" : "\\rm{M}_\\odot",
    "Rsun" : "\\rm{R}_\\odot",
    "rsun" : "\\rm{R}_\\odot",
    "Lsun" : "\\rm{L}_\\odot",
    "Tsun" : "\\rm{T}_\\odot",
    "Zsun" : "\\rm{Z}_\\odot",
}
for key in default_unit_symbol_lut:
    if key not in latex_symbol_lut:
        latex_symbol_lut[key] = "\\rm{" + key + "}"

# This dictionary formatting from magnitude package, credit to Juan Reyero.
unit_prefixes = {
    'Y': 1e24,   # yotta
    'Z': 1e21,   # zetta
    'E': 1e18,   # exa
    'P': 1e15,   # peta
    'T': 1e12,   # tera
    'G': 1e9,    # giga
    'M': 1e6,    # mega
    'k': 1e3,    # kilo
    'd': 1e1,    # deci
    'c': 1e-2,   # centi
    'm': 1e-3,   # mili
    'u': 1e-6,   # micro
    'n': 1e-9,   # nano
    'p': 1e-12,  # pico
    'f': 1e-15,  # femto
    'a': 1e-18,  # atto
    'z': 1e-21,  # zepto
    'y': 1e-24,  # yocto
}

prefixable_units = (
    "m",
    "pc",
    "mcm",
    "pccm",
    "g",
    "eV",
    "s",
    "yr",
    "K",
    "dyne",
    "erg",
    "esu",
    "J",
    "Hz",
    "W",
    "gauss",
    "Jy",
)

cgs_base_units = {
    dimensions.mass:'g',
    dimensions.length:'cm',
    dimensions.time:'s',
    dimensions.temperature:'K',
    dimensions.angle:'radian',
}
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Tools for fitting and removing trends from light curves using the ￭ algorithm.
The default settings are tuned to work well for Kepler light curves but the
same algorithm might be useful for other datasets.

"""

from __future__ import (division, print_function, absolute_import,
                        unicode_literals)

__all__ = ["untrend", "fit_trend", "discontinuity_scalar", "median"]

import logging
import numpy as np

try:
    from scipy.interpolate import LSQUnivariateSpline
    LSQUnivariateSpline = LSQUnivariateSpline
except ImportError:
    LSQUnivariateSpline = None

from . import _untrendy

def untrend(x, y, yerr=None, **kwargs):
    """
    Use iteratively re-weighted least squares to remove the out-of-transit
    trends in a light curve.

    **Parameters**

    :``x``:          The sampled times.
    :``y``:          The fluxes corresponding to the times in ``x``.
    :``yerr``:       (optional) The 1-sigma error bars on ``y``.
    :``**kwargs``:   (optional) Other arguments passed to the ``fit_trend``
                     function.

    **Returns**

    :``flux``:       The de-trended relative fluxes.
    :``ferr``:       The de-trended uncertainties on ``flux``.

    """
    trend = fit_trend(x, y, yerr=yerr, **kwargs)
    factor = trend(x)
    return y / factor, yerr / factor

def fit_trend(x, y, yerr=None, Q=24, dt=3., tol=1.25e-3, maxiter=15,
              fill_times=None, maxditer=4, nfill=4,
              widths=[1.5, 2.25, 3.0]):
    """
    Use iteratively re-weighted least squares to fit a spline to the
    out-of-transit trends in a time series. The input data should be "clean".
    In other words, bad data should be masked and it often helps to normalize
    the fluxes (by the median or something).

    **Parameters**

    :``x``:          The sampled times.
    :``y``:          The fluxes corresponding to the times in ``x``.
    :``yerr``:       (optional) The 1-sigma error bars on ``y``.
    :``Q``:          (optional) The parameter controlling the severity of the
                     re-weighting.
    :``dt``:         (optional) The initial spacing between time control
                     points.
    :``tol``:        (optional) The convergence criterion.
    :``maxiter``:    (optional) The maximum number of re-weighting iterations
                     to run.
    :``fill_times``: (optional) If provided, this number sets the minimum time
                     spacing between adjacent samples that is acceptable. If
                     the spacing is larger, knots will be added to fill in
                     the gap.
    :``maxditer``:   (optional) The maximum number of discontinuity search
                     iterations to run.
    :``nfill``:      (optional) The number of knots to use to fill in the
                     gaps.
    :``width``:      (optional) The width of the discontinuity filter in the
                     same units as ``x``.

    **Returns**

    :``trend``:      A callable representation of the trend.

    """
    if LSQUnivariateSpline is None:
        raise ImportError("scipy is required for spline de-trending.")

    assert maxditer > 0

    if yerr is None:
        yerr = np.ones_like(y)

    x, y, yerr = np.array(x), np.array(y), np.array(yerr)

    # Mask bad data.
    mask = ~(np.isnan(x) + np.isnan(y) + np.isnan(yerr))
    x_masked, y_masked, yerr_masked = x[mask], y[mask], yerr[mask]

    # Remove any points that aren't sequential.
    delta = np.append(x_masked[1:] - x_masked[:-1], True)
    x_masked = x_masked[delta > 0]
    y_masked = y_masked[delta > 0]
    yerr_masked = yerr_masked[delta > 0]

    # Get the median flux.
    mu = np.median(y_masked)

    # Compute the initial weights.
    ivar = 1. / yerr_masked / yerr_masked
    w = np.array(ivar)

    # Build the list of knot locations.
    N = (x[-1] - x[0]) / dt + 2
    t = np.linspace(x[0], x[-1], N)[1:-1]

    # Refine knot locations around break points.
    if fill_times is not None:
        inds = x[1:] - x[:-1] > fill_times
        logging.info("Filling in {0} time gaps.".format(np.sum(inds)))
        for i in np.arange(len(x))[inds]:
            t = _add_knots(t, x[i], x[i + 1], N=np.max([nfill, 4]))

    discontinuities = []
    for j in range(maxditer):
        s0 = None
        for i in range(maxiter):
            # Remove any knots that are at exactly the same point.
            delta = t[1:] - t[:-1]
            if np.any(delta <= 0):
                t = t[delta > 0]

            # Add "data" at the positions of all the knots at the median of
            # the fluxes. This should help keep the values reasonable even
            # in time gaps.
            x0 = np.append(x_masked, t)
            inds = np.argsort(x0)
            x0 = x0[inds]
            y0 = np.append(y_masked, mu * np.ones_like(t))[inds]
            w0 = np.append(w, np.ones_like(t))[inds]

            # Fit the spline.
            try:
                p = LSQUnivariateSpline(x0, y0, t, k=3, w=w0)
            except ValueError:
                print("Knot spacing:")
                print(list(x0[1:] - x0[:-1]))
                raise

            # Compute chi_i ^2.
            chi = (y_masked - p(x_masked)) / yerr_masked
            chi2 = chi * chi

            # Check for convergence.
            sigma = np.median(chi2)
            if s0 is not None and np.abs(s0 - sigma) < tol:
                logging.info("Converged after {0} re-weighting iterations."
                             .format(i))
                break
            s0 = sigma

            # Re compute weights.
            w = ivar * Q / (chi2 + Q)

        # Find any discontinuities.
        count = 0
        for width in widths:
            i = _untrendy.find_discontinuities(x_masked[1:-2], chi[1:-2],
                                               width, Q, 2)
            if i < 0 or x_masked[i + 1] in discontinuities:
                continue

            count += 1
            discontinuities.append(x_masked[i + 1])

            logging.info("Discontinuity found at t={0}"
                         .format(x_masked[i + 1]))
            t = _add_knots(t, x_masked[i + 1], x_masked[i + 2],
                           N=np.max([nfill, 4]))

        # End if nothing is found.
        if count == 0:
            break

    return p

def _add_knots(t, t1, t2, N=3):
    """
    A hack for adding ``N`` samples in a given region and removing any other
    samples in that region.

    """
    assert t2 > t1
    return np.sort(np.append(t[(t < t1) + (t > t2)], np.linspace(t1, t2, N)))

def discontinuity_scalar(x, y, yerr=None, **kwargs):
    kwargs["maxditer"] = kwargs.get("maxditer", 15) - 1
    trend = fit_trend(x, y, yerr=yerr, **kwargs)

    Q = kwargs.get("Q", 12)
    dt = kwargs.get("dt", 4.)

    chi = (y - trend(x)) / yerr
    softr = np.sqrt(Q / (Q + chi * chi)) * chi

    tmid = 0.5 * (x[1:] + x[:-1])
    k = (x[:, None] - tmid[None, :]) / dt
    k = (k - 1) ** 2 * (0 <= k) * (k <= 1) - (k + 1) ** 2 * (-1 <= k) * (k < 0)
    val = np.sum(k * softr[:, None], axis=0) / np.sum(k * k, axis=0)

    return tmid, val * val

def median(x, y, dt=4.):
    """
    De-trend a light curve using a windowed median.

    """
    x, y = np.atleast_1d(x), np.atleast_1d(y)
    assert len(x) == len(y)
    r = np.empty(len(y))
    for i, t in enumerate(x):
        inds = (x >= t - 0.5 * dt) * (x <= t + 0.5 * dt)
        r[i] = np.median(y[inds])
    return r
<commit_msg>bullshit<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Tools for fitting and removing trends from light curves using the ￭ algorithm.
The default settings are tuned to work well for Kepler light curves but the
same algorithm might be useful for other datasets.

"""

from __future__ import (division, print_function, absolute_import,
                        unicode_literals)

__all__ = ["untrend", "fit_trend", "discontinuity_scalar", "median"]

import logging
import numpy as np

try:
    from scipy.interpolate import LSQUnivariateSpline
    LSQUnivariateSpline = LSQUnivariateSpline
except ImportError:
    LSQUnivariateSpline = None

from . import _untrendy

def untrend(x, y, yerr=None, **kwargs):
    """
    Use iteratively re-weighted least squares to remove the out-of-transit
    trends in a light curve.

    **Parameters**

    :``x``:          The sampled times.
    :``y``:          The fluxes corresponding to the times in ``x``.
    :``yerr``:       (optional) The 1-sigma error bars on ``y``.
    :``**kwargs``:   (optional) Other arguments passed to the ``fit_trend``
                     function.

    **Returns**

    :``flux``:       The de-trended relative fluxes.
    :``ferr``:       The de-trended uncertainties on ``flux``.

    """
    trend = fit_trend(x, y, yerr=yerr, **kwargs)
    factor = trend(x)
    return y / factor, yerr / factor

def fit_trend(x, y, yerr=None, Q=24, dt=3., tol=1.25e-3, maxiter=15,
              fill_times=None, maxditer=4, nfill=4,
              widths=[1.5, 2.25, 3.0]):
    """
    Use iteratively re-weighted least squares to fit a spline to the
    out-of-transit trends in a time series. The input data should be "clean".
    In other words, bad data should be masked and it often helps to normalize
    the fluxes (by the median or something).

    **Parameters**

    :``x``:          The sampled times.
    :``y``:          The fluxes corresponding to the times in ``x``.
    :``yerr``:       (optional) The 1-sigma error bars on ``y``.
    :``Q``:          (optional) The parameter controlling the severity of the
                     re-weighting.
    :``dt``:         (optional) The initial spacing between time control
                     points.
    :``tol``:        (optional) The convergence criterion.
    :``maxiter``:    (optional) The maximum number of re-weighting iterations
                     to run.
    :``fill_times``: (optional) If provided, this number sets the minimum time
                     spacing between adjacent samples that is acceptable. If
                     the spacing is larger, knots will be added to fill in
                     the gap.
    :``maxditer``:   (optional) The maximum number of discontinuity search
                     iterations to run.
    :``nfill``:      (optional) The number of knots to use to fill in the
                     gaps.
    :``width``:      (optional) The width of the discontinuity filter in the
                     same units as ``x``.

    **Returns**

    :``trend``:      A callable representation of the trend.

    """
    if LSQUnivariateSpline is None:
        raise ImportError("scipy is required for spline de-trending.")

    assert maxditer > 0

    if yerr is None:
        yerr = np.ones_like(y)

    x, y, yerr = np.array(x), np.array(y), np.array(yerr)

    # Mask bad data.
    mask = ~(np.isnan(x) + np.isnan(y) + np.isnan(yerr))
    x_masked, y_masked, yerr_masked = x[mask], y[mask], yerr[mask]

    # Remove any points that aren't sequential.
    delta = np.append(x_masked[1:] - x_masked[:-1], True)
    x_masked = x_masked[delta > 0]
    y_masked = y_masked[delta > 0]
    yerr_masked = yerr_masked[delta > 0]

    # Get the median flux.
    mu = np.median(y_masked)

    # Compute the initial weights.
    ivar = 1. / yerr_masked / yerr_masked
    w = np.array(ivar)

    # Build the list of knot locations.
    N = (x[-1] - x[0]) / dt + 2
    t = np.linspace(x[0], x[-1], N)[1:-1]

    # Refine knot locations around break points.
    if fill_times is not None:
        inds = x[1:] - x[:-1] > fill_times
        logging.info("Filling in {0} time gaps.".format(np.sum(inds)))
        for i in np.arange(len(x))[inds]:
            t = _add_knots(t, x[i], x[i + 1], N=np.max([nfill, 4]))

    discontinuities = []
    for j in range(maxditer):
        s0 = None
        for i in range(maxiter):
            # Add "data" at the positions of all the knots at the median of
            # the fluxes. This should help keep the values reasonable even
            # in time gaps.
            x0 = np.append(x_masked, t)
            inds = np.argsort(x0)
            x0 = x0[inds]
            y0 = np.append(y_masked, mu * np.ones_like(t))[inds]
            w0 = np.append(w, np.ones_like(t))[inds]

            # Remove any knots that are at exactly the same point.
            delta = x0[1:] - x0[:-1]
            if np.any(delta <= 0):
                inds = delta > 0
                x0 = x0[inds]
                y0 = y0[inds]
                w0 = w0[inds]

            # Fit the spline.
            try:
                p = LSQUnivariateSpline(x0, y0, t, k=3, w=w0)
            except ValueError:
                print("Knot spacing:")
                print(list(x0[1:] - x0[:-1]))
                raise

            # Compute chi_i ^2.
            chi = (y_masked - p(x_masked)) / yerr_masked
            chi2 = chi * chi

            # Check for convergence.
            sigma = np.median(chi2)
            if s0 is not None and np.abs(s0 - sigma) < tol:
                logging.info("Converged after {0} re-weighting iterations."
                             .format(i))
                break
            s0 = sigma

            # Re compute weights.
            w = ivar * Q / (chi2 + Q)

        # Find any discontinuities.
        count = 0
        for width in widths:
            i = _untrendy.find_discontinuities(x_masked[1:-2], chi[1:-2],
                                               width, Q, 2)
            if i < 0 or x_masked[i + 1] in discontinuities:
                continue

            count += 1
            discontinuities.append(x_masked[i + 1])

            logging.info("Discontinuity found at t={0}"
                         .format(x_masked[i + 1]))
            t = _add_knots(t, x_masked[i + 1], x_masked[i + 2],
                           N=np.max([nfill, 4]))

        # End if nothing is found.
        if count == 0:
            break

    return p

def _add_knots(t, t1, t2, N=3):
    """
    A hack for adding ``N`` samples in a given region and removing any other
    samples in that region.

    """
    return np.sort(np.append(t[(t < t1) + (t > t2)], np.linspace(t1, t2, N)))

def discontinuity_scalar(x, y, yerr=None, **kwargs):
    kwargs["maxditer"] = kwargs.get("maxditer", 15) - 1
    trend = fit_trend(x, y, yerr=yerr, **kwargs)

    Q = kwargs.get("Q", 12)
    dt = kwargs.get("dt", 4.)

    chi = (y - trend(x)) / yerr
    softr = np.sqrt(Q / (Q + chi * chi)) * chi

    tmid = 0.5 * (x[1:] + x[:-1])
    k = (x[:, None] - tmid[None, :]) / dt
    k = (k - 1) ** 2 * (0 <= k) * (k <= 1) - (k + 1) ** 2 * (-1 <= k) * (k < 0)
    val = np.sum(k * softr[:, None], axis=0) / np.sum(k * k, axis=0)

    return tmid, val * val

def median(x, y, dt=4.):
    """
    De-trend a light curve using a windowed median.

    """
    x, y = np.atleast_1d(x), np.atleast_1d(y)
    assert len(x) == len(y)
    r = np.empty(len(y))
    for i, t in enumerate(x):
        inds = (x >= t - 0.5 * dt) * (x <= t + 0.5 * dt)
        r[i] = np.median(y[inds])
    return r
<|endoftext|>


<commit_before>"""
Predefined useful aliases to physical units

Note that all of these names can be imported from the top-level unyt namespace.
For example::

    >>> from unyt import cm, g, s
    >>> data = [3, 4, 5]*g*cm/s
    >>> print(data)
    [3. 4. 5.] cm*g/s

"""

# -----------------------------------------------------------------------------
# Copyright (c) 2018, yt Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the LICENSE file, distributed with this software.
# -----------------------------------------------------------------------------

from unyt.unit_object import Unit
from unyt.array import unyt_quantity as quan

#
# meter
#

#: femtometer
fm = femtometer = Unit("fm")
#: picometer
pm = picometer = Unit("pm")
#: nanometer
nm = nanometer = Unit("nm")
#: micrometer
um = micrometer = Unit("um")
#: millimeter
mm = millimeter = Unit("mm")
#: centimeter
cm = centimeter = Unit("cm")
#: meter
m = meter = Unit("m")
#: kilometer
km = kilometer = Unit("km")
#: Megameter
Mm = Megameter = megameter = Unit("Mm")

#
# parsec
#

#: parsec
pc = parsec = Unit("pc")
#: kiloparsec
kpc = kiloparsec = Unit("kpc")
#: megaparsec
Mpc = mpc = megaparsec = Unit("Mpc")
#: gigaparsec
Gpc = gpc = Gigaparsec = Unit("Gpc")

#
# gram
#

#: picogram
pg = picogram = Unit("pg")
#: nanogram
ng = nanogram = Unit("ng")
#: micogram
ug = microgram = Unit("ug")
#: milligram
mg = milligram = Unit("mg")
#: gram
g = gram = Unit("g")
#: kilogram
kg = kilogram = Unit("kg")
#: megagram
Mg = megagramme = tonne = metric_ton = Unit("kg")

#
# second
#

#: femtosecond
fs = femtoseconds = Unit("fs")
#: picosecond
ps = picosecond = Unit("ps")
#: nanosecond
ns = nanosecond = Unit("ns")
#: millisecond
ms = millisecond = Unit("ms")
#: second
s = second = Unit("s")
#: kilosecond
ks = kilosecond = Unit("ks")
#: megasecond
Ms = megasecond = Unit("Ms")
#: gigasecond
Gs = gigasecond = Unit("Gs")

#
# minute
#

#: minute
min = minute = Unit("min")

#
# hr
#

#: hour
hr = hour = Unit("hr")

#
# day
#

#: day
day = Unit("day")

#
# year
#

#: year
yr = year = Unit("yr")
#: kiloyear
kyr = kiloyear = Unit("kyr")
#: Megayear
Myr = Megayear = megayear = Unit("Myr")
#: Gigayear
Gyr = Gigayear = gigayear = Unit("Gyr")

#
# Temperatures
#

#: Degree kelvin
degree_kelvin = Kelvin = K = Unit("K")
#: Degree fahrenheit
degree_fahrenheit = degF = Unit("degF")
#: Degree Celsius
degree_celsius = degC = Unit("degC")
#:
degree_rankine = R = Unit("R")

#
# Misc CGS
#

#: dyne (CGS force)
dyne = dyn = Unit("dyne")
#: erg (CGS energy)
erg = ergs = Unit("erg")
#:
barye = Ba = Unit("Ba")

#
# Misc SI
#

#: Newton (SI force)
N = Newton = newton = Unit("N")
#: Joule (SI energy)
J = Joule = joule = Unit("J")
#: Watt (SI power)
W = Watt = watt = Unit("W")
#: Hertz
Hz = Hertz = hertz = Unit("Hz")
#: Kilohertz
kHz = khz = kilohertz = Unit("kHz")
#: Megahertz
MHz = mhz = megahertz = Unit("MHz")
#: Gigahertz
GHz = ghz = gigahertz = Unit("GHz")
#: Terahertz
THz = thz = terahertz = Unit("THz")
#: Pascal
Pa = pascal = Unit("Pa")
#: sievert
Sv = sievert = Unit("Sv")
#: candela
cd = Candela = candela = Unit("cd")
#: lumen
lm = Lumen = lumen = Unit("lm")
#: lux
lx = Lux = lux = Unit('lx')
#: lambert
lambert = Lambert = Unit('lambert')
#: nit
nt = nit = Nit = Unit("nt")

#
# Imperial units
#

#: inch
inch = Unit("inch")
#: foot
ft = foot = Unit("ft")
#: mile
mile = Unit("mile")
#: furlong
fur = furlong = Unit("fur")
#: yard
yard = yd = Unit("yd")
#: pound
lb = pound = Unit("lb")
#: slug
slug = Unit("slug")
#: ounce
oz = ounce = Unit("oz")
#: ton
ton = Unit("ton")
#: pound-force
lbf = pound_force = Unit("lbf")
#: atmosphere
atm = atmosphere = Unit("atm")
#: horsepower
hp = horsepower = Unit("hp")
#: BTU
BTU = Unit("BTU")
#: calorie
cal = calorie = Unit("cal")
#: psi
psi = Unit("psi")

#
# Solar units
#

#: Mass of the sun
Msun = Unit("Msun")
#: Radius of the sun
Rsun = R_sun = solar_radius = Unit("Rsun")
#: Radius of the sun
rsun = r_sun = Unit("rsun")
#: Luminosity of the sun
Lsun = lsun = l_sun = solar_luminosity = Unit("Lsun")
#: Temperature of the sun
Tsun = T_sun = solar_temperature = Unit("Tsun")
#: Metallicity of the sun
Zsun = Z_sun = solar_metallicity = Unit("Zsun")

#
# Misc Astronomical units
#

#: Astronomical unit
AU = astronomical_unit = Unit("AU")
#: Astronomical unit
au = Unit("au")
#: Light year
ly = light_year = Unit("ly")
#: Radius of the Earth
Rearth = R_earth = earth_radius = Unit('R_earth')
#: Radius of the Earth
rearth = r_earth = Unit('r_earth')
#: Radius of Jupiter
Rjup = R_jup = jupiter_radius = Unit('R_jup')
#: Radius of Jupiter
rjup = r_jup = Unit('r_jup')
#: Jansky
Jy = jansky = Unit("Jy")

#
# Physical units
#

#: electronvolt
eV = electron_volt = electronvolt = Unit("eV")
#: kiloelectronvolt
keV = kilo_electron_volt = kiloelectronvolt = Unit("keV")
#: Megaelectronvolt
MeV = mega_electron_volt = Megaelectronvolt = megaelectronvolt = quan(
    1.0, "MeV")
#: Gigaelectronvolt
GeV = giga_electron_volt = Gigaelectronvolt = gigaelectronvolt = quan(
    1.0, "GeV")
#: Atomic mass unit
amu = atomic_mass_unit = Unit("amu")
mol = Unit("mol")
#: Angstrom
angstrom = Unit("angstrom")
#: Electron mass
me = electron_mass = Unit("me")

#
# Angle units
#

#: Degree (angle)
deg = degree = Unit("degree")
#: Radian
rad = radian = Unit("radian")
#: Arcsecond
arcsec = arcsecond = Unit("arcsec")
#: Arcminute
arcmin = arcminute = Unit("arcmin")
#: milliarcsecond
mas = milliarcsecond = Unit("mas")
#: steradian
sr = steradian = Unit("steradian")
#: hourangle
HA = hourangle = Unit("hourangle")

#
# CGS electromagnetic units
#

#: electrostatic unit
electrostatic_unit = esu = Unit("esu")
#: Gauss
gauss = G = Unit("gauss")
#: Statampere
statampere = statA = Unit("statA")
#: Statvolt
statvolt = statV = Unit("statV")
#: Statohm
statohm = Unit("statohm")
#: Maxwell
Mx = maxwell = Maxwell = Unit("Mx")

#
# SI electromagnetic units
#

#: Coulomb
C = coulomb = Coulomb = Unit("C")
#: Tesla
T = tesla = Tesla = Unit("T")
#: Ampere
A = ampere = Ampere = Unit("A")
#: Volt
V = volt = Volt = Unit("V")
#: Ohm
ohm = Ohm = Unit("ohm")
#: Weber
Wb = weber = Weber = Unit("Wb")

#
# Geographic units
#

#: Degree latitude
latitude = lat = Unit("lat")
#: Degree longitude
longitude = lon = Unit("lon")

#
# Misc dimensionless units
#

#: Count of something
counts = count = Unit('counts')
#: Number of photons
photons = photon = Unit('photons')
#: dimensionless
_ = dimensionless = Unit('')
<commit_msg>Not sure why these couldn't be units also<commit_after>"""
Predefined useful aliases to physical units

Note that all of these names can be imported from the top-level unyt namespace.
For example::

    >>> from unyt import cm, g, s
    >>> data = [3, 4, 5]*g*cm/s
    >>> print(data)
    [3. 4. 5.] cm*g/s

"""

# -----------------------------------------------------------------------------
# Copyright (c) 2018, yt Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the LICENSE file, distributed with this software.
# -----------------------------------------------------------------------------

from unyt.unit_object import Unit

#
# meter
#

#: femtometer
fm = femtometer = Unit("fm")
#: picometer
pm = picometer = Unit("pm")
#: nanometer
nm = nanometer = Unit("nm")
#: micrometer
um = micrometer = Unit("um")
#: millimeter
mm = millimeter = Unit("mm")
#: centimeter
cm = centimeter = Unit("cm")
#: meter
m = meter = Unit("m")
#: kilometer
km = kilometer = Unit("km")
#: Megameter
Mm = Megameter = megameter = Unit("Mm")

#
# parsec
#

#: parsec
pc = parsec = Unit("pc")
#: kiloparsec
kpc = kiloparsec = Unit("kpc")
#: megaparsec
Mpc = mpc = megaparsec = Unit("Mpc")
#: gigaparsec
Gpc = gpc = Gigaparsec = Unit("Gpc")

#
# gram
#

#: picogram
pg = picogram = Unit("pg")
#: nanogram
ng = nanogram = Unit("ng")
#: micogram
ug = microgram = Unit("ug")
#: milligram
mg = milligram = Unit("mg")
#: gram
g = gram = Unit("g")
#: kilogram
kg = kilogram = Unit("kg")
#: megagram
Mg = megagramme = tonne = metric_ton = Unit("kg")

#
# second
#

#: femtosecond
fs = femtoseconds = Unit("fs")
#: picosecond
ps = picosecond = Unit("ps")
#: nanosecond
ns = nanosecond = Unit("ns")
#: millisecond
ms = millisecond = Unit("ms")
#: second
s = second = Unit("s")
#: kilosecond
ks = kilosecond = Unit("ks")
#: megasecond
Ms = megasecond = Unit("Ms")
#: gigasecond
Gs = gigasecond = Unit("Gs")

#
# minute
#

#: minute
min = minute = Unit("min")

#
# hr
#

#: hour
hr = hour = Unit("hr")

#
# day
#

#: day
day = Unit("day")

#
# year
#

#: year
yr = year = Unit("yr")
#: kiloyear
kyr = kiloyear = Unit("kyr")
#: Megayear
Myr = Megayear = megayear = Unit("Myr")
#: Gigayear
Gyr = Gigayear = gigayear = Unit("Gyr")

#
# Temperatures
#

#: Degree kelvin
degree_kelvin = Kelvin = K = Unit("K")
#: Degree fahrenheit
degree_fahrenheit = degF = Unit("degF")
#: Degree Celsius
degree_celsius = degC = Unit("degC")
#:
degree_rankine = R = Unit("R")

#
# Misc CGS
#

#: dyne (CGS force)
dyne = dyn = Unit("dyne")
#: erg (CGS energy)
erg = ergs = Unit("erg")
#:
barye = Ba = Unit("Ba")

#
# Misc SI
#

#: Newton (SI force)
N = Newton = newton = Unit("N")
#: Joule (SI energy)
J = Joule = joule = Unit("J")
#: Watt (SI power)
W = Watt = watt = Unit("W")
#: Hertz
Hz = Hertz = hertz = Unit("Hz")
#: Kilohertz
kHz = khz = kilohertz = Unit("kHz")
#: Megahertz
MHz = mhz = megahertz = Unit("MHz")
#: Gigahertz
GHz = ghz = gigahertz = Unit("GHz")
#: Terahertz
THz = thz = terahertz = Unit("THz")
#: Pascal
Pa = pascal = Unit("Pa")
#: sievert
Sv = sievert = Unit("Sv")
#: candela
cd = Candela = candela = Unit("cd")
#: lumen
lm = Lumen = lumen = Unit("lm")
#: lux
lx = Lux = lux = Unit('lx')
#: lambert
lambert = Lambert = Unit('lambert')
#: nit
nt = nit = Nit = Unit("nt")

#
# Imperial units
#

#: inch
inch = Unit("inch")
#: foot
ft = foot = Unit("ft")
#: mile
mile = Unit("mile")
#: furlong
fur = furlong = Unit("fur")
#: yard
yard = yd = Unit("yd")
#: pound
lb = pound = Unit("lb")
#: slug
slug = Unit("slug")
#: ounce
oz = ounce = Unit("oz")
#: ton
ton = Unit("ton")
#: pound-force
lbf = pound_force = Unit("lbf")
#: atmosphere
atm = atmosphere = Unit("atm")
#: horsepower
hp = horsepower = Unit("hp")
#: BTU
BTU = Unit("BTU")
#: calorie
cal = calorie = Unit("cal")
#: psi
psi = Unit("psi")

#
# Solar units
#

#: Mass of the sun
Msun = Unit("Msun")
#: Radius of the sun
Rsun = R_sun = solar_radius = Unit("Rsun")
#: Radius of the sun
rsun = r_sun = Unit("rsun")
#: Luminosity of the sun
Lsun = lsun = l_sun = solar_luminosity = Unit("Lsun")
#: Temperature of the sun
Tsun = T_sun = solar_temperature = Unit("Tsun")
#: Metallicity of the sun
Zsun = Z_sun = solar_metallicity = Unit("Zsun")

#
# Misc Astronomical units
#

#: Astronomical unit
AU = astronomical_unit = Unit("AU")
#: Astronomical unit
au = Unit("au")
#: Light year
ly = light_year = Unit("ly")
#: Radius of the Earth
Rearth = R_earth = earth_radius = Unit('R_earth')
#: Radius of the Earth
rearth = r_earth = Unit('r_earth')
#: Radius of Jupiter
Rjup = R_jup = jupiter_radius = Unit('R_jup')
#: Radius of Jupiter
rjup = r_jup = Unit('r_jup')
#: Jansky
Jy = jansky = Unit("Jy")

#
# Physical units
#

#: electronvolt
eV = electron_volt = electronvolt = Unit("eV")
#: kiloelectronvolt
keV = kilo_electron_volt = kiloelectronvolt = Unit("keV")
#: Megaelectronvolt
MeV = mega_electron_volt = Megaelectronvolt = megaelectronvolt = Unit("MeV")
#: Gigaelectronvolt
GeV = giga_electron_volt = Gigaelectronvolt = gigaelectronvolt = Unit("GeV")
#: Atomic mass unit
amu = atomic_mass_unit = Unit("amu")
mol = Unit("mol")
#: Angstrom
angstrom = Unit("angstrom")
#: Electron mass
me = electron_mass = Unit("me")

#
# Angle units
#

#: Degree (angle)
deg = degree = Unit("degree")
#: Radian
rad = radian = Unit("radian")
#: Arcsecond
arcsec = arcsecond = Unit("arcsec")
#: Arcminute
arcmin = arcminute = Unit("arcmin")
#: milliarcsecond
mas = milliarcsecond = Unit("mas")
#: steradian
sr = steradian = Unit("steradian")
#: hourangle
HA = hourangle = Unit("hourangle")

#
# CGS electromagnetic units
#

#: electrostatic unit
electrostatic_unit = esu = Unit("esu")
#: Gauss
gauss = G = Unit("gauss")
#: Statampere
statampere = statA = Unit("statA")
#: Statvolt
statvolt = statV = Unit("statV")
#: Statohm
statohm = Unit("statohm")
#: Maxwell
Mx = maxwell = Maxwell = Unit("Mx")

#
# SI electromagnetic units
#

#: Coulomb
C = coulomb = Coulomb = Unit("C")
#: Tesla
T = tesla = Tesla = Unit("T")
#: Ampere
A = ampere = Ampere = Unit("A")
#: Volt
V = volt = Volt = Unit("V")
#: Ohm
ohm = Ohm = Unit("ohm")
#: Weber
Wb = weber = Weber = Unit("Wb")

#
# Geographic units
#

#: Degree latitude
latitude = lat = Unit("lat")
#: Degree longitude
longitude = lon = Unit("lon")

#
# Misc dimensionless units
#

#: Count of something
counts = count = Unit('counts')
#: Number of photons
photons = photon = Unit('photons')
#: dimensionless
_ = dimensionless = Unit('')
<|endoftext|>


<commit_before>from os.path import basename
from functools import partial

from app.system.updater import check_updates, run_ansible
from app.system.updater import do_reboot
from app.views import SimpleBackgroundView
from .base import BaseService, BlockingServiceStart

class UpdaterService(BaseService, BlockingServiceStart):
    def __init__(self, observer=None):
        super().__init__(observer=observer)
        self._view = SimpleBackgroundView("Checking for updates.")
        self._view.args["subtitle"] = "Please wait ..."

    def on_service_start(self):
        def check_update_progress(val):
            self._view.args["subtitle"] = "Checking ... {:.0%}".format(val)
            self.observer()

        def check_pull_progress(base, val):
            self._view.args["subtitle"] = base + " ... {:.0%}".format(val)
            self.observer()

        values = check_updates(check_update_progress)
        for count, repo in enumerate(values):
            subtitle_params = count + 1, len(values), repo.repo_name
            subtitle = "({}/{}) Updating {}".format(*subtitle_params)

            self._view.args["subtitle"] = subtitle
            self.observer()
            repo.pull(partial(check_pull_progress, subtitle))

        if len(values):
            self._view.args["subtitle"] = "Updating system configuration..."
            self.observer()
            run_ansible()

            self._view.args["subtitle"] = "Restarting..."
            self.observer()
            do_reboot()

    def view(self):
        return self._view

<commit_msg>Refactor code.<commit_after>from os.path import basename
from functools import partial

from app.system.updater import check_updates, run_ansible
from app.system.updater import do_reboot
from app.views import SimpleBackgroundView
from .base import BaseService, BlockingServiceStart

class UpdaterService(BaseService, BlockingServiceStart):
    def __init__(self, observer=None):
        super().__init__(observer=observer)
        self._view = SimpleBackgroundView("Checking for updates.")
        self.flash_message("Please wait ...")

    def on_service_start(self):
        def check_update_progress(val):
            self.flash_message("Checking ... {:.0%}".format(val))

        def check_pull_progress(base, val):
            self.flash_message(base + " ... {:.0%}".format(val))

        values = check_updates(check_update_progress)
        for count, repo in enumerate(values):
            subtitle_params = count + 1, len(values), repo.repo_name
            subtitle = "({}/{}) Updating {}".format(*subtitle_params)

            self.flash_message(subtitle)
            repo.pull(partial(check_pull_progress, subtitle))

        if len(values):
            self.flash_message("Updating system configuration...")
            run_ansible()

            self.flash_message("Restarting...")
            do_reboot()

    def flash_message(self, msg):
        self._view.args["subtitle"] = msg
        self.observer()

    def view(self):
        return self._view

<|endoftext|>


<commit_before>#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Views for Programs.
"""

__authors__ = [
    '"Sverre Rabbelier" <sverre@rabbelier.nl>',
    '"Lennard de Rijk" <ljvderijk@gmail.com>',
  ]

from django import forms

from soc.logic import cleaning
from soc.logic import dicts
from soc.logic.models import timeline as timeline_logic
from soc.views import helper
from soc.views.helper import access
from soc.views.helper import redirects
from soc.views.models import base
from soc.views.models import document as document_view
from soc.views.models import sponsor as sponsor_view
from soc.views.sitemap import sidebar

import gsoc.models.timeline
import soc.models.timeline

import soc.logic.models.program

class View(base.View):
  """View methods for the Program model.
  """

  def __init__(self, params=None):
    """Defines the fields and methods required for the base View class
    to provide the user with list, public, create, edit and delete views.

    Params:
      params: a dict with params for this View
    """

    rights = {}
    rights['any_access'] = [access.allow]
    rights['show'] = [access.allow]

    new_params = {}
    new_params['logic'] = soc.logic.models.program.logic
    new_params['rights'] = rights

    new_params['scope_view'] = sponsor_view
    new_params['scope_redirect'] = redirects.getCreateRedirect

    new_params['name'] = "Program"
    new_params['name_short'] = "Program"
    new_params['name_plural'] = "Programs"
    new_params['url_name'] = "program"
    new_params['module_name'] = "program"

    new_params['extra_dynaexclude'] = ['home', 'timeline']
    new_params['create_extra_dynafields'] = {
        'description': forms.fields.CharField(widget=helper.widgets.TinyMCE(
            attrs={'rows':10, 'cols':40})),
        'scope_path': forms.CharField(widget=forms.HiddenInput, required=True),
        'workflow' : forms.ChoiceField(choices=[('gsoc','Project-based'),
            ('ghop','Task-based')], required=True),
        'clean_link_id': cleaning.clean_link_id,
        }

    params = dicts.merge(params, new_params)

    super(View, self).__init__(params=params)

  def _editPost(self, request, entity, fields):
    """See base._editPost().
    """

    fields['timeline'] = self._createTimelineForType(fields['workflow'])

  def _createTimelineForType(self, type):
    """Creates and stores a timeline model for the given type of program
    """

    timelines = {'gsoc' : gsoc.models.timeline.Timeline(),
                 'ghop' : soc.models.timeline.Timeline()}

    return timelines[type].put()

  def getExtraMenus(self, request, params=None):
    """Returns the extra menu's for this view.

    A menu item is generated for each program that is currently
    running. The public page for each program is added as menu item,
    as well as all public documents for that program.

    Args:
      request: unused
      params: a dict with params for this View.
    """

    params = dicts.merge(params, self._params)
    logic = params['logic']

    entities = logic.getForLimitAndOffset(1000)

    doc_params = document_view.view.getParams()
    menus = []

    for entity in entities:
      menu = {}
      menu['heading'] = entity.short_name
      items = document_view.view.getMenusForScope(entity, params)
      menu['items'] = sidebar.getSidebarMenu(request, items, params=doc_params)
      menus.append(menu)

    return menus

view = View()

create = view.create
delete = view.delete
edit = view.edit
list = view.list
public = view.public
<commit_msg>Fixed a bug where a new timeline would get created on every edit of an existing program.<commit_after>#!/usr/bin/python2.5
#
# Copyright 2008 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Views for Programs.
"""

__authors__ = [
    '"Sverre Rabbelier" <sverre@rabbelier.nl>',
    '"Lennard de Rijk" <ljvderijk@gmail.com>',
  ]

from django import forms

from soc.logic import cleaning
from soc.logic import dicts
from soc.logic.models import timeline as timeline_logic
from soc.views import helper
from soc.views.helper import access
from soc.views.helper import redirects
from soc.views.models import base
from soc.views.models import document as document_view
from soc.views.models import sponsor as sponsor_view
from soc.views.sitemap import sidebar

import gsoc.models.timeline
import soc.models.timeline

import soc.logic.models.program

class View(base.View):
  """View methods for the Program model.
  """

  def __init__(self, params=None):
    """Defines the fields and methods required for the base View class
    to provide the user with list, public, create, edit and delete views.

    Params:
      params: a dict with params for this View
    """

    rights = {}
    rights['any_access'] = [access.allow]
    rights['show'] = [access.allow]

    new_params = {}
    new_params['logic'] = soc.logic.models.program.logic
    new_params['rights'] = rights

    new_params['scope_view'] = sponsor_view
    new_params['scope_redirect'] = redirects.getCreateRedirect

    new_params['name'] = "Program"
    new_params['name_short'] = "Program"
    new_params['name_plural'] = "Programs"
    new_params['url_name'] = "program"
    new_params['module_name'] = "program"

    new_params['extra_dynaexclude'] = ['home', 'timeline']
    new_params['create_extra_dynafields'] = {
        'description': forms.fields.CharField(widget=helper.widgets.TinyMCE(
            attrs={'rows':10, 'cols':40})),
        'scope_path': forms.CharField(widget=forms.HiddenInput, required=True),
        'workflow' : forms.ChoiceField(choices=[('gsoc','Project-based'),
            ('ghop','Task-based')], required=True),
        'clean_link_id': cleaning.clean_link_id,
        }

    params = dicts.merge(params, new_params)

    super(View, self).__init__(params=params)

  def _editPost(self, request, entity, fields):
    """See base._editPost().
    """

    if not entity:
      # there is no existing entity so create a new timeline
      fields['timeline'] = self._createTimelineForType(fields['workflow'])
    else:
      # use the timeline from the entity
      fields['timeline'] = entity.timeline

  def _createTimelineForType(self, type):
    """Creates and stores a timeline model for the given type of program
    """

    timelines = {'gsoc' : gsoc.models.timeline.Timeline(),
                 'ghop' : soc.models.timeline.Timeline()}

    return timelines[type].put()

  def getExtraMenus(self, request, params=None):
    """Returns the extra menu's for this view.

    A menu item is generated for each program that is currently
    running. The public page for each program is added as menu item,
    as well as all public documents for that program.

    Args:
      request: unused
      params: a dict with params for this View.
    """

    params = dicts.merge(params, self._params)
    logic = params['logic']

    entities = logic.getForLimitAndOffset(1000)

    doc_params = document_view.view.getParams()
    menus = []

    for entity in entities:
      menu = {}
      menu['heading'] = entity.short_name
      items = document_view.view.getMenusForScope(entity, params)
      menu['items'] = sidebar.getSidebarMenu(request, items, params=doc_params)
      menus.append(menu)

    return menus

view = View()

create = view.create
delete = view.delete
edit = view.edit
list = view.list
public = view.public
<|endoftext|>