<commit_before>from django.db import models
from django.core.files.base import ContentFile
from picklefield.fields import PickledObjectField
from encrypted_fields import EncryptedCharField
from collections import Counter
from django.http import JsonResponse
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import api_view
from ipware.ip import get_ip
from random import randint, choice
import uuid
from polymorphic.models import PolymorphicModel
import json
from .fields import SeparatedValuesField
from datetime import datetime
from datetime import timedelta
from django.utils import timezone

class CaptchaToken(PolymorphicModel):
    # Superclass for tokens

    file = models.ImageField(upload_to='static/captchas/')
    # counter object that counts user proposals
    # to this captcha. If captcha is solved None is saved.
    proposals = PickledObjectField()
    resolved = models.BooleanField(default=False)
    captcha_type = models.CharField(max_length=128)
    unsolvable = models.BooleanField(default=False)

    def create(self, file_name, file_data, resolved):
        self.file.save(file_name, ContentFile(file_data))
        self.proposals = Counter()
        self.resolved = resolved

    def add_proposal(self, proposal):
        self.proposals[proposal] += 1
        self.save()

    def __str__(self):
        return str(self.id) + ", " + self.captcha_type + ", " + str(self.resolved)

class TextCaptchaToken(CaptchaToken):
    """docstring for TextCaptcha."""

    result = EncryptedCharField(max_length=256)

    def create(self, file_name, file_data, resolved, result='', unsolvable=False):
        super(TextCaptchaToken, self).create(file_name, file_data, resolved)
        self.result = result
        self.captcha_type = "text"
        return self

    # solves token if 3 matching proposals were made
    # marks token as unsolveable if more than 6 resolutions didn't result in
    # solved token
    def try_solve(self):
        # checks if there is a solution for a token based on saved proposals
        proposals = self.proposals
        most_common = proposals.most_common()
        num_proposoals = sum(proposals.values())

        if len(proposals.values()) >= 6:  # more than six different proposals
            self.unsolvable = True
            self.resolved = True
            self.save()
        elif num_proposoals >= 3:
            if most_common[0][1] >= 3:
                self.resolved = True
                self.result = most_common[0][0]
                self.save()

class ImageCaptchaToken(CaptchaToken):

    # The task is a category of pictures and it should be tested if the token belongs to it
    # The result just defines if the token belongs to the given category
    task = models.CharField(max_length=128)
    result = models.BooleanField(default=False)

    def create(self, file_name, file_data, resolved, task, result=False):
        super(ImageCaptchaToken, self).create(file_name, file_data, resolved)
        self.task = task
        if result == 'True':
            self.result = True
        else:
            self.result = False
        self.captcha_type = "image"
        return self

    # solves token if 4 matching proposals were made
    # marks token as unsolveable if more than 6 resolutions didn't result in
    # solved token
    def try_solve(self):
        proposals = self.proposals
        most_common = proposals.most_common()
        num_proposoals = sum(proposals.values())

        if num_proposoals >= 6:
            self.unsolvable = True
            self.resolved = True
            self.save()
        elif num_proposoals >= 4:
            if most_common[0][1] >= 4:
                self.resolved = True
                self.result = most_common[0][0]
                self.save()

class CaptchaSession(PolymorphicModel):
    # superclass for sessions

    session_key = models.CharField(
        primary_key=True, unique=True, max_length=256)

    origin = models.CharField(max_length=128)  # ip address

    session_type = models.CharField(max_length=128)

    session_length = models.DurationField()
    expiration_date = models.DateTimeField()

    is_solved = models.BooleanField()

    def create(self, remote_ip, session_type):
        # basic configuration for captcha sessions
        self.session_key = uuid.uuid4()
        self.origin = remote_ip
        self.session_type = session_type

        self.session_length = timedelta(minutes=30)
        self.expiration_date = timezone.now() + self.session_length

        self.is_solved = False

    def _any_parameter_unset(*keys):
        for key in keys:
            if not key:
                return True
        return False

    def expand_session(self):
        self.expiration_date = timezone.now() + self.session_length

    def is_expired(self):
        return timezone.now() > self.expiration_date

    # this method is used to ensure that a user has successfully solved the
    # session (and it is still active)
    def is_valid(self):
        return self.is_solved and not self.is_expired()

    # for debugging purposes
    def __str__(self):
        session_key = str(self.session_key)
        expiration_date = self.expiration_date.isoformat()
        time_until_expiration = str(self.expiration_date - timezone.now())
        is_solved = str(self.is_solved)
        is_valid = str(self.is_valid())
        return "session key: " + session_key + \
            ", expiration date: " + expiration_date + \
            ", time until expiration: " + time_until_expiration + \
            ", is solved: " + is_solved + \
            ", is valid: " + is_valid

class TextCaptchaSession(CaptchaSession):

    solved_captcha = models.ForeignKey(
        TextCaptchaToken,
        on_delete=models.PROTECT,
        limit_choices_to={'resolved': True},
        related_name='solved'
    )
    unsolved_captcha = models.ForeignKey(
        TextCaptchaToken,
        on_delete=models.PROTECT,
        limit_choices_to={'resolved': False},
        related_name='unsolved'
    )
    order = models.BooleanField()  # 0 -> solved unsolved 1 -> unsolved solved

    def create(self, remote_ip):
        super(TextCaptchaSession, self).create(remote_ip, 'textsession')
        self.solved_captcha, self.unsolved_captcha = self._get_random_captcha_pair()

        self.order = randint(0, 1)
        first_url, second_url = self._adjust_captchas_to_order()
        # create JsonResponse for WebApplication

        response = JsonResponse({'first_url': first_url,
                                 'second_url': second_url,
                                 'session_key': self.session_key,
                                 'type': 'text'})
        return self, response

    def validate(self, params):
        # checks if client solution for captcha is correct

        result = params.get('result', None).strip()

        try:
            first_result, second_result = result.split(' ')
        except:
            first_result, second_result = None, None
        if self._any_parameter_unset(self.session_key):
            return Response(status=status.HTTP_400_BAD_REQUEST)
        if self._any_parameter_unset(first_result, second_result):
            return JsonResponse({'valid': False})
        # validate input
        if self.order == 0 and self.solved_captcha.result.strip() == first_result.strip() or self.order == 1 and self.solved_captcha.result.strip() == second_result.strip():

            valid = True
            self.is_solved = True
            if self.order == 0:
                self.unsolved_captcha.add_proposal(second_result.strip())
            else:
                self.unsolved_captcha.add_proposal(first_result.strip())

            self.unsolved_captcha.try_solve()

        else:
            valid = False

        # choose new tokens if valid is false to prevent brute force
        if (valid == False):
            self.solved_captcha, self.unsolved_captcha = self._get_random_captcha_pair()
            first_url, second_url = self._adjust_captchas_to_order()
            self.save(force_update=True)

        return JsonResponse({'valid': valid,
                             'first_url': first_url,
                             'second_url': second_url,
                             'type': 'text'})

    def renew(self):
        # provides new tokens for a session
        self.expand_session()

        self.solved_captcha, self.unsolved_captcha = self._get_random_captcha_pair()
        first_url, second_url = self._adjust_captchas_to_order()
        self.save(force_update=True)
        return JsonResponse({'first_url': first_url,
                             'second_url': second_url,
                             'type': 'text'})

    @staticmethod
    def _get_random_captcha_pair():
        # get unsolved captcha_token
        text_tokens_unsolved = TextCaptchaToken.objects.all().filter(resolved=False)
        count_unsolved = text_tokens_unsolved.count()
        unsolved_captcha_index = randint(0, count_unsolved - 1)
        unsolved = text_tokens_unsolved[unsolved_captcha_index]
        # get solved captcha_token
        text_tokens_solved = TextCaptchaToken.objects.all().filter(resolved=True)
        count_solved = text_tokens_solved.count()
        solved_captcha_index = randint(0, count_solved - 1)
        solved = text_tokens_solved[solved_captcha_index]
        return solved, unsolved

    def _adjust_captchas_to_order(self):
        if self.order == 0:
            first_url = self.solved_captcha.file.url
            second_url = self.unsolved_captcha.file.url
        else:
            first_url = self.unsolved_captcha.file.url
            second_url = self.solved_captcha.file.url
        return first_url, second_url

class ImageCaptchaSession(CaptchaSession):

    # order is a list with 1->solved_captcha_token, 0->unsolved_captcha_token
    order = SeparatedValuesField()  # customField for saving lists in django

    # list with stored captcha_token
    image_token_list = SeparatedValuesField()
    # The task is a category of pictures and it should be tested if the tokens
    # of the session belong to it
    task = models.TextField(null=True)

    def create(self, remote_ip):
        super(ImageCaptchaSession, self).create(remote_ip, 'imagesession')

        self.order = self.create_order()
        self.task = self.choose_task()

        self.image_token_list = self.get_image_token_list()
        url_list = []
        for i in range(len(self.image_token_list)):
            url_list.append(self.image_token_list[i].file.url)

        response = JsonResponse({'url_list': url_list,
                                 'task': self.task,
                                 'session_key': self.session_key,
                                 'type': 'image'})

        return self, response

    def validate(self, params):
         # checks if client solution for captcha is correct

        # number of elements that are saved for each token in the
        # image_token_list
        number_of_elements_per_token = 3

        # transorm result string to bool array
        result_string = params.get('result', None)
        if self._any_parameter_unset(self.session_key, result_string):
            return Response(status=status.HTTP_400_BAD_REQUEST)

        result = result_string.split(",")
        for index, element in enumerate(result):
            if element == '1':
                result[index] = True
            else:
                result[index] = False

        self.image_token_list = self.rebuild_image_token_list(
            number_of_elements_per_token)

        solution_list = self.create_solution_list()

        # validation
        valid = True

        for index, element in enumerate(self.order):
            if(element == '1' and result[index] != solution_list[index]):
                valid = False

        # proposals
        if (valid == True):
            self.is_solved = True
            for index, element in enumerate(self.order):
                if (element == '0'):
                    current_token_pk = self.image_token_list[index][0]
                    current_token = CaptchaToken.objects.get(
                        pk=current_token_pk)
                    current_token.add_proposal(result[index])
                    current_token.try_solve()

        # choose new tokens if valid is false to prevent brute force
        if (valid == False):
            self.order = self.create_order()
            self.task = self.choose_task()
            self.image_token_list = self.get_image_token_list()
            url_list = []
            for i in range(len(self.image_token_list)):
                url_list.append(self.image_token_list[i].file.url)

            self.save(force_update=True)

        return JsonResponse({'valid': valid,
                             'url_list': url_list,
                             'type': 'image',
                             'task': self.task})

    def renew(self):
        # provides new tokens for a session
        self.expand_session()

        self.order = self.create_order()
        self.task = self.choose_task()
        self.image_token_list = self.get_image_token_list()
        url_list = []
        for i in range(len(self.image_token_list)):
            url_list.append(self.image_token_list[i].file.url)

        self.save(force_update=True)
        return JsonResponse({'url_list': url_list,
                             'task': self.task,
                             'type': 'image'})

    def get_image_token_list(self):
        token_list = []
        current_token = models.ForeignKey(
            ImageCaptchaToken,
            on_delete=models.PROTECT,
        )

        for boolean in self.order:
            if (boolean == 1):
                image_tokens = ImageCaptchaToken.objects.all().filter(
                    resolved=True).filter(task=self.task)
            else:
                image_tokens = ImageCaptchaToken.objects.all().filter(
                    resolved=False).filter(task=self.task)
            # if there are no unsolved tokens use solved tokens
            if not image_tokens:
                image_tokens = ImageCaptchaToken.objects.all().filter(
                    resolved=True).filter(task=self.task)
            count = image_tokens.count()
            current_token_index = randint(0, count - 1)
            current_token = image_tokens[current_token_index]
            token_list.append(current_token)
        return token_list

    @staticmethod
    def create_order():
        # create order with exactly 4 solved tokens, 1 -> solved, 0 -> unsolved
        order_list = [0] * 9
        i = 0
        while (i < 4):
            index_solved = randint(0, 8)
            if(order_list[index_solved] == 0):
                order_list[index_solved] = 1
                i += 1
        return order_list

    @staticmethod
    def choose_task():
        aux = ImageCaptchaToken.objects.all()
        count = aux.count()
        index = randint(0, count - 1)
        return aux[index].task

    def rebuild_image_token_list(self, number_of_elements_per_token):
        # custom field used for storing image_token_list doesnt save correct structure of ImageCaptchaToken
        # e.g. [<ImageCaptchaToken: 1155, image, True>] is saved as [1155, image, True]
        # workaround to rebuild normal structure

        rebuild_image_token_list = []
        auxlist = []
        i = 0
        for element in self.image_token_list:
            auxlist.append(element.strip())
            i += 1
            if (i == number_of_elements_per_token):
                rebuild_image_token_list.append(auxlist)
                auxlist = []
                i = 0
        return rebuild_image_token_list

    def create_solution_list(self):
        # results are not stored in image_token_list, so its necessary to get
        # them from db
        solution_list = []
        for token in self.image_token_list:
            solution_list.append(
                ImageCaptchaToken.objects.get(pk=token[0]).result)
        return solution_list
<commit_msg>fixed missing urls in response if valid == True<commit_after>from django.db import models
from django.core.files.base import ContentFile
from picklefield.fields import PickledObjectField
from encrypted_fields import EncryptedCharField
from collections import Counter
from django.http import JsonResponse
from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import api_view
from ipware.ip import get_ip
from random import randint, choice
import uuid
from polymorphic.models import PolymorphicModel
import json
from .fields import SeparatedValuesField
from datetime import datetime
from datetime import timedelta
from django.utils import timezone

class CaptchaToken(PolymorphicModel):
    # Superclass for tokens

    file = models.ImageField(upload_to='static/captchas/')
    # counter object that counts user proposals
    # to this captcha. If captcha is solved None is saved.
    proposals = PickledObjectField()
    resolved = models.BooleanField(default=False)
    captcha_type = models.CharField(max_length=128)
    unsolvable = models.BooleanField(default=False)

    def create(self, file_name, file_data, resolved):
        self.file.save(file_name, ContentFile(file_data))
        self.proposals = Counter()
        self.resolved = resolved

    def add_proposal(self, proposal):
        self.proposals[proposal] += 1
        self.save()

    def __str__(self):
        return str(self.id) + ", " + self.captcha_type + ", " + str(self.resolved)

class TextCaptchaToken(CaptchaToken):
    """docstring for TextCaptcha."""

    result = EncryptedCharField(max_length=256)

    def create(self, file_name, file_data, resolved, result='', unsolvable=False):
        super(TextCaptchaToken, self).create(file_name, file_data, resolved)
        self.result = result
        self.captcha_type = "text"
        return self

    # solves token if 3 matching proposals were made
    # marks token as unsolveable if more than 6 resolutions didn't result in
    # solved token
    def try_solve(self):
        # checks if there is a solution for a token based on saved proposals
        proposals = self.proposals
        most_common = proposals.most_common()
        num_proposoals = sum(proposals.values())

        if len(proposals.values()) >= 6:  # more than six different proposals
            self.unsolvable = True
            self.resolved = True
            self.save()
        elif num_proposoals >= 3:
            if most_common[0][1] >= 3:
                self.resolved = True
                self.result = most_common[0][0]
                self.save()

class ImageCaptchaToken(CaptchaToken):

    # The task is a category of pictures and it should be tested if the token belongs to it
    # The result just defines if the token belongs to the given category
    task = models.CharField(max_length=128)
    result = models.BooleanField(default=False)

    def create(self, file_name, file_data, resolved, task, result=False):
        super(ImageCaptchaToken, self).create(file_name, file_data, resolved)
        self.task = task
        if result == 'True':
            self.result = True
        else:
            self.result = False
        self.captcha_type = "image"
        return self

    # solves token if 4 matching proposals were made
    # marks token as unsolveable if more than 6 resolutions didn't result in
    # solved token
    def try_solve(self):
        proposals = self.proposals
        most_common = proposals.most_common()
        num_proposoals = sum(proposals.values())

        if num_proposoals >= 6:
            self.unsolvable = True
            self.resolved = True
            self.save()
        elif num_proposoals >= 4:
            if most_common[0][1] >= 4:
                self.resolved = True
                self.result = most_common[0][0]
                self.save()

class CaptchaSession(PolymorphicModel):
    # superclass for sessions

    session_key = models.CharField(
        primary_key=True, unique=True, max_length=256)

    origin = models.CharField(max_length=128)  # ip address

    session_type = models.CharField(max_length=128)

    session_length = models.DurationField()
    expiration_date = models.DateTimeField()

    is_solved = models.BooleanField()

    def create(self, remote_ip, session_type):
        # basic configuration for captcha sessions
        self.session_key = uuid.uuid4()
        self.origin = remote_ip
        self.session_type = session_type

        self.session_length = timedelta(minutes=30)
        self.expiration_date = timezone.now() + self.session_length

        self.is_solved = False

    def _any_parameter_unset(*keys):
        for key in keys:
            if not key:
                return True
        return False

    def expand_session(self):
        self.expiration_date = timezone.now() + self.session_length

    def is_expired(self):
        return timezone.now() > self.expiration_date

    # this method is used to ensure that a user has successfully solved the
    # session (and it is still active)
    def is_valid(self):
        return self.is_solved and not self.is_expired()

    # for debugging purposes
    def __str__(self):
        session_key = str(self.session_key)
        expiration_date = self.expiration_date.isoformat()
        time_until_expiration = str(self.expiration_date - timezone.now())
        is_solved = str(self.is_solved)
        is_valid = str(self.is_valid())
        return "session key: " + session_key + \
            ", expiration date: " + expiration_date + \
            ", time until expiration: " + time_until_expiration + \
            ", is solved: " + is_solved + \
            ", is valid: " + is_valid

class TextCaptchaSession(CaptchaSession):

    solved_captcha = models.ForeignKey(
        TextCaptchaToken,
        on_delete=models.PROTECT,
        limit_choices_to={'resolved': True},
        related_name='solved'
    )
    unsolved_captcha = models.ForeignKey(
        TextCaptchaToken,
        on_delete=models.PROTECT,
        limit_choices_to={'resolved': False},
        related_name='unsolved'
    )
    order = models.BooleanField()  # 0 -> solved unsolved 1 -> unsolved solved

    def create(self, remote_ip):
        super(TextCaptchaSession, self).create(remote_ip, 'textsession')
        self.solved_captcha, self.unsolved_captcha = self._get_random_captcha_pair()

        self.order = randint(0, 1)
        first_url, second_url = self._adjust_captchas_to_order()
        # create JsonResponse for WebApplication

        response = JsonResponse({'first_url': first_url,
                                 'second_url': second_url,
                                 'session_key': self.session_key,
                                 'type': 'text'})
        return self, response

    def validate(self, params):
        # checks if client solution for captcha is correct

        result = params.get('result', None).strip()

        try:
            first_result, second_result = result.split(' ')
        except:
            first_result, second_result = None, None
        if self._any_parameter_unset(self.session_key):
            return Response(status=status.HTTP_400_BAD_REQUEST)
        if self._any_parameter_unset(first_result, second_result):
            return JsonResponse({'valid': False})
        # validate input
        if self.order == 0 and self.solved_captcha.result.strip() == first_result.strip() or self.order == 1 and self.solved_captcha.result.strip() == second_result.strip():

            valid = True
            self.is_solved = True
            if self.order == 0:
                self.unsolved_captcha.add_proposal(second_result.strip())
            else:
                self.unsolved_captcha.add_proposal(first_result.strip())

            self.unsolved_captcha.try_solve()

        else:
            valid = False

        # choose new tokens if valid is false to prevent brute force
        if (valid == False):
            self.solved_captcha, self.unsolved_captcha = self._get_random_captcha_pair()
            first_url, second_url = self._adjust_captchas_to_order()
            self.save(force_update=True)
	else:
	    first_url, second_url = self._adjust_captchas_to_order()

	return JsonResponse({'valid': valid,
                             'first_url': first_url,
                             'second_url': second_url,
                             'type': 'text'})

    def renew(self):
        # provides new tokens for a session
        self.expand_session()

        self.solved_captcha, self.unsolved_captcha = self._get_random_captcha_pair()
        first_url, second_url = self._adjust_captchas_to_order()
        self.save(force_update=True)
        return JsonResponse({'first_url': first_url,
                             'second_url': second_url,
                             'type': 'text'})

    @staticmethod
    def _get_random_captcha_pair():
        # get unsolved captcha_token
        text_tokens_unsolved = TextCaptchaToken.objects.all().filter(resolved=False)
        count_unsolved = text_tokens_unsolved.count()
        unsolved_captcha_index = randint(0, count_unsolved - 1)
        unsolved = text_tokens_unsolved[unsolved_captcha_index]
        # get solved captcha_token
        text_tokens_solved = TextCaptchaToken.objects.all().filter(resolved=True)
        count_solved = text_tokens_solved.count()
        solved_captcha_index = randint(0, count_solved - 1)
        solved = text_tokens_solved[solved_captcha_index]
        return solved, unsolved

    def _adjust_captchas_to_order(self):
	# returns iamage urls for one solved and one unsolved CaptchaToken and returns them acoording to the order
        if self.order == 0:
            first_url = self.solved_captcha.file.url
            second_url = self.unsolved_captcha.file.url
        else:
            first_url = self.unsolved_captcha.file.url
            second_url = self.solved_captcha.file.url
        return first_url, second_url

class ImageCaptchaSession(CaptchaSession):

    # order is a list with 1->solved_captcha_token, 0->unsolved_captcha_token
    order = SeparatedValuesField()  # customField for saving lists in django

    # list with stored captcha_token
    image_token_list = SeparatedValuesField()
    # The task is a category of pictures and it should be tested if the tokens
    # of the session belong to it
    task = models.TextField(null=True)

    def create(self, remote_ip):
        super(ImageCaptchaSession, self).create(remote_ip, 'imagesession')

        self.order = self.create_order()
        self.task = self.choose_task()

        self.image_token_list = self.get_image_token_list()

	# create list of image urls to send in response
        url_list = []
        for i in range(len(self.image_token_list)):
            url_list.append(self.image_token_list[i].file.url)
        response = JsonResponse({'url_list': url_list,
                                 'task': self.task,
                                 'session_key': self.session_key,
                                 'type': 'image'})

        return self, response

    def validate(self, params):
        # checks if client solution for captcha is correct

        # number of elements that are saved for each token in the
        # image_token_list
        number_of_elements_per_token = 3

        # transorm result string to bool array
        result_string = params.get('result', None)
        if self._any_parameter_unset(self.session_key, result_string):
            return Response(status=status.HTTP_400_BAD_REQUEST)

        result = result_string.split(",")
        for index, element in enumerate(result):
            if element == '1':
                result[index] = True
            else:
                result[index] = False

        self.image_token_list = self.rebuild_image_token_list(
            number_of_elements_per_token)

        solution_list = self.create_solution_list()

        # validation
        valid = True

        for index, element in enumerate(self.order):
            if(element == '1' and result[index] != solution_list[index]):
                valid = False

        # proposals
        if (valid == True):
            self.is_solved = True
            for index, element in enumerate(self.order):
                if (element == '0'):
                    current_token_pk = self.image_token_list[index][0]
                    current_token = CaptchaToken.objects.get(
                        pk=current_token_pk)
                    current_token.add_proposal(result[index])
                    current_token.try_solve()

	if (valid == False):
           # choose new tokens if valid is false to prevent brute force
           self.order = self.create_order()
           self.task = self.choose_task()
           self.image_token_list = self.get_image_token_list()
	   url_list = []
           for i in range(len(self.image_token_list)):
               url_list.append(self.image_token_list[i].file.url)
	else:
	    # create list of recent image urls to send in response when valid is true
	    url_list = []
	    # get image urls by the token id saved in image_token_list
            for index in range(len(self.image_token_list)):
		current_token_pk = self.image_token_list[index][0]
		current_token = ImageCaptchaToken.objects.get(pk=current_token_pk)
		url = current_token.file.url
        	url_list.append(url)

        return JsonResponse({'valid': valid,
                             'url_list': url_list,
                             'type': 'image',
                             'task': self.task})

    def renew(self):
        # provides new tokens for a session
        self.expand_session()

        self.order = self.create_order()
        self.task = self.choose_task()
        self.image_token_list = self.get_image_token_list()
        url_list = []
        for i in range(len(self.image_token_list)):
            url_list.append(self.image_token_list[i].file.url)

        self.save(force_update=True)
        return JsonResponse({'url_list': url_list,
                             'task': self.task,
                             'type': 'image'})

    def get_image_token_list(self):
        token_list = []
        current_token = models.ForeignKey(
            ImageCaptchaToken,
            on_delete=models.PROTECT,
        )

        for boolean in self.order:
            if (boolean == 1):
                image_tokens = ImageCaptchaToken.objects.all().filter(
                    resolved=True).filter(task=self.task)
            else:
                image_tokens = ImageCaptchaToken.objects.all().filter(
                    resolved=False).filter(task=self.task)
            # if there are no unsolved tokens use solved tokens
            if not image_tokens:
                image_tokens = ImageCaptchaToken.objects.all().filter(
                    resolved=True).filter(task=self.task)
            count = image_tokens.count()
            current_token_index = randint(0, count - 1)
            current_token = image_tokens[current_token_index]
            token_list.append(current_token)
        return token_list

    @staticmethod
    def create_order():
        # create order with exactly 4 solved tokens, 1 -> solved, 0 -> unsolved
        order_list = [0] * 9
        i = 0
        while (i < 4):
            index_solved = randint(0, 8)
            if(order_list[index_solved] == 0):
                order_list[index_solved] = 1
                i += 1
        return order_list

    @staticmethod
    def choose_task():
        aux = ImageCaptchaToken.objects.all()
        count = aux.count()
        index = randint(0, count - 1)
        return aux[index].task

    def rebuild_image_token_list(self, number_of_elements_per_token):
        # custom field used for storing image_token_list doesnt save correct structure of ImageCaptchaToken
        # e.g. [<ImageCaptchaToken: 1155, image, True>] is saved as [1155, image, True]
        # workaround to rebuild normal structure

        rebuild_image_token_list = []
        auxlist = []
        i = 0
        for element in self.image_token_list:
            auxlist.append(element.strip())
            i += 1
            if (i == number_of_elements_per_token):
                rebuild_image_token_list.append(auxlist)
                auxlist = []
                i = 0
        return rebuild_image_token_list

    def create_solution_list(self):
        # results are not stored in image_token_list, so its necessary to get
        # them from db
        solution_list = []
        for token in self.image_token_list:
            solution_list.append(
                ImageCaptchaToken.objects.get(pk=token[0]).result)
        return solution_list
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

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

from .. import base
from girder.api import access
from girder.api.describe import Description, describeRoute
from girder.api.rest import Resource, RestException
from girder.constants import SettingKey, SettingDefault

testServer = None

def setUpModule():
    global testServer
    testServer = base.startServer()

def tearDownModule():
    base.stopServer()

class DummyResource(Resource):
    def __init__(self):
        super(DummyResource, self).__init__()
        self.route('GET', (':wc1', 'literal1'), self.handler)
        self.route('GET', (':wc1', 'literal2'), self.handler)
        self.route('GET', (':wc1', ':wc2'), self.handler)
        self.route('GET', (':wc1', 'literal1'), self.handler)
        self.route('GET', ('literal1', 'literal2'), self.handler)
        self.route('GET', (':wc1', 'admin'), self.handler)
        self.route('PATCH', (':id', 'patchy'), self.handler)
        self.route('GET', ('test', ), self.handler)
        self.route('PUT', ('test', ), self.handler)
        self.route('POST', ('test', ), self.handler)
        self.route('DELETE', ('test', ), self.handler)
        self.route('PATCH', ('test', ), self.handler)

    @access.public
    @describeRoute(
        Description('Dummy handler.')
    )
    def handler(self, **kwargs):
        return kwargs
    # We want to test adding and removing documentation when we add and remove
    # routes.

class RoutesTestCase(base.TestCase):
    """
    Unit tests of the routing system of REST Resources.
    """
    def testRouteSystem(self):
        dummy = DummyResource()

        # Bad route should give a useful exception.
        exc = None
        try:
            dummy.handleRoute('GET', (), {})
        except RestException as e:
            exc = e.message
        self.assertEqual(exc, 'No matching route for "GET "')

        # Make sure route ordering is correct; literals before wildcard tokens
        r = dummy.handleRoute('GET', ('literal1', 'foo'), {})
        self.assertEqual(r, {'wc1': 'literal1', 'wc2': 'foo', 'params': {}})

        r = dummy.handleRoute('GET', ('literal1', 'literal2'), {})
        self.assertEqual(r, {'params': {}})

        r = dummy.handleRoute('PATCH', ('guid', 'patchy'), {})
        self.assertEqual(r, {'id': 'guid', 'params': {}})

        # Add a new route with a new method
        dummy.route('DUMMY', (':id', 'dummy'), dummy.handler)
        r = dummy.handleRoute('DUMMY', ('guid', 'dummy'), {})
        self.assertEqual(r, {'id': 'guid', 'params': {}})

        registeredHandler = dummy.getRouteHandler('DUMMY', (':id', 'dummy'))
        # The handler method cannot be compared directly with `is`, but its name and behavior can be
        # examined
        self.assertEqual(registeredHandler.__name__, dummy.handler.__name__)
        self.assertEqual(registeredHandler(foo=42), {'foo': 42})

        # Now remove the route
        dummy.removeRoute('DUMMY', (':id', 'dummy'))
        self.assertRaises(RestException, dummy.handleRoute, 'DUMMY', ('guid', 'dummy'), {})

    def testCORS(self):
        testServer.root.api.v1.dummy = DummyResource()

        # When no origin header is passed, we shouldn't receive CORS headers
        resp = self.request(path='/dummy/test')
        self.assertStatusOk(resp)
        self.assertFalse('Access-Control-Allow-Origin' in resp.headers)
        self.assertFalse('Access-Control-Allow-Credentials' in resp.headers)

        # If no origins are allowed, we should not get an allow origin header
        resp = self.request(path='/dummy/test', additionalHeaders=[
            ('Origin', 'http://foo.com')
        ])
        self.assertStatusOk(resp)
        self.assertFalse('Access-Control-Allow-Origin' in resp.headers)

        # If we allow some origins, we should get the corresponding header
        self.model('setting').set(SettingKey.CORS_ALLOW_ORIGIN,
                                  'http://kitware.com')
        resp = self.request(path='/dummy/test', additionalHeaders=[
            ('Origin', 'http://foo.com')
        ])
        self.assertEqual(resp.headers['Access-Control-Allow-Origin'],
                         'http://kitware.com')
        self.assertEqual(resp.headers['Access-Control-Allow-Credentials'],
                         'true')

        # Simulate a preflight request; we should get back several headers
        self.model('setting').set(SettingKey.CORS_ALLOW_METHODS, 'POST')
        resp = self.request(
            path='/dummy/test', method='OPTIONS', additionalHeaders=[
                ('Origin', 'http://foo.com')
            ], isJson=False
        )
        self.assertStatusOk(resp)
        self.assertEqual(self.getBody(resp), '')
        self.assertEqual(resp.headers['Access-Control-Allow-Origin'],
                         'http://kitware.com')
        self.assertEqual(resp.headers['Access-Control-Allow-Credentials'],
                         'true')
        self.assertEqual(resp.headers['Access-Control-Allow-Headers'],
                         SettingDefault.defaults[SettingKey.CORS_ALLOW_HEADERS])
        self.assertEqual(resp.headers['Access-Control-Allow-Methods'], 'POST')

        # Set multiple allowed origins
        self.model('setting').set(SettingKey.CORS_ALLOW_ORIGIN,
                                  'http://foo.com, http://bar.com')
        resp = self.request(
            path='/dummy/test', method='GET', additionalHeaders=[
                ('Origin', 'http://bar.com')
            ], isJson=False)
        self.assertEqual(resp.headers['Access-Control-Allow-Origin'],
                         'http://bar.com')

        resp = self.request(
            path='/dummy/test', method='GET', additionalHeaders=[
                ('Origin', 'http://invalid.com')
            ], isJson=False)
        self.assertNotIn('Access-Control-Allow-Origin', resp.headers)
<commit_msg>Improve test coverage for routes<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

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

from .. import base
from girder.api import access
from girder.api.describe import Description, describeRoute
from girder.api.rest import Resource, RestException
from girder.models.model_base import GirderException
from girder.constants import SettingKey, SettingDefault

testServer = None

def setUpModule():
    global testServer
    testServer = base.startServer()

def tearDownModule():
    base.stopServer()

class DummyResource(Resource):
    def __init__(self):
        super(DummyResource, self).__init__()
        self.route('GET', (':wc1', 'literal1'), self.handler)
        self.route('GET', (':wc1', 'literal2'), self.handler)
        self.route('GET', (':wc1', ':wc2'), self.handler)
        self.route('GET', (':wc1', 'literal1'), self.handler)
        self.route('GET', ('literal1', 'literal2'), self.handler)
        self.route('GET', (':wc1', 'admin'), self.handler)
        self.route('PATCH', (':id', 'patchy'), self.handler)
        self.route('GET', ('test', ), self.handler)
        self.route('PUT', ('test', ), self.handler)
        self.route('POST', ('test', ), self.handler)
        self.route('DELETE', ('test', ), self.handler)
        self.route('PATCH', ('test', ), self.handler)

    @access.public
    @describeRoute(
        Description('Dummy handler.')
    )
    def handler(self, **kwargs):
        return kwargs
    # We want to test adding and removing documentation when we add and remove
    # routes.

class RoutesTestCase(base.TestCase):
    """
    Unit tests of the routing system of REST Resources.
    """
    def testRouteSystem(self):
        # Test an empty route handler
        emptyResource = Resource()
        self.assertRaises(GirderException, emptyResource.handleRoute, 'GET', (), {})

        dummy = DummyResource()

        # Bad route should give a useful exception.
        exc = None
        try:
            dummy.handleRoute('GET', (), {})
        except RestException as e:
            exc = e.message
        self.assertEqual(exc, 'No matching route for "GET "')

        # Make sure route ordering is correct; literals before wildcard tokens
        r = dummy.handleRoute('GET', ('literal1', 'foo'), {})
        self.assertEqual(r, {'wc1': 'literal1', 'wc2': 'foo', 'params': {}})

        r = dummy.handleRoute('GET', ('literal1', 'literal2'), {})
        self.assertEqual(r, {'params': {}})

        r = dummy.handleRoute('PATCH', ('guid', 'patchy'), {})
        self.assertEqual(r, {'id': 'guid', 'params': {}})

        # Add a new route with a new method
        dummy.route('DUMMY', (':id', 'dummy'), dummy.handler)
        r = dummy.handleRoute('DUMMY', ('guid', 'dummy'), {})
        self.assertEqual(r, {'id': 'guid', 'params': {}})

        # Test getting the route handler
        self.assertRaises(Exception, dummy.getRouteHandler, 'FOO', (':id', 'dummy'))
        self.assertRaises(Exception, dummy.getRouteHandler, 'DUMMY', (':id', 'foo'))
        registeredHandler = dummy.getRouteHandler('DUMMY', (':id', 'dummy'))
        # The handler method cannot be compared directly with `is`, but its name and behavior can be
        # examined
        self.assertEqual(registeredHandler.__name__, dummy.handler.__name__)
        self.assertEqual(registeredHandler(foo=42), {'foo': 42})

        # Now remove the route
        dummy.removeRoute('DUMMY', (':id', 'dummy'))
        self.assertRaises(RestException, dummy.handleRoute, 'DUMMY', ('guid', 'dummy'), {})

    def testCORS(self):
        testServer.root.api.v1.dummy = DummyResource()

        # When no origin header is passed, we shouldn't receive CORS headers
        resp = self.request(path='/dummy/test')
        self.assertStatusOk(resp)
        self.assertFalse('Access-Control-Allow-Origin' in resp.headers)
        self.assertFalse('Access-Control-Allow-Credentials' in resp.headers)

        # If no origins are allowed, we should not get an allow origin header
        resp = self.request(path='/dummy/test', additionalHeaders=[
            ('Origin', 'http://foo.com')
        ])
        self.assertStatusOk(resp)
        self.assertFalse('Access-Control-Allow-Origin' in resp.headers)

        # If we allow some origins, we should get the corresponding header
        self.model('setting').set(SettingKey.CORS_ALLOW_ORIGIN,
                                  'http://kitware.com')
        resp = self.request(path='/dummy/test', additionalHeaders=[
            ('Origin', 'http://foo.com')
        ])
        self.assertEqual(resp.headers['Access-Control-Allow-Origin'],
                         'http://kitware.com')
        self.assertEqual(resp.headers['Access-Control-Allow-Credentials'],
                         'true')

        # Simulate a preflight request; we should get back several headers
        self.model('setting').set(SettingKey.CORS_ALLOW_METHODS, 'POST')
        resp = self.request(
            path='/dummy/test', method='OPTIONS', additionalHeaders=[
                ('Origin', 'http://foo.com')
            ], isJson=False
        )
        self.assertStatusOk(resp)
        self.assertEqual(self.getBody(resp), '')
        self.assertEqual(resp.headers['Access-Control-Allow-Origin'],
                         'http://kitware.com')
        self.assertEqual(resp.headers['Access-Control-Allow-Credentials'],
                         'true')
        self.assertEqual(resp.headers['Access-Control-Allow-Headers'],
                         SettingDefault.defaults[SettingKey.CORS_ALLOW_HEADERS])
        self.assertEqual(resp.headers['Access-Control-Allow-Methods'], 'POST')

        # Set multiple allowed origins
        self.model('setting').set(SettingKey.CORS_ALLOW_ORIGIN,
                                  'http://foo.com, http://bar.com')
        resp = self.request(
            path='/dummy/test', method='GET', additionalHeaders=[
                ('Origin', 'http://bar.com')
            ], isJson=False)
        self.assertEqual(resp.headers['Access-Control-Allow-Origin'],
                         'http://bar.com')

        resp = self.request(
            path='/dummy/test', method='GET', additionalHeaders=[
                ('Origin', 'http://invalid.com')
            ], isJson=False)
        self.assertNotIn('Access-Control-Allow-Origin', resp.headers)
<|endoftext|>


<commit_before>###
# Copyright (c) 2016 - 2021, Barry Suridge
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright notice,
#     this list of conditions, and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions, and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   * Neither the name of the author of this software nor the name of
#     contributors to this software may be used to endorse or promote products
#     derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import json    # JavaScript Object Notation
import socket  # Low-level networking interface
#XXX For Python 3.4 and later
# HTTP client for Python
import urllib3
from urllib3.exceptions import HTTPError
# URL handling module for python
from urllib.parse import urlparse
# Validate and categorize the IP address according to their types
# (IPv4 or IPv6)
import ipaddress

# mIRC colour codes
from .local.color import teal

from supybot.commands import *
import supybot.ircutils as utils
import supybot.callbacks as callbacks

    ###############
    #  FUNCTIONS  #
    ###############

special_chars = (
    '-',
    '[',
    ']',
    '\\',
    '`',
    '^',
    '{',
    '}',
    '_')

def is_nick(nick):
    """ Checks to see if a nickname `nick` is valid.
    According to :rfc:`2812 #section-2.3.1`, section 2.3.1, a nickname must start
    with either a letter or one of the allowed special characters, and after
    that it may consist of any combination of letters, numbers, or allowed
    special characters.
    """
    if not nick[0].isalpha() and nick[0] not in special_chars:
        return False
    for char in nick[1:]:
        if not char.isalnum() and char not in special_chars:
            return False
    return True

def is_ip(s):
    """Returns whether or not a given string is a
       valid IPv4 or IPv6 address.
    """
    try:
        ipaddress.ip_address(s)
        return True
    except ValueError:
        return False

class MyDNS(callbacks.Plugin):
    """An alternative to Supybot's DNS function.
    """

    def __init__(self, irc):
        super().__init__(irc)

    threaded = True

    ##############
    #    MAIN    #
    ##############

    @wrap(['text'])
    def dns(self, irc, msg, args, address):
        """<hostname | Nick | URL | IPv4 or IPv6>
        An alternative to Supybot's DNS function.
        Returns the ip of <hostname | Nick | URL | ip or IPv6> or the reverse
        DNS hostname of <ip> using Python's socket library
        """
        channel = msg.args[0]

        # Check if we should be 'disabled' in a channel.
        # config channel #channel plugins.mydns.enable True or False (or On or Off)
        if self.registryValue('enable', channel):
            if is_ip(address):
                irc.reply(self.gethostbyaddr(address), prefixNick=False)
            elif is_nick(address):  # Valid nick?
                nick = address
                try:
                    userHostmask = irc.state.nickToHostmask(nick)
                    (nick, _, host) = utils.splitHostmask(userHostmask)  # Returns the nick and host of a user hostmask.
                    irc.reply(self.gethostbyaddr(host), prefixNick=False)
                except KeyError:
                    irc.reply(f"[{nick}] is unknown.", prefixNick=False)
            else:  # Neither IP or IRC user nick.
                irc.reply(self.getaddrinfo(address), prefixNick=False)
        else:
            return

    def getaddrinfo(self, host):
        """Get host information. Use returned IP address
        to find the (approximate) geolocation of the host.
        """
        host = host.lower()
        d = urlparse(host)

        if d.scheme:
            host = d.netloc

        try:
            result = socket.getaddrinfo(host, None)
        except socket.error as err:  # Catch failed address lookup.
            return (f'Could not resolve {host}: {err}')

        ipaddress = result[0][4][0]
        geoip = self.geoip(ipaddress)

        dns = teal('DNS: ')
        loc = teal('LOC: ')

        return (f'{dns}{host} resolves to [{ipaddress}] {loc}{geoip}')

    def gethostbyaddr(self, ip):
        """Do a reverse lookup for ip.
        """
        try:
            (hostname, _, address) = socket.gethostbyaddr(ip)
            hostname = hostname + ' <> ' + address[0]
            geoip = self.geoip(address[0])
            shortname = hostname.split('.')[0]
            dns = teal('DNS:')
            loc = teal('LOC:')
            return (f'{dns} <{shortname}> [{hostname}] {loc} {geoip}')
        except socket.error as err:  # Catch failed address lookup.
            return (f'Could not resolve {ip}: {err}')

    def geoip(self, address):
        """Search for the geolocation of IP addresses.
        Accuracy not guaranteed.
        """
        apikey = self.registryValue('ipstackAPI')

        if not apikey:
            raise callbacks.Error( \
                'Please configure the ipstack API key in config plugins.MyDNS.ipstackAPI')

        # Creating a PoolManager instance for sending requests.
        http = urllib3.PoolManager()

        # Set the URI
        uri = 'http://api.ipstack.com/' + address + '?access_key=' + apikey

        # Sending a GET request and getting back response as HTTPResponse object
        response = http.request("GET", uri, timeout=1)

        # 'OK', 'Request fulfilled, document follows'
        if response.status != 200:
            raise HTTPError(
                'Request failed with status {0}'.format(response.status),
            )
        else:
            data = json.loads(response.data.decode("utf-8"))

        city    = 'City:%s ' % data['city'] if data['city'] else ''
        state   = 'State:%s ' % data['region_name'] if data['region_name'] else ''
        long    = 'Long:%s ' % data['longitude'] if data['longitude'] else ''
        lat     = 'Lat:%s ' % data['latitude'] if data['latitude'] else ''
        code    = 'Country Code:%s ' % data['country_code'] if data['country_code'] else ''
        country = 'Country:%s ' % data['country_name'] if data['country_name'] else ''
        flag    = data['location']['country_flag_emoji']
        zip     = ' Post/Zip Code:%s' % data['zip'] if data['zip'] else ''

        try:
            s = ''
            seq = [city, state, long, lat, code, country, flag, zip]
            return (s.join( seq ))
        except TypeError:
            print(f'Could not resolve {address}')

Class = MyDNS

# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
<commit_msg>Update plugin.py<commit_after>###
# Copyright (c) 2016 - 2021, Barry Suridge
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright notice,
#     this list of conditions, and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions, and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   * Neither the name of the author of this software nor the name of
#     contributors to this software may be used to endorse or promote products
#     derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

import json    # JavaScript Object Notation
import socket  # Low-level networking interface
#XXX For Python 3.4 and later
# HTTP client for Python
import urllib3
from urllib3.exceptions import HTTPError
# URL handling module for python
from urllib.parse import urlparse
# Validate and categorize the IP address according to their types
# (IPv4 or IPv6)
import ipaddress

# mIRC colour codes
from .local.colour import bold, teal

from supybot.commands import *
import supybot.ircutils as utils
import supybot.callbacks as callbacks

    ###############
    #  FUNCTIONS  #
    ###############

special_chars = (
    '-',
    '[',
    ']',
    '\\',
    '`',
    '^',
    '{',
    '}',
    '_')

def is_nick(nick):
    """ Checks to see if a nickname `nick` is valid.
    According to :rfc:`2812 #section-2.3.1`, section 2.3.1, a nickname must start
    with either a letter or one of the allowed special characters, and after
    that it may consist of any combination of letters, numbers, or allowed
    special characters.
    """
    if not nick[0].isalpha() and nick[0] not in special_chars:
        return False
    for char in nick[1:]:
        if not char.isalnum() and char not in special_chars:
            return False
    return True

def is_ip(s):
    """Returns whether or not a given string is a
       valid IPv4 or IPv6 address.
    """
    try:
        ipaddress.ip_address(s)
        return True
    except ValueError:
        return False

class MyDNS(callbacks.Plugin):
    """An alternative to Supybot's DNS function.
    """

    def __init__(self, irc):
        super().__init__(irc)

    threaded = True

    ##############
    #    MAIN    #
    ##############

    @wrap(['text'])
    def dns(self, irc, msg, args, address):
        """<hostname | Nick | URL | IPv4 or IPv6>
        An alternative to Supybot's DNS function.
        Returns the ip of <hostname | Nick | URL | ip or IPv6> or the reverse
        DNS hostname of <ip> using Python's socket library
        """
        channel = msg.args[0]

        # Check if we should be 'disabled' in a channel.
        # config channel #channel plugins.mydns.enable True or False (or On or Off)
        if self.registryValue('enable', channel):
            if is_ip(address):
                irc.reply(self.gethostbyaddr(address), prefixNick=False)
            elif is_nick(address):  # Valid nick?
                nick = address
                try:
                    userHostmask = irc.state.nickToHostmask(nick)
                    (nick, _, host) = utils.splitHostmask(userHostmask)  # Returns the nick and host of a user hostmask.
                    irc.reply(self.gethostbyaddr(host), prefixNick=False)
                except KeyError:
                    irc.reply(f"[{nick}] is unknown.", prefixNick=False)
            else:  # Neither IP or IRC user nick.
                irc.reply(self.getaddrinfo(address), prefixNick=False)
        else:
            return

    def getaddrinfo(self, host):
        """Get host information. Use returned IP address
        to find the (approximate) geolocation of the host.
        """
        host = host.lower()
        d = urlparse(host)

        if d.scheme:
            host = d.netloc

        try:
            result = socket.getaddrinfo(host, None)
        except socket.error as err:  # Catch failed address lookup.
            return (f'Could not resolve {host}: {err}')

        ipaddress = result[0][4][0]
        geoip = self.geoip(ipaddress)

        dns = bold(teal('DNS: '))
        loc = bold(teal('LOC: '))

        return (f'{dns}{host} resolves to [{ipaddress}] {loc}{geoip}')

    def gethostbyaddr(self, ip):
        """Do a reverse lookup for ip.
        """
        try:
            (hostname, _, address) = socket.gethostbyaddr(ip)
            hostname = hostname + ' <> ' + address[0]
            geoip = self.geoip(address[0])
            shortname = hostname.split('.')[0]
            dns = bold(teal('DNS: '))
            loc = bold(teal('LOC: '))
            return (f'{dns} <{shortname}> [{hostname}] {loc} {geoip}')
        except socket.error as err:  # Catch failed address lookup.
            return (f'Could not resolve {ip}: {err}')

    def geoip(self, address):
        """Search for the geolocation of IP addresses.
        Accuracy not guaranteed.
        """
        apikey = self.registryValue('ipstackAPI')

        if not apikey:
            raise callbacks.Error( \
                'Please configure the ipstack API key in config plugins.MyDNS.ipstackAPI')

        # Creating a PoolManager instance for sending requests.
        http = urllib3.PoolManager()

        # Set the URI
        uri = 'http://api.ipstack.com/' + address + '?access_key=' + apikey

        # Sending a GET request and getting back response as HTTPResponse object
        response = http.request("GET", uri, timeout=1)

        # 'OK', 'Request fulfilled, document follows'
        if response.status != 200:
            raise HTTPError(
                'Request failed with status {0}'.format(response.status),
            )
        else:
            data = json.loads(response.data.decode("utf-8"))

        city    = 'City:%s ' % data['city'] if data['city'] else ''
        state   = 'State:%s ' % data['region_name'] if data['region_name'] else ''
        long    = 'Long:%s ' % data['longitude'] if data['longitude'] else ''
        lat     = 'Lat:%s ' % data['latitude'] if data['latitude'] else ''
        code    = 'Country Code:%s ' % data['country_code'] if data['country_code'] else ''
        country = 'Country:%s ' % data['country_name'] if data['country_name'] else ''
        flag    = data['location']['country_flag_emoji']
        zip     = ' Post/Zip Code:%s' % data['zip'] if data['zip'] else ''

        try:
            s = ''
            seq = [city, state, long, lat, code, country, flag, zip]
            return (s.join( seq ))
        except TypeError:
            print(f'Could not resolve {address}')

Class = MyDNS

# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
<|endoftext|>


<commit_before>"""The WaveBlocks Project

This file contains a propagator class for homogeneous wavepackets.

@author: V. Gradinaru
@copyright: Copyright (C) 2013, 2014 V. Gradinaru, R. Bourquin
@license: Modified BSD License
"""

from functools import partial
from numpy import dot, eye, atleast_2d, sqrt, zeros
from numpy.linalg import inv, det

from Propagator import Propagator
from BlockFactory import BlockFactory
from SplittingParameters import SplittingParameters
from ComplexMath import cont_angle

__all__ = ["Pre764scPropagator"]

class Pre764scPropagator(Propagator, SplittingParameters):
    r"""This class can numerically propagate given initial values :math:`\Psi` in
    a potential :math:`V(x)`. The propagation is done for a given set of homogeneous
    Hagedorn wavepackets neglecting interaction. It uses the preprocessor 764 method,
    see Blanes, Casas, Ros 2000, table IV and the idea of the semiclassical splitting
    """

    def __init__(self, parameters, potential, packets=[]):
        r"""Initialize a new :py:class:`SemiclassicalPropagator` instance.

        :param parameters: A :py:class:`ParameterProvider` instance containing at least
                           the key ``dt`` for providing the timestep :math:`\tau`.
        :type parameters: A :py:class:`ParameterProvider` instance

        :param potential: The potential :math:`V(x)` the wavepacket :math:`\Psi` feels during the time propagation.
        :param packet: The initial homogeneous Hagedorn wavepacket :math:`\Psi` we propagate in time.
        :raises ValueError: If the number of components of :math:`\Psi` does not match
                            the number of energy levels :math:`\lambda_i` of the potential.
        """
        # The potential :math:`V(x)` the packet(s) feel.
        self._potential = potential

        # Number :math:`N` of components the wavepacket :math:`\Psi` has got.
        self._number_components = self._potential.get_number_components()
        self._dimension = self._potential.get_dimension()

        # A list of Hagedorn wavepackets :math:`\Psi` together with some codata
        # like the leading component :math:`\chi` which is the index of the eigenvalue
        # :math:`\lambda_\chi` of the potential :math:`V` that is responsible for
        # propagating the Hagedorn parameters.
        # TODO: We assume a list of (packet, leading_component) tuples here. Generalize tuples to dicts!
        # TODO: Do not use a list but better use a hashtable by packet IDs?
        self._packets = packets[:]

        # Keep a reference to the parameter provider instance
        self._parameters = parameters

        self._dt = self._parameters["dt"]

        # The relative mass scaling matrix M
        if self._parameters.has_key("mass_scaling"):
            self._M = atleast_2d(self._parameters["mass_scaling"])
            assert self._M.shape == (self._dimension, self._dimension)
            self._Minv = inv(self._M)
        else:
            # No mass matrix given. Scale all masses equally
            self._M = eye(self._dimension)
            self._Minv = self._M

        # Decide about the matrix exponential algorithm to use
        self.__dict__["_matrix_exponential"] = BlockFactory().create_matrixexponential(parameters)

        # Precalculate the potential splittings needed
        self._prepare_potential()
        self._a, self._b = self.build(parameters["splitting_method"])

    def __str__(self):
        r"""Prepare a printable string representing the :py:class:`SemiclassicalPropagator` instance."""
        return "Homogeneous Semiclassical propagator for " + str(self._number_components) + " components.\n"

    def _prepare_potential(self):
        """Precalculate the potential splittings needed
        """
        for chi in set([ p[1] for p in self._packets ]):
            self._potential.calculate_local_quadratic(diagonal_component=chi)
            self._potential.calculate_local_remainder(diagonal_component=chi)

    def add_wavepacket(self, packet):
        r"""Add a new wavepacket :math:`\Psi` to the list of propagated wavepackets.

        :param packet: The new wavepacket :math:`\Psi` and its leading component :math:`\chi \in [0,N-1]`.
        :type packet: A tuple :math:`(\Psi, \chi)` with :math:`\Psi` a :py:class:`HagedornWavepacket`
                      instance and :math:`\chi` an integer.
        """
        self._packets.append(tuple(packet))
        self._prepare_potential()

    # TODO: Consider removig this, duplicate
    def get_number_components(self):
        r""":return: The number :math:`N` of components :math:`\Phi_i` of :math:`\Psi`.
        """
        return self._number_components

    def get_wavepackets(self, packet=None):
        r"""Return the wavepackets :math:`\{\Psi_i\}_i` that take part in the time propagation by the
        current :py:class:`SemiclassicalPropagator` instance.

        :param packet: The index :math:`i` (in this list) of a single packet :math:`\Psi_i` that is
                       to be returned. If set to ``None`` (default) return the full list with all packets.
        :type packet: Integer or ``None``
        :return: A list of :py:class:`HagedornWavepacket` instances or a single instance.
        """
        # TODO: Does not return leading components. Add this if needed somewhere.
        if packet is None:
            return [ p[0] for p in self._packets ]
        else:
            return self._packets[packet][0]

    def set_wavepackets(self, packetlist):
        """Set the list :math:`\{\Psi_i\}_i` of wavepackets that the propagator will propagate.

        :param packetlist: A list of new wavepackets :math:`\Psi_i` and their
                           leading components :math:`\chi_i` to propagate.
        :type packetlist: A list of :math:`(\Psi_i, \chi_i)` tuples.
        """
        self._packets = packetlist[:]

    def _propkin(self, h, packet):
        """Do a kinetic step of size h.
        """
        Mi = self._Minv
        key = ("q", "p", "Q", "P", "S", "adQ")
        q, p, Q, P, S, adQ = packet.get_parameters(key=key)
        q = q + h * dot(Mi, p)
        Q = Q + h * dot(Mi, P)
        S = S + 0.5 * h * dot(p.T, dot(Mi, p))
        adQn = cont_angle(det(Q), reference=adQ)[0]
        packet.set_parameters((q, p, Q, P, S, adQn), key=key)

    def _proppotquad(self, h, packet, leading_chi):
        """Do a potential step of size h with the local quadratic part.
        """
        q, p, Q, P, S = packet.get_parameters()
        V = self._potential.evaluate_local_quadratic_at(q, diagonal_component=leading_chi)
        p = p - h * V[1]
        P = P - h * dot(V[2], Q)
        S = S - h * V[0]
        packet.set_parameters((q, p, Q, P, S))

    def pre_propagate(self):
        r"""Given the wavefunction :math:`\psi` at initial time :math:`t_0`,
        perform some computations exactly once before running the ordinary
        time propagation.
        """
        # Cache some parameter values
        dt = 1.0*self._dt
        a = self._a
        b = self._b
        # Processor
        z4Abig = zeros(6)
        z4Abig[0] = -0.3346222298730
        z4Abig[1] = 1.097567990732164
        z4Abig[2] = -1.038088746096783
        z4Abig[3] = 0.6234776317921379
        z4Abig[4] = -1.102753206303191
        z4Abig[5] = -0.0141183222088869
        y4Beps = zeros(6)
        y4Beps[0] = -1.621810118086801
        y4Beps[1] = 0.0061709468110142
        y4Beps[2] = 0.8348493592472594
        y4Beps[3] = -0.0511253369989315
        y4Beps[4] = 0.5633782670698199
        y4Beps[5] = -0.5
        # Apply preprocessor step
        for packet, leading_chi in self._packets:
            eps = packet.get_eps()
            nrtmp = int(sqrt(dt*eps**-0.75))
            nrlocalsteps = max(1, 1+nrtmp)
            for j in xrange(6):
                # Step with Abig
                h1 = -z4Abig[j]*dt
                self.intsplit(self._propkin, self._proppotquad, a,b, [0.0,h1], nrlocalsteps, [packet], [packet,leading_chi])
                # Step with Beps
                h2 = -y4Beps[j]*dt
                # Do a potential step with the local non-quadratic taylor remainder
                innerproduct = packet.get_innerproduct()
                F = innerproduct.build_matrix(packet, operator=partial(self._potential.evaluate_local_remainder_at, diagonal_component=leading_chi))

                coefficients = packet.get_coefficient_vector()
                coefficients = self._matrix_exponential(F, coefficients, h2/eps**2)
                packet.set_coefficient_vector(coefficients)

    def post_propagate(self):
        r"""Given the wavefunction :math:`\psi` at final time :math:`T`,
        perform some computations exactly once after running the ordinary
        time propagation.
        """
        # Cache some parameter values
        dt = 1.0*self._dt
        a = self._a
        b = self._b
        # Postprocessor
        z4Abig = zeros(6)
        z4Abig[0] = -0.3346222298730
        z4Abig[1] = 1.097567990732164
        z4Abig[2] = -1.038088746096783
        z4Abig[3] = 0.6234776317921379
        z4Abig[4] = -1.102753206303191
        z4Abig[5] = -0.0141183222088869
        y4Beps = zeros(6)
        y4Beps[0] = -1.621810118086801
        y4Beps[1] = 0.0061709468110142
        y4Beps[2] = 0.8348493592472594
        y4Beps[3] = -0.0511253369989315
        y4Beps[4] = 0.5633782670698199
        y4Beps[5] = -0.5
        # Apply postprocessor step
        for packet, leading_chi in self._packets:
            eps = packet.get_eps()
            nrtmp = int(sqrt(dt*eps**-0.75))
            nrlocalsteps = max(1, 1+nrtmp)
            for j in xrange(6-1,-1,-1):
                # Step with Beps
                h2 = y4Beps[j]*dt
                # Do a potential step with the local non-quadratic taylor remainder
                innerproduct = packet.get_innerproduct()
                F = innerproduct.build_matrix(packet, operator=partial(self._potential.evaluate_local_remainder_at, diagonal_component=leading_chi))

                coefficients = packet.get_coefficient_vector()
                coefficients = self._matrix_exponential(F, coefficients, h2/eps**2)
                packet.set_coefficient_vector(coefficients)
                # Step with Abig
                h1 = z4Abig[j]*dt
                self.intsplit(self._propkin, self._proppotquad, a,b, [0.0,h1], nrlocalsteps, [packet], [packet,leading_chi])

    def propagate(self):
        r"""Given a wavepacket :math:`\Psi` at time :math:`t` compute the propagated
        wavepacket at time :math:`t + \tau`. We perform exactly one timestep of size
        :math:`\tau` here. This propagation is done for all packets in the list
        :math:`\{\Psi_i\}_i` and neglects any interaction between two packets.
        The semiclassical propagations scheme is used.
        """
        # Cache some parameter values
        dt = 1.0*self._dt
        a = self._a
        b = self._b
        # Kernel Pattern ABA
        Beps = zeros(4)
        Beps[1] = 1.5171479707207228
        Beps[2] = 1.0 - 2.0 * Beps[1]
        Beps[3] = 1.0 * Beps[1]
        Abig = zeros(4)
        Abig[0] = 0.5600879810924619
        Abig[1] = 0.5 - Abig[0]
        Abig[2] = 1.0 * Abig[1]
        Abig[3] = 1.0 * Abig[0]
        # Propagate all packets
        for packet, leading_chi in self._packets:
            eps = packet.get_eps()
            nrtmp = int(sqrt(dt*eps**-0.75))
            nrlocalsteps = max(1, 1+nrtmp)
            for j in xrange(4):
                # Step with Beps
                h2 = Beps[j]*dt
                # Do a potential step with the local non-quadratic taylor remainder
                if j>0: # Beps[0] = 0, hence nothing to to
                    innerproduct = packet.get_innerproduct()
                    F = innerproduct.build_matrix(packet, operator=partial(self._potential.evaluate_local_remainder_at, diagonal_component=leading_chi))

                    coefficients = packet.get_coefficient_vector()
                    coefficients = self._matrix_exponential(F, coefficients, h2/eps**2)
                    packet.set_coefficient_vector(coefficients)
                # Step with Abig
                h = Abig[j]*dt
                self.intsplit(self._propkin, self._proppotquad, a,b, [0.0,h], nrlocalsteps, [packet], [packet,leading_chi])
<commit_msg>Remove redundant parameter definitions<commit_after>"""The WaveBlocks Project

This file contains a propagator class for homogeneous wavepackets.

@author: V. Gradinaru
@copyright: Copyright (C) 2013, 2014 V. Gradinaru, R. Bourquin
@license: Modified BSD License
"""

from functools import partial
from numpy import dot, eye, atleast_2d, sqrt, zeros
from numpy.linalg import inv, det

from Propagator import Propagator
from BlockFactory import BlockFactory
from SplittingParameters import SplittingParameters
from ProcessingSplittingParameters import ProcessingSplittingParameters
from ComplexMath import cont_angle

__all__ = ["Pre764scPropagator"]

class Pre764scPropagator(Propagator, SplittingParameters):
    r"""This class can numerically propagate given initial values :math:`\Psi` in
    a potential :math:`V(x)`. The propagation is done for a given set of homogeneous
    Hagedorn wavepackets neglecting interaction. It uses the preprocessor 764 method,
    see Blanes, Casas, Ros 2000, table IV and the idea of the semiclassical splitting
    """

    def __init__(self, parameters, potential, packets=[]):
        r"""Initialize a new :py:class:`SemiclassicalPropagator` instance.

        :param parameters: A :py:class:`ParameterProvider` instance containing at least
                           the key ``dt`` for providing the timestep :math:`\tau`.
        :type parameters: A :py:class:`ParameterProvider` instance

        :param potential: The potential :math:`V(x)` the wavepacket :math:`\Psi` feels during the time propagation.
        :param packet: The initial homogeneous Hagedorn wavepacket :math:`\Psi` we propagate in time.
        :raises ValueError: If the number of components of :math:`\Psi` does not match
                            the number of energy levels :math:`\lambda_i` of the potential.
        """
        # The potential :math:`V(x)` the packet(s) feel.
        self._potential = potential

        # Number :math:`N` of components the wavepacket :math:`\Psi` has got.
        self._number_components = self._potential.get_number_components()
        self._dimension = self._potential.get_dimension()

        # A list of Hagedorn wavepackets :math:`\Psi` together with some codata
        # like the leading component :math:`\chi` which is the index of the eigenvalue
        # :math:`\lambda_\chi` of the potential :math:`V` that is responsible for
        # propagating the Hagedorn parameters.
        # TODO: We assume a list of (packet, leading_component) tuples here. Generalize tuples to dicts!
        # TODO: Do not use a list but better use a hashtable by packet IDs?
        self._packets = packets[:]

        # Keep a reference to the parameter provider instance
        self._parameters = parameters

        self._dt = self._parameters["dt"]

        # The relative mass scaling matrix M
        if self._parameters.has_key("mass_scaling"):
            self._M = atleast_2d(self._parameters["mass_scaling"])
            assert self._M.shape == (self._dimension, self._dimension)
            self._Minv = inv(self._M)
        else:
            # No mass matrix given. Scale all masses equally
            self._M = eye(self._dimension)
            self._Minv = self._M

        # Decide about the matrix exponential algorithm to use
        self.__dict__["_matrix_exponential"] = BlockFactory().create_matrixexponential(parameters)

        # Precalculate the potential splittings needed
        self._prepare_potential()
        self._a, self._b = SplittingParameters().build(parameters["splitting_method"])
        self._A, self._B, self._Y, self._Z = ProcessingSplittingParameters().build("BCR764")

    def __str__(self):
        r"""Prepare a printable string representing the :py:class:`SemiclassicalPropagator` instance."""
        return "Homogeneous Semiclassical propagator for " + str(self._number_components) + " components.\n"

    def _prepare_potential(self):
        """Precalculate the potential splittings needed
        """
        for chi in set([ p[1] for p in self._packets ]):
            self._potential.calculate_local_quadratic(diagonal_component=chi)
            self._potential.calculate_local_remainder(diagonal_component=chi)

    def add_wavepacket(self, packet):
        r"""Add a new wavepacket :math:`\Psi` to the list of propagated wavepackets.

        :param packet: The new wavepacket :math:`\Psi` and its leading component :math:`\chi \in [0,N-1]`.
        :type packet: A tuple :math:`(\Psi, \chi)` with :math:`\Psi` a :py:class:`HagedornWavepacket`
                      instance and :math:`\chi` an integer.
        """
        self._packets.append(tuple(packet))
        self._prepare_potential()

    # TODO: Consider removig this, duplicate
    def get_number_components(self):
        r""":return: The number :math:`N` of components :math:`\Phi_i` of :math:`\Psi`.
        """
        return self._number_components

    def get_wavepackets(self, packet=None):
        r"""Return the wavepackets :math:`\{\Psi_i\}_i` that take part in the time propagation by the
        current :py:class:`SemiclassicalPropagator` instance.

        :param packet: The index :math:`i` (in this list) of a single packet :math:`\Psi_i` that is
                       to be returned. If set to ``None`` (default) return the full list with all packets.
        :type packet: Integer or ``None``
        :return: A list of :py:class:`HagedornWavepacket` instances or a single instance.
        """
        # TODO: Does not return leading components. Add this if needed somewhere.
        if packet is None:
            return [ p[0] for p in self._packets ]
        else:
            return self._packets[packet][0]

    def set_wavepackets(self, packetlist):
        """Set the list :math:`\{\Psi_i\}_i` of wavepackets that the propagator will propagate.

        :param packetlist: A list of new wavepackets :math:`\Psi_i` and their
                           leading components :math:`\chi_i` to propagate.
        :type packetlist: A list of :math:`(\Psi_i, \chi_i)` tuples.
        """
        self._packets = packetlist[:]

    def _propkin(self, h, packet):
        """Do a kinetic step of size h.
        """
        Mi = self._Minv
        key = ("q", "p", "Q", "P", "S", "adQ")
        q, p, Q, P, S, adQ = packet.get_parameters(key=key)
        q = q + h * dot(Mi, p)
        Q = Q + h * dot(Mi, P)
        S = S + 0.5 * h * dot(p.T, dot(Mi, p))
        adQn = cont_angle(det(Q), reference=adQ)[0]
        packet.set_parameters((q, p, Q, P, S, adQn), key=key)

    def _proppotquad(self, h, packet, leading_chi):
        """Do a potential step of size h with the local quadratic part.
        """
        q, p, Q, P, S = packet.get_parameters()
        V = self._potential.evaluate_local_quadratic_at(q, diagonal_component=leading_chi)
        p = p - h * V[1]
        P = P - h * dot(V[2], Q)
        S = S - h * V[0]
        packet.set_parameters((q, p, Q, P, S))

    def pre_propagate(self):
        r"""Given the wavefunction :math:`\psi` at initial time :math:`t_0`,
        perform some computations exactly once before running the ordinary
        time propagation.
        """
        # Cache some parameter values
        dt = 1.0*self._dt
        a = self._a
        b = self._b
        # Processor
        Z = self._Z
        Y = self._Y
        # Apply preprocessor step
        for packet, leading_chi in self._packets:
            eps = packet.get_eps()
            nrtmp = int(sqrt(dt*eps**-0.75))
            nrlocalsteps = max(1, 1+nrtmp)
            for j in xrange(6):
                # Step with Abig
                h1 = -Z[j]*dt
                self.intsplit(self._propkin, self._proppotquad, a,b, [0.0,h1], nrlocalsteps, [packet], [packet,leading_chi])
                # Step with Beps
                h2 = -Y[j]*dt
                # Do a potential step with the local non-quadratic taylor remainder
                innerproduct = packet.get_innerproduct()
                F = innerproduct.build_matrix(packet, operator=partial(self._potential.evaluate_local_remainder_at, diagonal_component=leading_chi))

                coefficients = packet.get_coefficient_vector()
                coefficients = self._matrix_exponential(F, coefficients, h2/eps**2)
                packet.set_coefficient_vector(coefficients)

    def post_propagate(self):
        r"""Given the wavefunction :math:`\psi` at final time :math:`T`,
        perform some computations exactly once after running the ordinary
        time propagation.
        """
        # Cache some parameter values
        dt = 1.0*self._dt
        a = self._a
        b = self._b
        # Postprocessor
        Z = self._Z
        Y = self._Y
        # Apply postprocessor step
        for packet, leading_chi in self._packets:
            eps = packet.get_eps()
            nrtmp = int(sqrt(dt*eps**-0.75))
            nrlocalsteps = max(1, 1+nrtmp)
            for j in xrange(6-1,-1,-1):
                # Step with Beps
                h2 = Y[j]*dt
                # Do a potential step with the local non-quadratic taylor remainder
                innerproduct = packet.get_innerproduct()
                F = innerproduct.build_matrix(packet, operator=partial(self._potential.evaluate_local_remainder_at, diagonal_component=leading_chi))

                coefficients = packet.get_coefficient_vector()
                coefficients = self._matrix_exponential(F, coefficients, h2/eps**2)
                packet.set_coefficient_vector(coefficients)
                # Step with Abig
                h1 = Z[j]*dt
                self.intsplit(self._propkin, self._proppotquad, a,b, [0.0,h1], nrlocalsteps, [packet], [packet,leading_chi])

    def propagate(self):
        r"""Given a wavepacket :math:`\Psi` at time :math:`t` compute the propagated
        wavepacket at time :math:`t + \tau`. We perform exactly one timestep of size
        :math:`\tau` here. This propagation is done for all packets in the list
        :math:`\{\Psi_i\}_i` and neglects any interaction between two packets.
        The semiclassical propagations scheme is used.
        """
        # Cache some parameter values
        dt = 1.0*self._dt
        a = self._a
        b = self._b
        # Kernel Pattern ABA
        Beps = self._A
        Abig = self._B
        # Propagate all packets
        for packet, leading_chi in self._packets:
            eps = packet.get_eps()
            nrtmp = int(sqrt(dt*eps**-0.75))
            nrlocalsteps = max(1, 1+nrtmp)
            for j in xrange(4):
                # Step with Beps
                h2 = Beps[j]*dt
                # Do a potential step with the local non-quadratic Taylor remainder
                # Beps[0] = 0, hence nothing to do
                if j>0:
                    innerproduct = packet.get_innerproduct()
                    F = innerproduct.build_matrix(packet, operator=partial(self._potential.evaluate_local_remainder_at, diagonal_component=leading_chi))

                    coefficients = packet.get_coefficient_vector()
                    coefficients = self._matrix_exponential(F, coefficients, h2/eps**2)
                    packet.set_coefficient_vector(coefficients)
                # Step with Abig
                h1 = Abig[j]*dt
                self.intsplit(self._propkin, self._proppotquad, a,b, [0.0,h1], nrlocalsteps, [packet], [packet,leading_chi])
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from django import forms
from django.conf import settings
from taggit_autosuggest.widgets import TagAutoSuggest

class LatestEntriesForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(LatestEntriesForm, self).__init__(*args, **kwargs)
        # self.fields['tags'].widget = TagAutoSuggest('taggit.Tag')

    class Media:
        css = {
            'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL,
                                                 'djangocms_blog_admin.css'),)
        }
<commit_msg>active on_site to categories filter in Latest Blog Articles plugin<commit_after># -*- coding: utf-8 -*-
from django import forms
from django.conf import settings
from django.contrib.sites.models import Site
from taggit_autosuggest.widgets import TagAutoSuggest

from djangocms_blog.models import BlogCategory

class LatestEntriesForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(LatestEntriesForm, self).__init__(*args, **kwargs)
        # self.fields['tags'].widget = TagAutoSuggest('taggit.Tag')
        for field_name in self.fields:
            if field_name == "categories":
                formfield = self.fields[field_name]
                if hasattr(formfield, 'queryset'):
                    formfield.queryset = BlogCategory.objects.filter(
                        sites=Site.objects.get_current())

    class Media:
        css = {
            'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL,
                                                 'djangocms_blog_admin.css'),)
        }
<|endoftext|>