<commit_before># BS mark.1-55
# /* coding: utf-8 */

# BlackSmith Extension Manager
# This plugin distributed under Apache 2.0 license.
# (c) simpleApps, 2012.

## NOTICE:
##			All plugins that depend from another plugins or files (not help files that placed in help dir)
##			Must be contain this code: #-extmanager-depends:depend1;depend2;depend3-#
##			Where depend1, depend2 and depend3 are depends of this plugin.
import urllib

svnUrl = "http://blacksmith-bot.googlecode.com/svn/proposed/%s/"
extFile = "extensions.txt"

def urlsplit(url):
	if url and url.count("/"):
		strippedUrl = url.rstrip("/")
		tailIndex = strippedUrl.rfind("/")
		head = strippedUrl[:tailIndex]
		tail = strippedUrl[tailIndex:]
		url = (head, tail)
	return url

def getSize(url):
	request = urllib.urlopen(url)
	return int(request.headers.get("Content-Length"))

def getDepsSize(depList):
	size = int()
	for dep in depList:
		size += getSize(svnUrl % dep)
	return size

def saveDeps(path):
	Dir = os.path.split(path)[0]
	if Dir and not os.path.exists(Dir):
		os.makedirs(Dir)
	return path

def getDeps(depList = [], plugin = None):
	if plugin:
		depList = findDeps(read_url(svnUrl % "extensions/%s" % plugin))
	if depList:
		for dep in depList:
			if dep.endswith(".dir"):
				Dir = dep[:-4]
				if not os.path.exists(Dir):
					os.makedirs(Dir)
			else:
				urllib.urlretrieve(svnUrl % dep, saveDeps(dep))

def findDeps(data, join = None):
	match = re.search("#-extmanager-depends:(.*)-#", data)
	if match:
		dep = match.group(1)
		depList = dep.split(";")
		if join:
			return str.join(join, depList)
		return depList

def findExtVer(data):
	match = re.search("#-extmanager-extVer:(.*)-#", data)
	if match:
		ver = match.group(1)
		return ver
	return "1.0"

def findConflicts(data):
	match = re.search("#-extmanager-conflict:(.*)-#", data)
	if match:
		rawConflicts = match.group(1)
		if rawConflicts.count(";"):
			return rawConflicts.split(";")
		return [rawConflicts]

def extManager(mType, source, args):
	if args:
		answer = str()
		a = args.split()
		name, fullName = a[0], a[0] + ".py"
		afterA0 = args[(args.find(" ") + 1):].strip()
		extList = re.findall("\">(.*\.py)
", read_url(svnUrl % "extensions")) #"
		extList = [x[:-3] for x in extList]

		if a[0] == u"лист":
			for x, y in enumerate(extList):
				answer +=  u"%i. %s;\n" % (x + 1, y)

		elif a[0] in extList and len(a) > 1:
			if a[1] in (u"лист", u"инфо", "установить"):
				data = read_url(svnUrl % "extensions/%s" % fullName)
				depList = findDeps(data)
				conflicts = findConflicts(data)
				if a[1] == u"инфо":
					pluginInfo = eval(read_url(svnUrl % ("help/" + a[0])).decode("utf-8"))
					commandList = [pluginInfo[x]["cmd"] for x in pluginInfo.keys()]
					if depList:
						jDepList = str.join(", ", depList)
						sizeOf = byteFormat(getDepsSize(depList) + getSize(svnUrl % "extensions/%s" % fullName))
					if conflicts:
						conflictList = str.join(", ", conflicts)
					commandList = str.join(", ", commandList)
					answer =\
						"\nПлагин: %(name)s.\nСодержит команды: %(commandList)s."
					if depList:
						answer +=\
							"\nДля плагина требуется: %(jDepList)s, после установки будет занятно примерно %(sizeOf)s."
					if conflicts:
						answer += " Также будут удалены: %(conflictList)s."
					answer = answer % vars()

				elif a[1] == u"установить":
					extensions = eval(read_file("dynamic/%s" % extFile))
					urllib.urlretrieve(svnUrl % "extensions/%s" % fullName, "extensions/%s" % fullName)
					urllib.urlretrieve(svnUrl % "help/" + a[0], "help/%s" % a[0])
					getDeps(depList)
					extensions[fullName] = findExtVer(read_url(svnUrl % "extensions/%s" % fullName))
					write_file("dynamic/%s" % extFile, str(extensions))
					if conflicts:
						for x in conflicts:
								if os.path.exists(x):
									try:
										os.remove(x)
										conflicts.remove(x)
									except:
										pass
								else:
									conflicts.remove(x)
					answer = u"Плагин «%s» успешно установлен"
					try:
						execfile("./extensions/%s" % fullName, globals())
						answer += " и подгружен. Возможно, понадобится перезапуск бота."
					except:
						answer += u", однако подгрузка не удалась: \n%s" % (returnExc())
					answer = answer % name
					if conflicts:
						conflicts = str.join(", ", conflicts)
						answer += u" Также, не удалось устранить следующие конфликты: %(conflicts)s."

			elif a[1] == u"удалить":
				if os.path.exists("./extensions/%s" % fullName):
					size = 0
					extensions = eval(read_file("dynamic/%s" % extFile))
					depList = findDeps(read_file("./extensions/%s" % fullName))
					try:
						for x in ("./extensions/%s" % fullName, "./help/%s" % name):
							size += os.path.getsize(x)
							os.remove(x)
						answer += u"Плагин «%(name)s» успешно удалён."
						if fullName in extensions.keys():
							del extensions[fullName]
							write_file("dynamic/%s" % extFile, str(extensions))
					except:
						answer += u"Удаление плагина «%(name)s» не удалось."

					if depList:
						for dep in depList:
							if os.path.exists(dep):
								size += os.path.getsize(dep)
								if not os.path.isdir(dep):
									os.remove(dep)
						depList = str.join(", ", depList)
						answer += u" Также были удалены: %(depList)s."
					size = byteFormat(size)
					answer += " Освобождённое место: %(size)s."
				else:
					answer = u"Плагин «%(name)s» не найден!"
			else:
				answer = u"Ошибка. Возможно, этого плагина нет в списке или вы указали несуществующий параметр."

		elif a[0] == u"upgrade":
			extensions = eval(read_file("dynamic/%s" % extFile))
			toUpdate = dict()
			for ext in extensions.keys():
				localVer = extensions[ext]
				remoteVer = findExtVer(read_url(svnUrl % "extensions/%s" % ext))
				if localVer != remoteVer:
					toUpdate[ext] = remoteVer
			if toUpdate:
				answer = "\nОбновлено %d плагинов: " % len(toUpdate) + str.join(", ", toUpdate)
				jDepList = []
				for ext in toUpdate.keys():
					name = ext[:-3]
					depList = findDeps(read_url(svnUrl % "extensions/%s" % ext))
					if depList:
						jDepList.extend(depList)
					urllib.urlretrieve(svnUrl % "extensions/%s" % ext, "extensions/%s" % ext)
					urllib.urlretrieve(svnUrl % "help/" + name, "help/%s" % name)
					getDeps(depList)
					extensions[ext] = toUpdate[ext]
					execfile("extensions/%s" % ext, globals())
				if jDepList:
					jDepList = str.join(", ", jDepList)
					answer += "\nТакже были установлены следующие зависимости: %(jDepList)s"
				answer = answer % vars()
				write_file("dynamic/%s" % extFile, str(extensions))

		reply(mType, source, answer % vars())

def extmanager_init():
	if not initialize_file(extFile, "{}"):
		delivery(u"Внимание! Не удалось создать extmanager.txt!")

command_handler(extManager, 100, "extmanager")

handler_register("02si", extmanager_init)<commit_msg>extmanager fix<commit_after># BS mark.1-55
# /* coding: utf-8 */

# BlackSmith Extension Manager
# This plugin distributed under Apache 2.0 license.
# (c) simpleApps, 2012.

## NOTICE:
##			All plugins that depend from another plugins or files (not help files that placed in help dir)
##			Must be contain this code: #-extmanager-depends:depend1;depend2;depend3-#
##			Where depend1, depend2 and depend3 are depends of this plugin.
import urllib

svnUrl = "http://blacksmith-bot.googlecode.com/svn/proposed/%s/"
extFile = "dynamic/extensions.txt"

def urlsplit(url):
	if url and url.count("/"):
		strippedUrl = url.rstrip("/")
		tailIndex = strippedUrl.rfind("/")
		head = strippedUrl[:tailIndex]
		tail = strippedUrl[tailIndex:]
		url = (head, tail)
	return url

def getSize(url):
	request = urllib.urlopen(url)
	return int(request.headers.get("Content-Length"))

def getDepsSize(depList):
	size = int()
	for dep in depList:
		size += getSize(svnUrl % dep)
	return size

def saveDeps(path):
	Dir = os.path.split(path)[0]
	if Dir and not os.path.exists(Dir):
		os.makedirs(Dir)
	return path

def getDeps(depList = [], plugin = None):
	if plugin:
		depList = findDeps(read_url(svnUrl % "extensions/%s" % plugin))
	if depList:
		for dep in depList:
			if dep.endswith(".dir"):
				Dir = dep[:-4]
				if not os.path.exists(Dir):
					os.makedirs(Dir)
			else:
				urllib.urlretrieve(svnUrl % dep, saveDeps(dep))

def findDeps(data, join = None):
	match = re.search("#-extmanager-depends:(.*)-#", data)
	if match:
		dep = match.group(1)
		depList = dep.split(";")
		if join:
			return str.join(join, depList)
		return depList

def findExtVer(data):
	match = re.search("#-extmanager-extVer:(.*)-#", data)
	if match:
		ver = match.group(1)
		return ver
	return "1.0"

def findConflicts(data):
	match = re.search("#-extmanager-conflict:(.*)-#", data)
	if match:
		rawConflicts = match.group(1)
		if rawConflicts.count(";"):
			return rawConflicts.split(";")
		return [rawConflicts]

def extManager(mType, source, args):
	if args:
		answer = str()
		a = args.split()
		name, fullName = a[0], a[0] + ".py"
		afterA0 = args[(args.find(" ") + 1):].strip()
		extList = re.findall("\">(.*\.py)
", read_url(svnUrl % "extensions")) #"
		extList = [x[:-3] for x in extList]

		if a[0] == u"лист":
			for x, y in enumerate(extList):
				answer +=  u"%i. %s;\n" % (x + 1, y)

		elif a[0] in extList and len(a) > 1:
			if a[1] in (u"лист", u"инфо", "установить"):
				data = read_url(svnUrl % "extensions/%s" % fullName)
				depList = findDeps(data)
				conflicts = findConflicts(data)
				if a[1] == u"инфо":
					pluginInfo = eval(read_url(svnUrl % ("help/" + a[0])).decode("utf-8"))
					commandList = [pluginInfo[x]["cmd"] for x in pluginInfo.keys()]
					if depList:
						jDepList = str.join(", ", depList)
						sizeOf = byteFormat(getDepsSize(depList) + getSize(svnUrl % "extensions/%s" % fullName))
					if conflicts:
						conflictList = str.join(", ", conflicts)
					commandList = str.join(", ", commandList)
					answer =\
						"\nПлагин: %(name)s.\nСодержит команды: %(commandList)s."
					if depList:
						answer +=\
							"\nДля плагина требуется: %(jDepList)s, после установки будет занятно примерно %(sizeOf)s."
					if conflicts:
						answer += " Также будут удалены: %(conflictList)s."
					answer = answer % vars()

				elif a[1] == u"установить":
					extensions = eval(read_file(extFile))
					urllib.urlretrieve(svnUrl % "extensions/%s" % fullName, "extensions/%s" % fullName)
					urllib.urlretrieve(svnUrl % "help/" + a[0], "help/%s" % a[0])
					getDeps(depList)
					extensions[fullName] = findExtVer(read_url(svnUrl % "extensions/%s" % fullName))
					write_file(extFile, str(extensions))
					if conflicts:
						for x in conflicts:
								if os.path.exists(x):
									try:
										os.remove(x)
										conflicts.remove(x)
									except:
										pass
								else:
									conflicts.remove(x)
					answer = u"Плагин «%s» успешно установлен"
					try:
						execfile("./extensions/%s" % fullName, globals())
						answer += " и подгружен. Возможно, понадобится перезапуск бота."
					except:
						answer += u", однако подгрузка не удалась: \n%s" % (returnExc())
					answer = answer % name
					if conflicts:
						conflicts = str.join(", ", conflicts)
						answer += u" Также, не удалось устранить следующие конфликты: %(conflicts)s."

			elif a[1] == u"удалить":
				if os.path.exists("./extensions/%s" % fullName):
					size = 0
					extensions = eval(read_file(extFile))
					depList = findDeps(read_file("./extensions/%s" % fullName))
					try:
						for x in ("./extensions/%s" % fullName, "./help/%s" % name):
							size += os.path.getsize(x)
							os.remove(x)
						answer += u"Плагин «%(name)s» успешно удалён."
						if fullName in extensions.keys():
							del extensions[fullName]
							write_file(extFile, str(extensions))
					except:
						answer += u"Удаление плагина «%(name)s» не удалось."

					if depList:
						for dep in depList:
							if os.path.exists(dep):
								size += os.path.getsize(dep)
								if not os.path.isdir(dep):
									os.remove(dep)
						depList = str.join(", ", depList)
						answer += u" Также были удалены: %(depList)s."
					size = byteFormat(size)
					answer += " Освобождённое место: %(size)s."
				else:
					answer = u"Плагин «%(name)s» не найден!"
			else:
				answer = u"Ошибка. Возможно, этого плагина нет в списке или вы указали несуществующий параметр."

		elif a[0] == u"upgrade":
			extensions = eval(read_file(extFile))
			toUpdate = dict()
			for ext in extensions.keys():
				localVer = extensions[ext]
				remoteVer = findExtVer(read_url(svnUrl % "extensions/%s" % ext))
				if localVer != remoteVer:
					toUpdate[ext] = remoteVer
			if toUpdate:
				answer = "\nОбновлено %d плагинов: " % len(toUpdate) + str.join(", ", toUpdate)
				jDepList = []
				for ext in toUpdate.keys():
					name = ext[:-3]
					depList = findDeps(read_url(svnUrl % "extensions/%s" % ext))
					if depList:
						jDepList.extend(depList)
					urllib.urlretrieve(svnUrl % "extensions/%s" % ext, "extensions/%s" % ext)
					urllib.urlretrieve(svnUrl % "help/" + name, "help/%s" % name)
					getDeps(depList)
					extensions[ext] = toUpdate[ext]
					execfile("extensions/%s" % ext, globals())
				if jDepList:
					jDepList = str.join(", ", jDepList)
					answer += "\nТакже были установлены следующие зависимости: %(jDepList)s"
				answer = answer % vars()
				write_file(extFile, str(extensions))

		reply(mType, source, answer % vars())

def extmanager_init():
	if not initialize_file(extFile, "{}"):
		delivery(u"Внимание! Не удалось создать extmanager.txt!")

command_handler(extManager, 100, "extmanager")

handler_register("02si", extmanager_init)<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

from django import forms

from djspace.registration.models.undergraduate import Undergraduate
from djspace.registration.models.graduate import Graduate, GRADUATE_DEGREE
from djspace.registration.models.professional import Professional
from djspace.registration.models.professor import Faculty
from djspace.registration.models.k12educator import K12Educator
from djspace.registration.models.base_models import YES_NO_DECLINE, RACES
from djspace.registration.models.base_models import UNDERGRADUATE_DEGREE

from djtools.fields import GENDER_CHOICES, BINARY_CHOICES, SALUTATION_TITLES

from localflavor.us.forms import USPhoneNumberField

class UndergraduateForm(forms.ModelForm):
    """
    A form to collect undergraduate information
    """

    birthdate = forms.DateField(
        label = "Birth date",
        widget=forms.TextInput(attrs={'placeholder': 'Format: 05/30/1993'})
    )
    citizen = forms.TypedChoiceField(
        choices = BINARY_CHOICES, widget = forms.RadioSelect()
    )
    rocket_comp = forms.TypedChoiceField(
        choices = BINARY_CHOICES, widget = forms.RadioSelect()
    )
    gender = forms.TypedChoiceField(
        choices = GENDER_CHOICES, widget = forms.RadioSelect()
    )
    disability = forms.TypedChoiceField(
        choices = YES_NO_DECLINE, widget = forms.RadioSelect()
    )
    race = forms.MultipleChoiceField(
        help_text = 'Check all that apply',
        choices = RACES,
        widget = forms.CheckboxSelectMultiple()
    )
    degree = forms.TypedChoiceField(
        choices = UNDERGRADUATE_DEGREE, widget = forms.RadioSelect()
    )
    phone = USPhoneNumberField(
        widget=forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'})
    )

    class Meta:
        model = Undergraduate
        fields = [
            'first','middle','last','citizen','rocket_comp','birthdate',
            'gender', 'disability','race','tribe','wsgc_school','major',
            'major_other', 'secondary_major_minor',
            'secondary_major_minor_other','student_id', 'gpa',
            'gpa_major','scale', 'CREDITS', 'graduation', 'degree',
            'highschool_name', 'highschool_city', 'highschool_state',
            'address', 'street', 'city', 'state', 'postal_code', 'phone',
            'email'
        ]
        '''exclude = (
            'salutation', 'maiden', 'additional', 'title_department',
            'webpage',
            'primary', 'primary_other', 'secondary', 'secondary_other',
            'wsgc_school_num', 'wsgc_advisor_salutation', 'wsgc_advisor_first',
            'wsgc_advisor_middle', 'wsgc_advisor_last',
            'wsgc_advisor_title_department', 'wsgc_advisor_email',
            'wsgc_advisor_confirm_email', 'wsgc_advisor_phone',
            'highschool_postal_code', 'degree',
        )'''
        widgets = {
            'webpage': forms.TextInput(attrs={'placeholder': 'eg. www.mywebsite.com'}),
            'graduation': forms.TextInput(attrs={'placeholder': 'eg. 05/2014'}),
            #wsgc
            'wsgc_advisor_phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            #highschool
            'gpa': forms.TextInput(attrs={'placeholder': 'eg. 3.87'}),
            'CREDITS': forms.TextInput(attrs={'placeholder': 'eg. 86'}),
            #college
            'scale': forms.TextInput(attrs={'placeholder': 'eg. 4'}),
            'gpa_major': forms.TextInput(attrs={'placeholder': 'eg. 3.87'}),
            'graduation': forms.TextInput(attrs={'placeholder': 'eg. 05/15'}),
            'year_in_school': forms.TextInput(attrs={'placeholder': 'eg. 2015'})
        }

    def clean(self):
        cleaned_data = super(UndergraduateForm, self).clean()
        citizen = cleaned_data.get("citizen")

        if citizen == "No":
            self._errors["citizen"] = self.error_class(["Must be Yes."])

        return cleaned_data

class GraduateForm(forms.ModelForm):
    """
    A form to collect graduate information
    """

    birthdate = forms.DateField(
        label = "Birth date",
        widget=forms.TextInput(attrs={'placeholder': 'Format: 05/30/1993'})
    )
    citizen = forms.TypedChoiceField(
        choices = BINARY_CHOICES, widget = forms.RadioSelect()
    )
    gender = forms.TypedChoiceField(
        choices = GENDER_CHOICES, widget = forms.RadioSelect()
    )
    disability = forms.TypedChoiceField(
        choices = YES_NO_DECLINE, widget = forms.RadioSelect()
    )
    race = forms.MultipleChoiceField(
        help_text = 'Check all that apply',
        choices = RACES, widget = forms.CheckboxSelectMultiple()
    )
    degree_program = forms.TypedChoiceField(
        choices = GRADUATE_DEGREE, widget = forms.RadioSelect()
    )

    class Meta:
        model = Graduate
        fields = [
            'first', 'middle', 'last', 'citizen', 'birthdate', 'gender',
            'disability', 'race', 'tribe', 'wsgc_school', 'degree_program',
            'degree_program_other', 'concentration_area', 'graduate_gpa',
            'graduate_scale', 'graduate_graduation_year', 'address',
            'street', 'city', 'state', 'postal_code', 'phone', 'email'
        ]
        '''exclude = (
            'salutation', 'rocket_comp', 'maiden', 'additional',
            'title_department',
            'primary', 'primary_other', 'secondary',
            'secondary_other', 'wsgc_school_num', 'wsgc_advisor_salutation',
            'wsgc_advisor_first', 'wsgc_advisor_middle', 'wsgc_advisor_last',
            'wsgc_advisor_title_department', 'wsgc_advisor_email',
            'wsgc_advisor_confirm_email'
        )'''
        widgets = {
            'webpage': forms.TextInput(attrs={'placeholder': 'eg. www.mywebsite.com'}),
            'phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            'birthdate': forms.TextInput(attrs={'placeholder': 'eg. 05/30/1993'}),
            'graduation': forms.TextInput(attrs={'placeholder': '05-15-2014'}),
            #wsgc
            'wsgc_advisor_phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            #college
            'graduate_gpa': forms.TextInput(attrs={'placeholder': 'eg. 3.87'}),
            'graduate_gpa_major': forms.TextInput(attrs={'placeholder': 'eg. 3.87'}),
            'graduate_CREDITS': forms.TextInput(attrs={'placeholder': 'eg. 86'}),
            'graduate_scale': forms.TextInput(attrs={'placeholder': 'eg. 4'}),
            'graduate_year_in_school': forms.TextInput(attrs={'placeholder': 'eg. 2015'}),
            'graduate_graduation': forms.TextInput(attrs={'placeholder': 'eg. 05-15-2014'})
        }

    def clean(self):
        cleaned_data = super(GraduateForm, self).clean()
        degree_program = cleaned_data.get("degree_program")
        degree_program_other = cleaned_data.get("degree_program_other")

        if degree_program == "Other":
            if degree_program_other == "":
                self._errors["degree_program_other"] = self.error_class(["Required field."])

        return cleaned_data

class ProfessionalForm(forms.ModelForm):
    """
    A form to collect professional information
    """

    birthdate = forms.DateField(
        label = "Birth date",
        widget=forms.TextInput(attrs={'placeholder': 'Format: 05/30/1993'})
    )
    gender = forms.TypedChoiceField(
        choices = GENDER_CHOICES, widget = forms.RadioSelect()
    )
    disability = forms.TypedChoiceField(
        choices = YES_NO_DECLINE, widget = forms.RadioSelect()
    )
    race = forms.MultipleChoiceField(
        help_text = 'Check all that apply',
        choices = RACES, widget = forms.CheckboxSelectMultiple()
    )

    class Meta:
        model = Professional
        fields = [
            'first', 'middle', 'last', 'citizen', 'birthdate',
            'gender','disability','race', 'wsgc_affiliate',
            'phone', 'email'
        ]
        exclude = (
            'salutation', 'maiden', 'additional', 'title_department',
            'webpage', 'secondary', 'secondary_other', 'tribe'
        )
        widgets = {
            'citizen': forms.RadioSelect(),
            'webpage': forms.TextInput(attrs={'placeholder': 'eg. www.mywebsite.com'}),
            'phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            'birthdate': forms.TextInput(attrs={'placeholder': 'eg. 05-30-1993'}),
            'graduation': forms.TextInput(attrs={'placeholder': '05-15-2014'})
        }

class FacultyForm(forms.ModelForm):
    """
    A form to collect faculty information
    """
    salutation = forms.CharField(
        widget=forms.Select(choices=SALUTATION_TITLES),
        required=False
    )
    gender = forms.TypedChoiceField(
        choices = GENDER_CHOICES, widget = forms.RadioSelect()
    )
    disability = forms.TypedChoiceField(
        choices = YES_NO_DECLINE, widget = forms.RadioSelect()
    )
    race = forms.MultipleChoiceField(
        help_text = 'Check all that apply',
        choices = RACES, widget = forms.CheckboxSelectMultiple()
    )
    #campus_phone = USPhoneNumberField(
    #    "Campus phone number",
    #    widget=forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'})
    #)

    class Meta:
        model = Faculty
        fields = [
            'salutation', 'first', 'middle', 'last', 'gender', 'disability',
            'race', 'tribe', 'citizen', 'department_program', 'title',
            'webpage', 'campus_email', 'address_1', 'address_2', 'city',
            'state', 'postal_code',
            #'campus_phone'
        ]
        widgets = {
            'citizen': forms.RadioSelect(),
            'webpage': forms.TextInput(attrs={'placeholder': 'eg. www.mywebsite.com'}),
            'phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            'birthdate': forms.TextInput(attrs={'placeholder': 'eg. 05-30-1993'}),
            'graduation': forms.TextInput(attrs={'placeholder': '05-15-2014'})
        }

class K12EducatorForm(forms.ModelForm):
    """
    A form to collect K12 information
    """

    class Meta:
        model = K12Educator
        exclude = (
            'salutation', 'title_department', 'webpage',
            'secondary', 'secondary_other'
        )
        widgets = {
            'webpage': forms.TextInput(attrs={'placeholder': 'eg. www.mywebsite.com'}),
            'phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            'birthdate': forms.TextInput(attrs={'placeholder': 'eg. 05-30-1993'}),
            'graduation': forms.TextInput(attrs={'placeholder': '05-15-2014'})
        }
<commit_msg>removed rocket competition field for real this time<commit_after># -*- coding: utf-8 -*-

from django import forms

from djspace.registration.models.undergraduate import Undergraduate
from djspace.registration.models.graduate import Graduate, GRADUATE_DEGREE
from djspace.registration.models.professional import Professional
from djspace.registration.models.professor import Faculty
from djspace.registration.models.k12educator import K12Educator
from djspace.registration.models.base_models import YES_NO_DECLINE, RACES
from djspace.registration.models.base_models import UNDERGRADUATE_DEGREE

from djtools.fields import GENDER_CHOICES, BINARY_CHOICES, SALUTATION_TITLES

from localflavor.us.forms import USPhoneNumberField

class UndergraduateForm(forms.ModelForm):
    """
    A form to collect undergraduate information
    """

    birthdate = forms.DateField(
        label = "Birth date",
        widget=forms.TextInput(attrs={'placeholder': 'Format: 05/30/1993'})
    )
    citizen = forms.TypedChoiceField(
        choices = BINARY_CHOICES, widget = forms.RadioSelect()
    )
    gender = forms.TypedChoiceField(
        choices = GENDER_CHOICES, widget = forms.RadioSelect()
    )
    disability = forms.TypedChoiceField(
        choices = YES_NO_DECLINE, widget = forms.RadioSelect()
    )
    race = forms.MultipleChoiceField(
        help_text = 'Check all that apply',
        choices = RACES,
        widget = forms.CheckboxSelectMultiple()
    )
    degree = forms.TypedChoiceField(
        choices = UNDERGRADUATE_DEGREE, widget = forms.RadioSelect()
    )
    phone = USPhoneNumberField(
        widget=forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'})
    )

    class Meta:
        model = Undergraduate
        fields = [
            'first','middle','last','citizen','birthdate',
            'gender', 'disability','race','tribe','wsgc_school','major',
            'major_other', 'secondary_major_minor',
            'secondary_major_minor_other','student_id', 'gpa',
            'gpa_major','scale', 'CREDITS', 'graduation', 'degree',
            'highschool_name', 'highschool_city', 'highschool_state',
            'address', 'street', 'city', 'state', 'postal_code', 'phone',
            'email'
        ]
        '''exclude = (
            'salutation', 'maiden', 'additional', 'title_department',
            'webpage',
            'primary', 'primary_other', 'secondary', 'secondary_other',
            'wsgc_school_num', 'wsgc_advisor_salutation', 'wsgc_advisor_first',
            'wsgc_advisor_middle', 'wsgc_advisor_last',
            'wsgc_advisor_title_department', 'wsgc_advisor_email',
            'wsgc_advisor_confirm_email', 'wsgc_advisor_phone',
            'highschool_postal_code', 'degree',
        )'''
        widgets = {
            'webpage': forms.TextInput(attrs={'placeholder': 'eg. www.mywebsite.com'}),
            'graduation': forms.TextInput(attrs={'placeholder': 'eg. 05/2014'}),
            #wsgc
            'wsgc_advisor_phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            #highschool
            'gpa': forms.TextInput(attrs={'placeholder': 'eg. 3.87'}),
            'CREDITS': forms.TextInput(attrs={'placeholder': 'eg. 86'}),
            #college
            'scale': forms.TextInput(attrs={'placeholder': 'eg. 4'}),
            'gpa_major': forms.TextInput(attrs={'placeholder': 'eg. 3.87'}),
            'graduation': forms.TextInput(attrs={'placeholder': 'eg. 05/15'}),
            'year_in_school': forms.TextInput(attrs={'placeholder': 'eg. 2015'})
        }

    def clean(self):
        cleaned_data = super(UndergraduateForm, self).clean()
        citizen = cleaned_data.get("citizen")

        if citizen == "No":
            self._errors["citizen"] = self.error_class(["Must be Yes."])

        return cleaned_data

class GraduateForm(forms.ModelForm):
    """
    A form to collect graduate information
    """

    birthdate = forms.DateField(
        label = "Birth date",
        widget=forms.TextInput(attrs={'placeholder': 'Format: 05/30/1993'})
    )
    citizen = forms.TypedChoiceField(
        choices = BINARY_CHOICES, widget = forms.RadioSelect()
    )
    gender = forms.TypedChoiceField(
        choices = GENDER_CHOICES, widget = forms.RadioSelect()
    )
    disability = forms.TypedChoiceField(
        choices = YES_NO_DECLINE, widget = forms.RadioSelect()
    )
    race = forms.MultipleChoiceField(
        help_text = 'Check all that apply',
        choices = RACES, widget = forms.CheckboxSelectMultiple()
    )
    degree_program = forms.TypedChoiceField(
        choices = GRADUATE_DEGREE, widget = forms.RadioSelect()
    )

    class Meta:
        model = Graduate
        fields = [
            'first', 'middle', 'last', 'citizen', 'birthdate', 'gender',
            'disability', 'race', 'tribe', 'wsgc_school', 'degree_program',
            'degree_program_other', 'concentration_area', 'graduate_gpa',
            'graduate_scale', 'graduate_graduation_year', 'address',
            'street', 'city', 'state', 'postal_code', 'phone', 'email'
        ]
        '''exclude = (
            'salutation', 'rocket_comp', 'maiden', 'additional',
            'title_department',
            'primary', 'primary_other', 'secondary',
            'secondary_other', 'wsgc_school_num', 'wsgc_advisor_salutation',
            'wsgc_advisor_first', 'wsgc_advisor_middle', 'wsgc_advisor_last',
            'wsgc_advisor_title_department', 'wsgc_advisor_email',
            'wsgc_advisor_confirm_email'
        )'''
        widgets = {
            'webpage': forms.TextInput(attrs={'placeholder': 'eg. www.mywebsite.com'}),
            'phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            'birthdate': forms.TextInput(attrs={'placeholder': 'eg. 05/30/1993'}),
            'graduation': forms.TextInput(attrs={'placeholder': '05-15-2014'}),
            #wsgc
            'wsgc_advisor_phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            #college
            'graduate_gpa': forms.TextInput(attrs={'placeholder': 'eg. 3.87'}),
            'graduate_gpa_major': forms.TextInput(attrs={'placeholder': 'eg. 3.87'}),
            'graduate_CREDITS': forms.TextInput(attrs={'placeholder': 'eg. 86'}),
            'graduate_scale': forms.TextInput(attrs={'placeholder': 'eg. 4'}),
            'graduate_year_in_school': forms.TextInput(attrs={'placeholder': 'eg. 2015'}),
            'graduate_graduation': forms.TextInput(attrs={'placeholder': 'eg. 05-15-2014'})
        }

    def clean(self):
        cleaned_data = super(GraduateForm, self).clean()
        degree_program = cleaned_data.get("degree_program")
        degree_program_other = cleaned_data.get("degree_program_other")

        if degree_program == "Other":
            if degree_program_other == "":
                self._errors["degree_program_other"] = self.error_class(["Required field."])

        return cleaned_data

class ProfessionalForm(forms.ModelForm):
    """
    A form to collect professional information
    """

    birthdate = forms.DateField(
        label = "Birth date",
        widget=forms.TextInput(attrs={'placeholder': 'Format: 05/30/1993'})
    )
    gender = forms.TypedChoiceField(
        choices = GENDER_CHOICES, widget = forms.RadioSelect()
    )
    disability = forms.TypedChoiceField(
        choices = YES_NO_DECLINE, widget = forms.RadioSelect()
    )
    race = forms.MultipleChoiceField(
        help_text = 'Check all that apply',
        choices = RACES, widget = forms.CheckboxSelectMultiple()
    )

    class Meta:
        model = Professional
        fields = [
            'first', 'middle', 'last', 'citizen', 'birthdate',
            'gender','disability','race', 'wsgc_affiliate',
            'phone', 'email'
        ]
        exclude = (
            'salutation', 'maiden', 'additional', 'title_department',
            'webpage', 'secondary', 'secondary_other', 'tribe'
        )
        widgets = {
            'citizen': forms.RadioSelect(),
            'webpage': forms.TextInput(attrs={'placeholder': 'eg. www.mywebsite.com'}),
            'phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            'birthdate': forms.TextInput(attrs={'placeholder': 'eg. 05-30-1993'}),
            'graduation': forms.TextInput(attrs={'placeholder': '05-15-2014'})
        }

class FacultyForm(forms.ModelForm):
    """
    A form to collect faculty information
    """
    salutation = forms.CharField(
        widget=forms.Select(choices=SALUTATION_TITLES),
        required=False
    )
    gender = forms.TypedChoiceField(
        choices = GENDER_CHOICES, widget = forms.RadioSelect()
    )
    disability = forms.TypedChoiceField(
        choices = YES_NO_DECLINE, widget = forms.RadioSelect()
    )
    race = forms.MultipleChoiceField(
        help_text = 'Check all that apply',
        choices = RACES, widget = forms.CheckboxSelectMultiple()
    )
    #campus_phone = USPhoneNumberField(
    #    "Campus phone number",
    #    widget=forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'})
    #)

    class Meta:
        model = Faculty
        fields = [
            'salutation', 'first', 'middle', 'last', 'gender', 'disability',
            'race', 'tribe', 'citizen', 'department_program', 'title',
            'webpage', 'campus_email', 'address_1', 'address_2', 'city',
            'state', 'postal_code',
            #'campus_phone'
        ]
        widgets = {
            'citizen': forms.RadioSelect(),
            'webpage': forms.TextInput(attrs={'placeholder': 'eg. www.mywebsite.com'}),
            'phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            'birthdate': forms.TextInput(attrs={'placeholder': 'eg. 05-30-1993'}),
            'graduation': forms.TextInput(attrs={'placeholder': '05-15-2014'})
        }

class K12EducatorForm(forms.ModelForm):
    """
    A form to collect K12 information
    """

    class Meta:
        model = K12Educator
        exclude = (
            'salutation', 'title_department', 'webpage',
            'secondary', 'secondary_other'
        )
        widgets = {
            'webpage': forms.TextInput(attrs={'placeholder': 'eg. www.mywebsite.com'}),
            'phone': forms.TextInput(attrs={'placeholder': 'eg. 123-456-7890'}),
            'birthdate': forms.TextInput(attrs={'placeholder': 'eg. 05-30-1993'}),
            'graduation': forms.TextInput(attrs={'placeholder': '05-15-2014'})
        }
<|endoftext|>


<commit_before>"""Reads the fasttext word embeddings

Visit: https://fasttext.cc/docs/en/english-vectors.html#format"""

import os
import numpy as np
import dataset.utils as utils
from . import fetcher

NAME = "wiki-news-300d-1M.vec"

def fetch_and_parse(data_dir):
    """
    Fetches and parses the fasttext word embeddings dataset. The dataset is
    also cached as a pickle for further calls.

    Args:
        data_dir (str): absolute path to the dir where datasets are stored

    Returns:
        voc (dict): bimap of word <-> id
        emb (numpy array): array of embeddings for each word in `voc`
    """
    fasttext_dir = fetcher.fetch(data_dir)

    return parse(fasttext_dir)

@utils.cache(2)
def parse(fasttext_dir):
    """
    Parses the fasttext word embeddings.

    Args:
        fastext_dir (str): absolute path to the extracted word embeddings

    Returns:
        voc (dict): bimap of word <-> id
        emb (numpy.array): array of embeddings for each word in `voc`
    """
    voc = {}
    emb = []
    first = True
    fasttext_path = os.path.join(fasttext_dir, NAME)
    with open(fasttext_path) as f:
        for line in f:
            # First line contains # words and embedding sizes, skip
            if first:
                first = False
                continue

            i = len(emb)
            parts = line.split(" ")
            voc[parts[0]] = i
            voc[i] = parts[0]
            emb.append([float(n) for n in parts[1:-1]])
    return voc, np.array(emb)
<commit_msg>dataset: add UNK token to default vocabulary<commit_after>"""Reads the fasttext word embeddings

Visit: https://fasttext.cc/docs/en/english-vectors.html#format"""

import os
import numpy as np
import dataset.utils as utils
from collections import defaultdict
from . import fetcher

NAME = "wiki-news-300d-1M.vec"

def fetch_and_parse(data_dir):
    """
    Fetches and parses the fasttext word embeddings dataset. The dataset is
    also cached as a pickle for further calls.

    Args:
        data_dir (str): absolute path to the dir where datasets are stored

    Returns:
        voc (dict): bimap of word <-> id
        emb (numpy array): array of embeddings for each word in `voc`
    """
    fasttext_dir = fetcher.fetch(data_dir)

    return parse(fasttext_dir)

@utils.cache(2)
def parse(fasttext_dir):
    """
    Parses the fasttext word embeddings.

    Args:
        fastext_dir (str): absolute path to the extracted word embeddings

    Returns:
        voc (dict): bimap of word <-> id
        emb (numpy.array): array of embeddings for each word in `voc`
    """
    # The first embedding is reserved for the UNK token
    emb = [[]]
    voc = defaultdict(int)
    voc[0] = "UNK"
    voc["UNK"] = 0

    first = True
    fasttext_path = os.path.join(fasttext_dir, NAME)
    with open(fasttext_path) as f:
        for line in f:
            # First line contains # words and embedding sizes, skip
            if first:
                first = False
                continue

            i = len(emb)
            parts = line.split(" ")
            voc[parts[0]] = i
            voc[i] = parts[0]
            emb.append([float(n) for n in parts[1:-1]])

    # We copy the last embedding for the UNK token
    emb[0] = emb[-1]
    return voc, np.array(emb)
<|endoftext|>


<commit_before>{
    'name' : 'Log\Notify Next Action changes',
    'version' : '1.0.0',
    'author' : 'Ivan Yelizariev',
    'category' : 'Sale',
    'website' : 'https://yelizariev.github.io',
    'price': 9.00,
    'currency': 'EUR',
    'depends' : ['crm'],
    'data':['data.xml'],
    'installable': True
}
<commit_msg>[DOC] small fixes<commit_after>{
    'name' : 'Log\Notify Next Action changes',
    'version' : '1.0.0',
    'author' : 'Ivan Yelizariev',
    'category' : 'Sale',
    'website' : 'https://yelizariev.github.io',
    'price': 9.00,
    'currency': 'EUR',
    'depends' : ['crm'],
    'images': ['images/lead.png'],
    'data':['data.xml'],
    'installable': True
}
<|endoftext|>


<commit_before>#!/usr/bin/env python
"""HTML tag annotator"""

from HTMLParser import HTMLParser

from annotator import *

import re

# create a subclass and override the handler methods
class HTMLOffsetParser(HTMLParser):

    text = ''
    index = 0

    space_chars = set([' ', '\n', '\t'])

    def __init__(self, tagset=None):
        HTMLParser.__init__(self)
        if tagset is not None:
            self.tagset = [tag.lower() for tag in tagset]
        else:
            self.tagset = []
        self.pending_tags = []
        self.tags = []

    def handle_starttag(self, tag, attrs):
        if tag in self.tagset:
            self.pending_tags.append(
                {'name': tag,
                 'start': self.index,
                 'attrs': attrs
                 })

    def handle_endtag(self, tag):
        if self.pending_tags[-1]['name'] == tag:
            pending_tag = self.pending_tags.pop()
            pending_tag['end'] = self.index
            self.tags.append(pending_tag)
        else:
            # Do we want to raise an error or log unexpected end tags?
            pass

    def handle_data(self, data):

        # If we are starting a paragraph and we don't have whitespace after
        # the end of the last paragraph, add a space.
        if (self.pending_tags and
            self.pending_tags[-1]['name'] == 'p' and
            self.text and
            self.text[-1] not in self.space_chars and
            data[0] not in self.space_chars):
            self.text += ' ' + data
            self.index += len(data) + 1
            self.pending_tags[-1]['start'] += 1
        else:
            self.text += data
            self.index += len(data)

class HTMLTagAnnotator:

    def __init__(self, tagset):
        if tagset is not None:
            self.tagset = [tag.lower() for tag in tagset]
        else:
            self.tagset = []
        self.tags = []

    def annotate(self, doc):
        """Annotate a document by taking the text and removing all HTML tags.
        Add spans for the tags in tagset. Need to run this first before other
        annotators because it transforms doc.text, so other offsets would become
        invalid.
        """

        parser = HTMLOffsetParser(self.tagset)

        parser.feed(doc.text)

        spans = []
        for tag in parser.tags:
            span = AnnoSpan(tag['start'],
                            tag['end'],
                            doc,
                            label=tag['name'])
            span.attrs = dict(tag['attrs'])
            spans.append(span)

        doc.tiers['html'] = AnnoTier(spans)
        doc.text = parser.text

        doc.tiers['html'].sort_spans()

        return doc
<commit_msg>check if pending_tags has any members before trying to access one<commit_after>#!/usr/bin/env python
"""HTML tag annotator"""

from HTMLParser import HTMLParser

from annotator import *

import re

# create a subclass and override the handler methods
class HTMLOffsetParser(HTMLParser):

    text = ''
    index = 0

    space_chars = set([' ', '\n', '\t'])

    def __init__(self, tagset=None):
        HTMLParser.__init__(self)
        if tagset is not None:
            self.tagset = [tag.lower() for tag in tagset]
        else:
            self.tagset = []
        self.pending_tags = []
        self.tags = []

    def handle_starttag(self, tag, attrs):
        if tag in self.tagset:
            self.pending_tags.append(
                {'name': tag,
                 'start': self.index,
                 'attrs': attrs
                 })

    def handle_endtag(self, tag):
        if self.pending_tags and self.pending_tags[-1]['name'] == tag:
            pending_tag = self.pending_tags.pop()
            pending_tag['end'] = self.index
            self.tags.append(pending_tag)
        else:
            # Do we want to raise an error or log unexpected end tags?
            pass

    def handle_data(self, data):

        # If we are starting a paragraph and we don't have whitespace after
        # the end of the last paragraph, add a space.
        if (self.pending_tags and
            self.pending_tags[-1]['name'] == 'p' and
            self.text and
            self.text[-1] not in self.space_chars and
            data[0] not in self.space_chars):
            self.text += ' ' + data
            self.index += len(data) + 1
            self.pending_tags[-1]['start'] += 1
        else:
            self.text += data
            self.index += len(data)

class HTMLTagAnnotator:

    def __init__(self, tagset):
        if tagset is not None:
            self.tagset = [tag.lower() for tag in tagset]
        else:
            self.tagset = []
        self.tags = []

    def annotate(self, doc):
        """Annotate a document by taking the text and removing all HTML tags.
        Add spans for the tags in tagset. Need to run this first before other
        annotators because it transforms doc.text, so other offsets would become
        invalid.
        """

        parser = HTMLOffsetParser(self.tagset)

        parser.feed(doc.text)

        spans = []
        for tag in parser.tags:
            span = AnnoSpan(tag['start'],
                            tag['end'],
                            doc,
                            label=tag['name'])
            span.attrs = dict(tag['attrs'])
            spans.append(span)

        doc.tiers['html'] = AnnoTier(spans)
        doc.text = parser.text

        doc.tiers['html'].sort_spans()

        return doc
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

import annotran
import annotran.languages.models as lang_models
import annotran.pages.models
import h
import h.accounts.models
import h.groups.models
import sqlalchemy as sa
from h.db import Base
from sqlalchemy.orm import exc
from sqlalchemy import and_

class Translation(Base):
    """
    Represents a translation in the database
    """
    __tablename__ = 'translation'

    id = sa.Column(sa.Integer, autoincrement=True, primary_key=True)

    page_id = sa.Column(sa.Integer, sa.ForeignKey(annotran.pages.models.Page.id))
    page = sa.orm.relationship('Page', backref='page_translation')

    language_id = sa.Column(sa.Integer, sa.ForeignKey(annotran.languages.models.Language.id))
    language = sa.orm.relationship('Language', backref='language_translation')

    group_id = sa.Column(sa.Integer, sa.ForeignKey(h.groups.models.Group.id))
    group = sa.orm.relationship('Group', backref='group_translation')

    def __init__(self, page, language, group):
        """
        Initializes a translation
        :param page: the page
        :param language: the language
        :param group: the group
        """
        if group and page and language:
            self.page_id = page.id
            self.language_id = language.id
            self.group_id = group.id

    @classmethod
    def get_translation(cls, page, language, group):
        """
        Retrieve a translation by page, language and group
        :param page: the page ID
        :param language: the language ID
        :param group: the group ID
        :return: a translation or None
        """
        try:
            if group is None:
                return cls.query.filter(
                    cls.page_id == page.id,
                    cls.language_id == language.id,
                    cls.group_id == -1).one()
            else:
                return cls.query.filter(
                    cls.page_id == page.id,
                    cls.language_id == language.id,
                    cls.group_id == group.id).one()
        except exc.NoResultFound:
            return None

    @classmethod
    def get_public_translations(cls, page):
        """
        Get a list of public translations for a page
        :param page: the page to query
        :return: a list of languages or an empty list
        """
        try:
            return lang_models.Language.query.\
                join(cls, and_(cls.page_id == page.id,
                               cls.group_id == -1,
                               lang_models.Language.id == cls.language_id)).\
                with_entities(lang_models.Language.id,
                              lang_models.Language.name,
                              lang_models.Language.pubid,
                              cls.group_id).all()
        except exc.NoResultFound:
            return None

    @classmethod
    def get_page_translations(cls, page):
        """
        Get a list of all translations for a page
        :param page: the page to query
        :return: a list of languages or an empty list
        """
        try:
            return lang_models.Language.query.\
                join(cls, and_(cls.page_id == page.id,
                               lang_models.Language.id == cls.language_id)).\
                with_entities(lang_models.Language.id,
                              lang_models.Language.name,
                              lang_models.Language.pubid,
                              cls.group_id).all()
        except exc.NoResultFound:
            return None

    '''
        We currently do not support deletion of added translation.
        This means once language is added for a page and a group, it will be there for all
        authorised users even without any translations on the page.
        The only way to remove such "empty" translations is for admin to directly remove them from the database.
    '''
    @classmethod
    def delete_translation(cls, page, language, group):
        """
        Delete all translation for a page, language and group
        :param page: the page ID
        :param language: the language ID
        :param group: the group ID
        :return: the result of the delete method or None
        """
        return None

    @classmethod
    def get_by_id(cls, id_):
        """
        Get a vote by ID
        :param id_: the ID to query
        :return: a vote or None
        """
        try:
            return cls.query.filter(
                cls.id == id_).one()
        except exc.NoResultFound:
            return None
<commit_msg>Designate composite keys and use ForeignKeyConstraint (instead of ForeignKey) to define composite foreign key.<commit_after># -*- coding: utf-8 -*-

import annotran
import annotran.languages.models as lang_models
import annotran.pages.models
import h
import h.accounts.models
import h.groups.models
import sqlalchemy as sa
from h.db import Base
from sqlalchemy.orm import exc
from sqlalchemy import and_

class Translation(Base):
    """
    Represents a translation in the database
    """
    __tablename__ = 'translation'

    page_id = sa.Column(sa.Integer, sa.ForeignKey(annotran.pages.models.Page.id), primary_key=True)
    page = sa.orm.relationship('Page', backref='page_translation')

    language_id = sa.Column(sa.Integer, sa.ForeignKey(annotran.languages.models.Language.id), primary_key=True)
    language = sa.orm.relationship('Language', backref='language_translation')

    group_id = sa.Column(sa.Integer, sa.ForeignKey(h.groups.models.Group.id), primary_key=True)
    group = sa.orm.relationship('Group', backref='group_translation')

    def __init__(self, page, language, group):
        """
        Initializes a translation
        :param page: the page
        :param language: the language
        :param group: the group
        """
        if group and page and language:
            self.page_id = page.id
            self.language_id = language.id
            self.group_id = group.id

    @classmethod
    def get_translation(cls, page, language, group):
        """
        Retrieve a translation by page, language and group
        :param page: the page ID
        :param language: the language ID
        :param group: the group ID
        :return: a translation or None
        """
        try:
            if group is None:
                return cls.query.filter(
                    cls.page_id == page.id,
                    cls.language_id == language.id,
                    cls.group_id == -1).one()
            else:
                return cls.query.filter(
                    cls.page_id == page.id,
                    cls.language_id == language.id,
                    cls.group_id == group.id).one()
        except exc.NoResultFound:
            return None

    @classmethod
    def get_public_translations(cls, page):
        """
        Get a list of public translations for a page
        :param page: the page to query
        :return: a list of languages or an empty list
        """
        try:
            return lang_models.Language.query.\
                join(cls, and_(cls.page_id == page.id,
                               cls.group_id == -1,
                               lang_models.Language.id == cls.language_id)).\
                with_entities(lang_models.Language.id,
                              lang_models.Language.name,
                              lang_models.Language.pubid,
                              cls.group_id).all()
        except exc.NoResultFound:
            return None

    @classmethod
    def get_page_translations(cls, page):
        """
        Get a list of all translations for a page
        :param page: the page to query
        :return: a list of languages or an empty list
        """
        try:
            return lang_models.Language.query.\
                join(cls, and_(cls.page_id == page.id,
                               lang_models.Language.id == cls.language_id)).\
                with_entities(lang_models.Language.id,
                              lang_models.Language.name,
                              lang_models.Language.pubid,
                              cls.group_id).all()
        except exc.NoResultFound:
            return None

    '''
        We currently do not support deletion of added translation.
        This means once language is added for a page and a group, it will be there for all
        authorised users even without any translations on the page.
        The only way to remove such "empty" translations is for admin to directly remove them from the database.
    '''
    @classmethod
    def delete_translation(cls, page, language, group):
        """
        Delete all translation for a page, language and group
        :param page: the page ID
        :param language: the language ID
        :param group: the group ID
        :return: the result of the delete method or None
        """
        return None

    @classmethod
    def get_by_id(cls, translation):
        """
        Get a vote by ID
        :param id_: the ID to query
        :return: a vote or None
        """
        try:
            return cls.query.filter(
                cls.page_id == translation.page_id,
                cls.language_id == translation.language_id,
                cls.group_id == translation.group_id).one()
        except exc.NoResultFound:
            return None
<|endoftext|>


<commit_before>import random
from simulation_event import AbstractSimulationEvent

class AbstractPeriodicRealityProcessor(AbstractSimulationEvent):
    PERIOD = 100
    def __init__(self, end_time=PERIOD):
        self.end_time = end_time
    def reset(self):
        self.end_time = self.PERIOD
    def set_ant_count(self, ant_count):
        self.ant_count = ant_count
    def process_end(self, reality, stats):
        raise NotImplementedError('%s did not implement a mandatory method' % (self.__class__.__name__,))

class AbstractPeriodicEdgeModifier(AbstractPeriodicRealityProcessor):
    def __init__(self, cost_trigger_level, cost_trigger_level_addition, **kwargs):
        super(AbstractPeriodicEdgeModifier, self).__init__(**kwargs)
        self.cost_trigger_level = cost_trigger_level
        self.cost_trigger_level_addition = cost_trigger_level
    def process_end(self, reality, stats):
        if reality.world.completion_level() >= self.cost_trigger_level:
            for edge in reality.world.edges:
                edge.cost = self.compute_new_cost(edge.cost)
        return self.__class__(self.cost_trigger_level + self.cost_trigger_level_addition, self.cost_trigger_level_addition, end_time=self.end_time+self.PERIOD), frozenset()
    def compute_new_cost(self, old_cost):
        raise NotImplementedError()

class EdgeMutator(AbstractPeriodicEdgeModifier):
    def compute_new_cost(self, old_cost):
        return old_cost * 2.0 / random.randint(1, 4)

class AbstractPeriodicEdgePheromoneModifier(AbstractPeriodicEdgeModifier):
    def __init__(self, trigger_level, **kwargs):
        super(AbstractPeriodicEdgeModifier, self).__init__(**kwargs)
        self.pheromone_trigger_level = trigger_level
    def process_end(self, reality, stats):
        changed_pheromone_edges = []
        avg_pheromone = reality.world.get_average_pheromone_level()
        max_pheromone = reality.world.get_max_pheromone_level()
        if max_pheromone/(avg_pheromone or 1) >= self.pheromone_trigger_level:
            for edge in reality.world.edges:
                for edge_end in (edge.a_end, edge.b_end):
                    new = self.compute_new_pheromone(edge_end.pheromone_level)
                    if edge_end.pheromone_level!=new:
                        changed_pheromone_edges.append(edge_end.edge)
                        edge_end.pheromone_level = new
        return self.__class__(self.pheromone_trigger_level, end_time=self.end_time+self.PERIOD), frozenset(changed_pheromone_edges)
    def compute_new_pheromone(self, old_pheromone_level):
        raise NotImplementedError()

<commit_msg>Fix edge cost mutator<commit_after>import random
from simulation_event import AbstractSimulationEvent

class AbstractPeriodicRealityProcessor(AbstractSimulationEvent):
    PERIOD = 100
    def __init__(self, end_time=PERIOD):
        self.end_time = end_time
    def reset(self):
        self.end_time = self.PERIOD
    def set_ant_count(self, ant_count):
        self.ant_count = ant_count
    def process_end(self, reality, stats):
        raise NotImplementedError('%s did not implement a mandatory method' % (self.__class__.__name__,))

class AbstractPeriodicEdgeModifier(AbstractPeriodicRealityProcessor):
    PERIOD = 10000
    def __init__(self, cost_trigger_level, cost_trigger_level_addition, **kwargs):
        super(AbstractPeriodicEdgeModifier, self).__init__(**kwargs)
        self.cost_trigger_level = cost_trigger_level
        self.cost_trigger_level_addition = cost_trigger_level_addition
    def process_end(self, reality, stats):
        next_trigger_level = self.cost_trigger_level
        #print 'processing %s' % (self.__class__.__name__,), self.cost_trigger_level, reality.world.completion_level()
        if reality.world.completion_level() >= self.cost_trigger_level:
            print self.__class__.__name__, 'processing edges at', reality.world.completion_level()
            next_trigger_level += self.cost_trigger_level_addition
            for edge in reality.world.edges:
                edge.cost = self.compute_new_cost(edge.cost)
        return self.__class__(
                next_trigger_level,
                self.cost_trigger_level_addition,
                end_time=self.end_time+self.PERIOD), frozenset()
    def compute_new_cost(self, old_cost):
        raise NotImplementedError()

class EdgeMutator(AbstractPeriodicEdgeModifier):
    def compute_new_cost(self, old_cost):
        return old_cost * 2.0 / random.randint(1, 4)

class AbstractPeriodicEdgePheromoneModifier(AbstractPeriodicEdgeModifier):
    def __init__(self, trigger_level, **kwargs):
        super(AbstractPeriodicEdgeModifier, self).__init__(**kwargs)
        self.pheromone_trigger_level = trigger_level
    def process_end(self, reality, stats):
        changed_pheromone_edges = []
        avg_pheromone = reality.world.get_average_pheromone_level()
        max_pheromone = reality.world.get_max_pheromone_level()
        if max_pheromone/(avg_pheromone or 1) >= self.pheromone_trigger_level:
            for edge in reality.world.edges:
                for edge_end in (edge.a_end, edge.b_end):
                    new = self.compute_new_pheromone(edge_end.pheromone_level)
                    if edge_end.pheromone_level!=new:
                        changed_pheromone_edges.append(edge_end.edge)
                        edge_end.pheromone_level = new
        return self.__class__(self.pheromone_trigger_level, end_time=self.end_time+self.PERIOD), frozenset(changed_pheromone_edges)
    def compute_new_pheromone(self, old_pheromone_level):
        raise NotImplementedError()

<|endoftext|>


<commit_before>#
# Copyright (C) 2013 Satoru SATOH <ssato @ redhat.com>
# License: MIT
#
from configobj import ConfigObj
from anyconfig.compat import StringIO, iteritems

import anyconfig.backend.base as Base
import sys

class ConfigObjParser(Base.ConfigParser):
    _type = "configobj"
    _priority = 10
    _supported = True
    _extensions = ["ini"]

    _load_opts = ["cls", "configspec", "encoding", "interpolation",
                  "raise_errors", "list_values", "create_empty", "file_error",
                  "stringify", "indent_type", "default_encoding", "unrepr",
                  "_inspec", ]
    _dump_opts = ["cls", "encoding", "list_values", "indent_type",
                  "default_encoding", "unrepr", "write_empty_values", ]

    @classmethod
    def load_impl(cls, config_fp, **kwargs):
        """
        :param config_fp:  Config file object
        :return: dict object holding config parameters
        """
        return ConfigObj(config_fp)

    @classmethod
    def dumps_impl(cls, data, **kwargs):
        """
        :param data: Data to dump :: dict
        """
        conf = ConfigObj(**Base.mk_opt_args(cls._dump_opts, kwargs))
        conf.update(data)
        conf.filename = None

        return '\n'.join(conf.write())

    @classmethod
    def dump_impl(cls, data, config_path, **kwargs):
        """
        :param data: Data to dump :: dict
        :param config_path: Dump destination file path
        """
        conf = ConfigObj(**Base.mk_opt_args(cls._dump_opts, kwargs))
        conf.update(data)

        conf.write(open(config_path, 'w'))

# vim:sw=4:ts=4:et:
<commit_msg>remove unused imports and simplified imports<commit_after>#
# Copyright (C) 2013 Satoru SATOH <ssato @ redhat.com>
# License: MIT
#
from configobj import ConfigObj
from anyconfig.backend.base import ConfigParser, mk_opt_args

class ConfigObjParser(ConfigParser):
    _type = "configobj"
    _priority = 10
    _supported = True
    _extensions = ["ini"]

    _load_opts = ["cls", "configspec", "encoding", "interpolation",
                  "raise_errors", "list_values", "create_empty", "file_error",
                  "stringify", "indent_type", "default_encoding", "unrepr",
                  "_inspec", ]
    _dump_opts = ["cls", "encoding", "list_values", "indent_type",
                  "default_encoding", "unrepr", "write_empty_values", ]

    @classmethod
    def load_impl(cls, config_fp, **kwargs):
        """
        :param config_fp:  Config file object
        :return: dict object holding config parameters
        """
        return ConfigObj(config_fp)

    @classmethod
    def dumps_impl(cls, data, **kwargs):
        """
        :param data: Data to dump :: dict
        """
        conf = ConfigObj(**mk_opt_args(cls._dump_opts, kwargs))
        conf.update(data)
        conf.filename = None

        return '\n'.join(conf.write())

    @classmethod
    def dump_impl(cls, data, config_path, **kwargs):
        """
        :param data: Data to dump :: dict
        :param config_path: Dump destination file path
        """
        conf = ConfigObj(**mk_opt_args(cls._dump_opts, kwargs))
        conf.update(data)

        conf.write(open(config_path, 'w'))

# vim:sw=4:ts=4:et:
<|endoftext|>


<commit_before># The Hazard Library
# Copyright (C) 2012-2017 GEM Foundation
#
# 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/>.
"""
Module :mod:`openquake.hazardlib.source.base` defines a base class for
seismic sources.
"""
import abc
from openquake.baselib.slots import with_slots
from openquake.baselib.python3compat import with_metaclass

@with_slots
class BaseSeismicSource(with_metaclass(abc.ABCMeta)):
    """
    Base class representing a seismic source, that is a structure generating
    earthquake ruptures.

    :param source_id:
        Some (numeric or literal) source identifier. Supposed to be unique
        within the source model.
    :param name:
        String, a human-readable name of the source.
    :param tectonic_region_type:
        Source's tectonic regime. See :class:`openquake.hazardlib.const.TRT`.
    """
    _slots_ = ['source_id', 'name', 'tectonic_region_type',
               'src_group_id', 'num_ruptures', 'seed', 'id']
    RUPTURE_WEIGHT = 1.  # overridden in (Multi)PointSource, AreaSource
    nsites = 1

    @abc.abstractproperty
    def MODIFICATIONS(self):
        pass

    @property
    def weight(self):
        """
        Determine the source weight from the number of ruptures, by
        multiplying with the scale factor RUPTURE_WEIGHT
        """
        if not self.num_ruptures:
            self.num_ruptures = self.count_ruptures()
        return self.num_ruptures * self.RUPTURE_WEIGHT * self.nsites

    def __init__(self, source_id, name, tectonic_region_type):
        self.source_id = source_id
        self.name = name
        self.tectonic_region_type = tectonic_region_type
        self.src_group_id = None  # set by the engine
        self.num_ruptures = 0  # set by the engine
        self.seed = None  # set by the engine
        self.id = None  # set by the engine

    @abc.abstractmethod
    def iter_ruptures(self):
        """
        Get a generator object that yields probabilistic ruptures the source
        consists of.

        :returns:
            Generator of instances of sublclass of :class:
            `~openquake.hazardlib.source.rupture.BaseProbabilisticRupture`.
        """

    @abc.abstractmethod
    def count_ruptures(self):
        """
        Return the number of ruptures that will be generated by the source.
        """

    @abc.abstractmethod
    def get_min_max_mag(self):
        """
        Return minimum and maximum magnitudes of the ruptures generated
        by the source.
        """

    @abc.abstractmethod
    def get_rupture_enclosing_polygon(self, dilation=0):
        """
        Get a polygon which encloses all the ruptures generated by the source.

        The rupture enclosing polygon is meant to be used in all hazard
        calculators to filter out sources whose ruptures the user wants
        to be neglected because they are too far from the locations
        of interest.

        For performance reasons, the ``get_rupture_enclosing_polygon()``
        should compute the polygon, without creating all the ruptures.
        The rupture enclosing polygon may not be necessarily the *minimum*
        enclosing polygon, but must guarantee that all ruptures are within
        the polygon.

        This method must be implemented by subclasses.

        :param dilation:
            A buffer distance in km to extend the polygon borders to.
        :returns:
            Instance of :class:`openquake.hazardlib.geo.polygon.Polygon`.
        """

    def get_bounding_box(self, dilation=0):
        """
        Returns the bounding box of all the ruptures generated by the source,
        enlarged by the integration distance (dilation).
        """
        return self.get_rupture_enclosing_polygon(dilation).get_bbox()

    def filter_sites_by_distance_to_source(self, integration_distance, sites):
        """
        Filter out sites from the collection that are further from the source
        than some arbitrary threshold.

        :param integration_distance:
            Distance in km representing a threshold: sites that are further
            than that distance from the closest rupture produced by the source
            should be excluded.
        :param sites:
            Instance of :class:`openquake.hazardlib.site.SiteCollection`
            to filter.
        :returns:
            Filtered :class:`~openquake.hazardlib.site.SiteCollection`.

        Method can be overridden by subclasses in order to achieve
        higher performance for a specific typology. Base class method calls
        :meth:`get_rupture_enclosing_polygon` with ``integration_distance``
        as a dilation value and then filters site collection by checking
        :meth:
        `containment <openquake.hazardlib.geo.polygon.Polygon.intersects>`
        of site locations.

        The main criteria for this method to decide whether a site should be
        filtered out or not is the minimum distance between the site and all
        the ruptures produced by the source. If at least one rupture is closer
        (in terms of great circle distance between surface projections) than
        integration distance to a site, it should not be filtered out. However,
        it is important not to make this method too computationally intensive.
        If short-circuits are taken, false positives are generally better than
        false negatives (it's better not to filter a site out if there is some
        uncertainty about its distance).
        """
        if integration_distance is None:  # no filtering
            return sites
        rup_enc_poly = self.get_rupture_enclosing_polygon(integration_distance)
        return sites.filter(rup_enc_poly.intersects(sites.mesh))

    def modify(self, modification, parameters):
        """
        Apply a single modificaton to the source parameters
        Reflects the modification method and calls it passing ``parameters``
        as keyword arguments.

        Modifications can be applied one on top of another. The logic
        of stacking modifications is up to a specific source implementation.

        :param modification:
            String name representing the type of modification.
        :param parameters:
            Dictionary of parameters needed for modification.
        :raises ValueError:
            If ``modification`` is missing from the attribute `MODIFICATIONS`.
        """
        if modification not in self.MODIFICATIONS:
            raise ValueError('Modification %s is not supported by %s' %
                             (modification, type(self).__name__))
        meth = getattr(self, 'modify_%s' % modification)
        meth(**parameters)

@with_slots
class ParametricSeismicSource(with_metaclass(abc.ABCMeta, BaseSeismicSource)):
    """
    Parametric Seismic Source generates earthquake ruptures from source
    parameters, and associated probabilities of occurrence are defined through
    a magnitude frequency distribution and a temporal occurrence model.

    :param mfd:
        Magnitude-Frequency distribution for the source.
        See :mod:`openquake.hazardlib.mfd`.
    :param rupture_mesh_spacing:
        The desired distance between two adjacent points in source's
        ruptures' mesh, in km. Mainly this parameter allows to balance
        the trade-off between time needed to compute the :meth:`distance
        <openquake.hazardlib.geo.surface.base.BaseQuadrilateralSurface.get_min_distance>`
        between the rupture surface and a site and the precision of that
        computation.
    :param magnitude_scaling_relationship:
        Instance of subclass of
        :class:`openquake.hazardlib.scalerel.base.BaseMSR` to
        describe how does the area of the rupture depend on magnitude and rake.
    :param rupture_aspect_ratio:
        Float number representing how much source's ruptures are more wide
        than tall. Aspect ratio of 1 means ruptures have square shape,
        value below 1 means ruptures stretch vertically more than horizontally
        and vice versa.
    :param temporal_occurrence_model:
        Instance of
        :class:`openquake.hazardlib.tom.PoissonTOM` defining temporal
        occurrence model for calculating rupture occurrence probabilities

    :raises ValueError:
        If either rupture aspect ratio or rupture mesh spacing is not positive
        (if not None).
    """

    _slots_ = BaseSeismicSource._slots_ + '''mfd rupture_mesh_spacing
    magnitude_scaling_relationship rupture_aspect_ratio
    temporal_occurrence_model'''.split()

    def __init__(self, source_id, name, tectonic_region_type, mfd,
                 rupture_mesh_spacing, magnitude_scaling_relationship,
                 rupture_aspect_ratio, temporal_occurrence_model):
        super(ParametricSeismicSource, self). \
            __init__(source_id, name, tectonic_region_type)

        if rupture_mesh_spacing is not None and not rupture_mesh_spacing > 0:
            raise ValueError('rupture mesh spacing must be positive')

        if rupture_aspect_ratio is not None and not rupture_aspect_ratio > 0:
            raise ValueError('rupture aspect ratio must be positive')

        self.mfd = mfd
        self.rupture_mesh_spacing = rupture_mesh_spacing
        self.magnitude_scaling_relationship = magnitude_scaling_relationship
        self.rupture_aspect_ratio = rupture_aspect_ratio
        self.temporal_occurrence_model = temporal_occurrence_model

    def get_annual_occurrence_rates(self, min_rate=0):
        """
        Get a list of pairs "magnitude -- annual occurrence rate".

        The list is taken from assigned MFD object
        (see :meth:`openquake.hazardlib.mfd.base.BaseMFD.get_annual_occurrence_rates`)
        with simple filtering by rate applied.

        :param min_rate:
            A non-negative value to filter magnitudes by minimum annual
            occurrence rate. Only magnitudes with rates greater than that
            are included in the result list.
        :returns:
            A list of two-item tuples -- magnitudes and occurrence rates.
        """
        return [(mag, occ_rate)
                for (mag, occ_rate) in self.mfd.get_annual_occurrence_rates()
                if min_rate is None or occ_rate > min_rate]

    def get_min_max_mag(self):
        """
        Get the minimum and maximum magnitudes of the ruptures generated
        by the source from the underlying MFD.
        """
        return self.mfd.get_min_max_mag()

    def __repr__(self):
        """
        String representation of a source, displaying the source class name
        and the source id.
        """
        return '<%s %s>' % (self.__class__.__name__, self.source_id)
<commit_msg>Set BaseSource.weight to 0<commit_after># The Hazard Library
# Copyright (C) 2012-2017 GEM Foundation
#
# 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/>.
"""
Module :mod:`openquake.hazardlib.source.base` defines a base class for
seismic sources.
"""
import abc
from openquake.baselib.slots import with_slots
from openquake.baselib.python3compat import with_metaclass

@with_slots
class BaseSeismicSource(with_metaclass(abc.ABCMeta)):
    """
    Base class representing a seismic source, that is a structure generating
    earthquake ruptures.

    :param source_id:
        Some (numeric or literal) source identifier. Supposed to be unique
        within the source model.
    :param name:
        String, a human-readable name of the source.
    :param tectonic_region_type:
        Source's tectonic regime. See :class:`openquake.hazardlib.const.TRT`.
    """
    _slots_ = ['source_id', 'name', 'tectonic_region_type',
               'src_group_id', 'num_ruptures', 'seed', 'id']
    RUPTURE_WEIGHT = 1.  # overridden in (Multi)PointSource, AreaSource
    nsites = 0  # must be overridden as instance attribute

    @abc.abstractproperty
    def MODIFICATIONS(self):
        pass

    @property
    def weight(self):
        """
        Determine the source weight from the number of ruptures, by
        multiplying with the scale factor RUPTURE_WEIGHT
        """
        if not self.num_ruptures:
            self.num_ruptures = self.count_ruptures()
        return self.num_ruptures * self.RUPTURE_WEIGHT * self.nsites

    def __init__(self, source_id, name, tectonic_region_type):
        self.source_id = source_id
        self.name = name
        self.tectonic_region_type = tectonic_region_type
        self.src_group_id = None  # set by the engine
        self.num_ruptures = 0  # set by the engine
        self.seed = None  # set by the engine
        self.id = None  # set by the engine

    @abc.abstractmethod
    def iter_ruptures(self):
        """
        Get a generator object that yields probabilistic ruptures the source
        consists of.

        :returns:
            Generator of instances of sublclass of :class:
            `~openquake.hazardlib.source.rupture.BaseProbabilisticRupture`.
        """

    @abc.abstractmethod
    def count_ruptures(self):
        """
        Return the number of ruptures that will be generated by the source.
        """

    @abc.abstractmethod
    def get_min_max_mag(self):
        """
        Return minimum and maximum magnitudes of the ruptures generated
        by the source.
        """

    @abc.abstractmethod
    def get_rupture_enclosing_polygon(self, dilation=0):
        """
        Get a polygon which encloses all the ruptures generated by the source.

        The rupture enclosing polygon is meant to be used in all hazard
        calculators to filter out sources whose ruptures the user wants
        to be neglected because they are too far from the locations
        of interest.

        For performance reasons, the ``get_rupture_enclosing_polygon()``
        should compute the polygon, without creating all the ruptures.
        The rupture enclosing polygon may not be necessarily the *minimum*
        enclosing polygon, but must guarantee that all ruptures are within
        the polygon.

        This method must be implemented by subclasses.

        :param dilation:
            A buffer distance in km to extend the polygon borders to.
        :returns:
            Instance of :class:`openquake.hazardlib.geo.polygon.Polygon`.
        """

    def get_bounding_box(self, dilation=0):
        """
        Returns the bounding box of all the ruptures generated by the source,
        enlarged by the integration distance (dilation).
        """
        return self.get_rupture_enclosing_polygon(dilation).get_bbox()

    def filter_sites_by_distance_to_source(self, integration_distance, sites):
        """
        Filter out sites from the collection that are further from the source
        than some arbitrary threshold.

        :param integration_distance:
            Distance in km representing a threshold: sites that are further
            than that distance from the closest rupture produced by the source
            should be excluded.
        :param sites:
            Instance of :class:`openquake.hazardlib.site.SiteCollection`
            to filter.
        :returns:
            Filtered :class:`~openquake.hazardlib.site.SiteCollection`.

        Method can be overridden by subclasses in order to achieve
        higher performance for a specific typology. Base class method calls
        :meth:`get_rupture_enclosing_polygon` with ``integration_distance``
        as a dilation value and then filters site collection by checking
        :meth:
        `containment <openquake.hazardlib.geo.polygon.Polygon.intersects>`
        of site locations.

        The main criteria for this method to decide whether a site should be
        filtered out or not is the minimum distance between the site and all
        the ruptures produced by the source. If at least one rupture is closer
        (in terms of great circle distance between surface projections) than
        integration distance to a site, it should not be filtered out. However,
        it is important not to make this method too computationally intensive.
        If short-circuits are taken, false positives are generally better than
        false negatives (it's better not to filter a site out if there is some
        uncertainty about its distance).
        """
        if integration_distance is None:  # no filtering
            return sites
        rup_enc_poly = self.get_rupture_enclosing_polygon(integration_distance)
        return sites.filter(rup_enc_poly.intersects(sites.mesh))

    def modify(self, modification, parameters):
        """
        Apply a single modificaton to the source parameters
        Reflects the modification method and calls it passing ``parameters``
        as keyword arguments.

        Modifications can be applied one on top of another. The logic
        of stacking modifications is up to a specific source implementation.

        :param modification:
            String name representing the type of modification.
        :param parameters:
            Dictionary of parameters needed for modification.
        :raises ValueError:
            If ``modification`` is missing from the attribute `MODIFICATIONS`.
        """
        if modification not in self.MODIFICATIONS:
            raise ValueError('Modification %s is not supported by %s' %
                             (modification, type(self).__name__))
        meth = getattr(self, 'modify_%s' % modification)
        meth(**parameters)

@with_slots
class ParametricSeismicSource(with_metaclass(abc.ABCMeta, BaseSeismicSource)):
    """
    Parametric Seismic Source generates earthquake ruptures from source
    parameters, and associated probabilities of occurrence are defined through
    a magnitude frequency distribution and a temporal occurrence model.

    :param mfd:
        Magnitude-Frequency distribution for the source.
        See :mod:`openquake.hazardlib.mfd`.
    :param rupture_mesh_spacing:
        The desired distance between two adjacent points in source's
        ruptures' mesh, in km. Mainly this parameter allows to balance
        the trade-off between time needed to compute the :meth:`distance
        <openquake.hazardlib.geo.surface.base.BaseQuadrilateralSurface.get_min_distance>`
        between the rupture surface and a site and the precision of that
        computation.
    :param magnitude_scaling_relationship:
        Instance of subclass of
        :class:`openquake.hazardlib.scalerel.base.BaseMSR` to
        describe how does the area of the rupture depend on magnitude and rake.
    :param rupture_aspect_ratio:
        Float number representing how much source's ruptures are more wide
        than tall. Aspect ratio of 1 means ruptures have square shape,
        value below 1 means ruptures stretch vertically more than horizontally
        and vice versa.
    :param temporal_occurrence_model:
        Instance of
        :class:`openquake.hazardlib.tom.PoissonTOM` defining temporal
        occurrence model for calculating rupture occurrence probabilities

    :raises ValueError:
        If either rupture aspect ratio or rupture mesh spacing is not positive
        (if not None).
    """

    _slots_ = BaseSeismicSource._slots_ + '''mfd rupture_mesh_spacing
    magnitude_scaling_relationship rupture_aspect_ratio
    temporal_occurrence_model'''.split()

    def __init__(self, source_id, name, tectonic_region_type, mfd,
                 rupture_mesh_spacing, magnitude_scaling_relationship,
                 rupture_aspect_ratio, temporal_occurrence_model):
        super(ParametricSeismicSource, self). \
            __init__(source_id, name, tectonic_region_type)

        if rupture_mesh_spacing is not None and not rupture_mesh_spacing > 0:
            raise ValueError('rupture mesh spacing must be positive')

        if rupture_aspect_ratio is not None and not rupture_aspect_ratio > 0:
            raise ValueError('rupture aspect ratio must be positive')

        self.mfd = mfd
        self.rupture_mesh_spacing = rupture_mesh_spacing
        self.magnitude_scaling_relationship = magnitude_scaling_relationship
        self.rupture_aspect_ratio = rupture_aspect_ratio
        self.temporal_occurrence_model = temporal_occurrence_model

    def get_annual_occurrence_rates(self, min_rate=0):
        """
        Get a list of pairs "magnitude -- annual occurrence rate".

        The list is taken from assigned MFD object
        (see :meth:`openquake.hazardlib.mfd.base.BaseMFD.get_annual_occurrence_rates`)
        with simple filtering by rate applied.

        :param min_rate:
            A non-negative value to filter magnitudes by minimum annual
            occurrence rate. Only magnitudes with rates greater than that
            are included in the result list.
        :returns:
            A list of two-item tuples -- magnitudes and occurrence rates.
        """
        return [(mag, occ_rate)
                for (mag, occ_rate) in self.mfd.get_annual_occurrence_rates()
                if min_rate is None or occ_rate > min_rate]

    def get_min_max_mag(self):
        """
        Get the minimum and maximum magnitudes of the ruptures generated
        by the source from the underlying MFD.
        """
        return self.mfd.get_min_max_mag()

    def __repr__(self):
        """
        String representation of a source, displaying the source class name
        and the source id.
        """
        return '<%s %s>' % (self.__class__.__name__, self.source_id)
<|endoftext|>


<commit_before>from bs4 import BeautifulSoup
from colorama import init, Fore, Style
from tqdm import tqdm
from .helpers import formatstr
import requests
import json
import argparse
import os

# parse positional and optional arguments
def parse_args():
    parser = argparse.ArgumentParser(
        description='Download docs right from the Command-Line')
    parser.add_argument(
        'query',
        metavar='QUERY',
        type=str,
        nargs='*',
        help='name of the project')
    parser.add_argument(
        '-o',
        '--output-directory',
        type=str,
        nargs=1,
        help='custom output directory'
        )
    parser.add_argument(
        '-c',
        '--color',
        help='colorize or style text',
        action='store_true')
    return parser

# parse the query into a searchable query
def generate_search_query(query):
    query = (' '.join(query)).replace(' ', '+')
    return query

# returns all titles from the search page
def title_scraper(query):
    project_titles = []                                                         #list of all project titles from search results
    project_descs = []
    url = 'https://readthedocs.org/search/?q='+str(query)+'&version=latest&type=project&language=en'
    source_code = requests.get(url).text
    soup = BeautifulSoup(source_code, 'html.parser')
    for p in soup.find_all('li', {'class': 'module-item'}):
        ps = p.find_all('p')

        try:
            title_p, desc_p, *_ = ps
        except ValueError:
            # some results have no description
            title_p = ps[0]
            desc = ''
        else:
            desc = desc_p.get_text()

        title = title_p.find('a').string
        desc = decode_description(desc)

        project_titles.append(title)
        project_descs.append(desc)
    return project_titles, project_descs

#converts titles into project names
def decode_title(result):
    result = result.lower()
    result = result.replace(" ","-").replace("_","-")
    return result

#house keeping for description
def decode_description(result):
    result = result.strip()
    result = result.replace('=','').replace('\r','').replace('\n','')
    return result

#prints first 10 project titles
def show_project_titles(result,numb,desc):
    string = str(numb)+'.'+str(result)
    formatstr(string, CYAN, colored)
    formatstr(desc, BLUE, colored)

#returns list of 10 project_names
def ten_titles(all_titles, all_descs):
    names = []                          #project name list
    numb = 1
    print('\n')
    for result, desc in zip(all_titles[:10], all_descs[:10]):
        name = decode_title(result)
        show_project_titles(result ,numb, desc)
        numb += 1
        names.append(name)
    return names

#Collects inputs from the user and returns selected project name
def get_project_input(names):
    while True:
        selection = int(input('> '))
        if selection <= len(names) and selection >= 1:
            break
        else:
            print("Choose a valid number!!")
    return names[selection -1]

#prints list of available file formats to download
def show_available_formats(file_types,numb):
    string = str(numb)+'.'+str(file_types)
    formatstr(string, CYAN, colored)

#returns links of available docs
def links_scraper(selected_project):
    file_types = []
    download_links = []
    numb = 1
    url = 'http://readthedocs.org/api/v1/project/'+str(selected_project)+'?format=json'
    json_obj = requests.get(url).text
    data = json.loads(json_obj)
    for k, v in data['downloads'].items():
        file_types.append(k)
        download_links.append(v)
    for result in file_types:
        show_available_formats(result,numb)
        numb += 1
    return download_links

#Collects inputs from the user and returns selected file's link
def get_file_input(download_links):
    while True:
        selection = int(input('> '))
        if selection <= len(download_links) and selection >= 1:
            break
        else:
            print("Choose a valid number!!")
    return download_links[selection -1]

# makes dir input workable
def generate_dir_query(dir):
    dir = ' '.join(dir)
    return dir

#downloads the required file
def download_file(selected_file,dir):
    json_url = 'https:' + str(selected_file)
    r = requests.get(json_url, allow_redirects=True, stream=True)           # to get content after redirection
    total_size = int(r.headers.get('content-length', 0));                   # Total size in bytes.
    file_url = r.url                                                        #redirected url
    file_name = file_url.split('/')[-1]
    if dir:                                                                 #if custom dir is mentioned
        dir = generate_dir_query(dir)
        string = "Directory =" + dir
        formatstr(string, MAGENTA, colored)
        if not os.path.exists(dir):                                         #Create directory is not exists
            os.makedirs(dir)
            string = "Created directory "+dir
            formatstr(string, MAGENTA, colored)
        print(GREEN)
        with open(dir+file_name, 'wb') as f:
          for data in tqdm(r.iter_content(), total=total_size, unit='B', unit_scale=True):
            f.write(data)
        print(u"\u2713 " + str(file_name) + " has been downloaded.\n" + Style.RESET_ALL)
    else:
        print(GREEN)
        with open(file_name, 'wb') as f:
            for data in tqdm(r.iter_content(), total=total_size, unit='B', unit_scale=True):
                f.write(data)
        print(u"\u2713" + str(file_name) + " has been downloaded.\n" + Style.RESET_ALL)

# the main function
def rtfd(query,dir):
    query = generate_search_query(query)
    all_titles, all_descs = title_scraper(query)
    req_projects_names =  ten_titles(all_titles, all_descs)
    print("\nChoose required project:")
    selected_project = get_project_input(req_projects_names)
    print("\nAvailable Formats:\n")
    download_links = links_scraper(selected_project)
    print("\nChoose format you wish to download:")
    selected_file = get_file_input(download_links)
    print("\nDownloading the selected format, please wait......\n")
    download_file(selected_file, dir)

def command_line():
    init()
    parser = parse_args()
    args = parser.parse_args()
    if not args.query:
        parser.print_help()
        exit()
    query = args.query                      #user query
    dir = args.output_directory             #custom user dir
    global colored
    colored = args.color                    #colorize the text
    rtfd(query,dir)

#GLOBAL VARIABLES
CYAN = Fore.CYAN + Style.BRIGHT             #list of colors to choose from
GREEN = Fore.GREEN + Style.BRIGHT
BLUE = Fore.BLUE + Style.BRIGHT
MAGENTA = Fore.MAGENTA + Style.BRIGHT
RED = Fore.RED + Style.BRIGHT

if __name__ == '__main__':
    command_line()
<commit_msg>Changes to improve UI<commit_after>from bs4 import BeautifulSoup
from colorama import init, Fore, Style
from tqdm import tqdm
from .helpers import formatstr
import requests
import json
import argparse
import os

# parse positional and optional arguments
def parse_args():
    parser = argparse.ArgumentParser(
        description='Download docs right from the Command-Line')
    parser.add_argument(
        'query',
        metavar='QUERY',
        type=str,
        nargs='*',
        help='name of the project')
    parser.add_argument(
        '-o',
        '--output-directory',
        type=str,
        nargs=1,
        help='custom output directory'
        )
    parser.add_argument(
        '-c',
        '--color',
        help='colorize or style text',
        action='store_true')
    return parser

# parse the query into a searchable query
def generate_search_query(query):
    query = (' '.join(query)).replace(' ', '+')
    return query

# returns all titles from the search page
def title_scraper(query):
    project_titles = []                                                         #list of all project titles from search results
    project_descs = []
    url = 'https://readthedocs.org/search/?q='+str(query)+'&version=latest&type=project&language=en'
    source_code = requests.get(url).text
    soup = BeautifulSoup(source_code, 'html.parser')
    for p in soup.find_all('li', {'class': 'module-item'}):
        ps = p.find_all('p')

        try:
            title_p, desc_p, *_ = ps
        except ValueError:
            # some results have no description
            title_p = ps[0]
            desc = 'Description not available.'
        else:
            desc = desc_p.get_text()
            desc = decode_description(desc)

        title = title_p.find('a').string
        project_titles.append(title)
        project_descs.append(desc)
    return project_titles, project_descs

#converts titles into project names
def decode_title(result):
    result = result.lower()
    result = result.replace(" ","-").replace("_","-")
    return result

#house keeping for description
def decode_description(result):
    result = result.strip()
    result = result.replace('=','').replace('\r','').replace('\n','').replace('...','')
    return result

#prints first 10 project titles
def show_project_titles(result,numb,desc):
    string = str(numb)+'> '+str(result)
    formatstr(string, CYAN, colored)
    formatstr(desc, BLUE, colored)
    print()

#returns list of 10 project_names
def ten_titles(all_titles, all_descs):
    names = []                          #project name list
    numb = 1
    print('\n')
    for result, desc in zip(all_titles[:10], all_descs[:10]):
        name = decode_title(result)
        show_project_titles(result ,numb, desc)
        numb += 1
        names.append(name)
    return names

#Collects inputs from the user and returns selected project name
def get_project_input(names):
    while True:
        selection = int(input('> '))
        if selection <= len(names) and selection >= 1:
            break
        else:
            print("Choose a valid number!!")
    return names[selection -1]

#prints list of available file formats to download
def show_available_formats(file_types,numb):
    string = str(numb)+'.'+str(file_types)
    formatstr(string, CYAN, colored)

#returns links of available docs
def links_scraper(selected_project):
    file_types = []
    download_links = []
    numb = 1
    url = 'http://readthedocs.org/api/v1/project/'+str(selected_project)+'?format=json'
    json_obj = requests.get(url).text
    data = json.loads(json_obj)
    for k, v in data['downloads'].items():
        file_types.append(k)
        download_links.append(v)
    for result in file_types:
        show_available_formats(result,numb)
        numb += 1
    return download_links

#Collects inputs from the user and returns selected file's link
def get_file_input(download_links):
    while True:
        selection = int(input('> '))
        if selection <= len(download_links) and selection >= 1:
            break
        else:
            print("Choose a valid number!!")
    return download_links[selection -1]

# makes dir input workable
def generate_dir_query(dir):
    dir = ' '.join(dir)
    return dir

#downloads the required file
def download_file(selected_file,dir):
    json_url = 'https:' + str(selected_file)
    r = requests.get(json_url, allow_redirects=True, stream=True)           # to get content after redirection
    total_size = int(r.headers.get('content-length', 0));                   # Total size in bytes.
    file_url = r.url                                                        #redirected url
    file_name = file_url.split('/')[-1]
    if dir:                                                                 #if custom dir is mentioned
        dir = generate_dir_query(dir)
        string = "Directory =" + dir
        formatstr(string, MAGENTA, colored)
        if not os.path.exists(dir):                                         #Create directory is not exists
            os.makedirs(dir)
            string = "Created directory "+dir
            formatstr(string, MAGENTA, colored)
        print(GREEN)
        with open(dir+file_name, 'wb') as f:
          for data in tqdm(r.iter_content(), total=total_size, unit='B', unit_scale=True):
            f.write(data)
        print(u"\u2713 " + str(file_name) + " has been downloaded.\n" + Style.RESET_ALL)
    else:
        print(GREEN)
        with open(file_name, 'wb') as f:
            for data in tqdm(r.iter_content(), total=total_size, unit='B', unit_scale=True):
                f.write(data)
        print(u"\u2713" + str(file_name) + " has been downloaded.\n" + Style.RESET_ALL)

# the main function
def rtfd(query,dir):
    query = generate_search_query(query)
    all_titles, all_descs = title_scraper(query)
    req_projects_names =  ten_titles(all_titles, all_descs)
    print("\nChoose required project:")
    selected_project = get_project_input(req_projects_names)
    print("\nAvailable Formats:\n")
    download_links = links_scraper(selected_project)
    print("\nChoose format you wish to download:")
    selected_file = get_file_input(download_links)
    print("\nDownloading the selected format, please wait......\n")
    download_file(selected_file, dir)

def command_line():
    init()
    parser = parse_args()
    args = parser.parse_args()
    if not args.query:
        parser.print_help()
        exit()
    query = args.query                      #user query
    dir = args.output_directory             #custom user dir
    global colored
    colored = args.color                    #colorize the text
    rtfd(query,dir)

#GLOBAL VARIABLES
CYAN = Fore.CYAN + Style.BRIGHT             #list of colors to choose from
GREEN = Fore.GREEN + Style.BRIGHT
BLUE = Fore.BLUE + Style.BRIGHT
MAGENTA = Fore.MAGENTA + Style.BRIGHT
RED = Fore.RED + Style.BRIGHT

if __name__ == '__main__':
    command_line()
<|endoftext|>