import abc
import os
import version
import semver
import subprocess
import traceback

from util import (
    ctx,
    existing_file,
    existing_dir,
    not_empty,
    not_none,
    fail,
    verbose,
    info,
    warning,
)
from gitutil import GitHelper
from github.util import (
    GitHubRepositoryHelper,
    GitHubRepoBranch,
)
import product.model
from github.release_notes.util import (
    fetch_release_notes,
    post_to_slack,
    github_repo_path,
    draft_release_name_for_version,
)

class TransactionContext(object):
    def __init__(self):
        self._step_outputs = {}

    def step_output(self, step_name: str):
        return self._step_outputs[step_name]

    def set_step_output(self, step_name: str, output):
        if step_name in self._step_outputs.keys():
            raise RuntimeError(f"Context already contains output of step '{step_name}'")
        self._step_outputs[step_name] = output

class TransactionalStep(object, metaclass=abc.ABCMeta):
    '''Abstract base class for operations that are to be executed with transactional semantics.

    Instances represent operations which typically cause external and persistent side effects.
    Typically, a sequence of (different) steps are grouped in a `Transaction`

    Subclasses *may* overwrite the `validate` method, which performs optional checks that indicate
    whether the operation would probably fail. Those checks are intended to be run for all steps of
    a `Transaction` before actually executing it. Validation *must not* cause any persistent side
    effects to external resources.

    Subclasses *must* overwrite the `apply` method, which performs the actual payload of the step,
    typically resulting in persistent external side effects. The `apply` method *may* also return
    an object (e.g.: a `dict`) that is then made available to later steps
    when part of a `Transaction`.

    Subclasses *must* overwrite the `revert` method, which reverts any persistent external side
    effects previously created by running the step's `apply` method. This should take into account
    that the execution of the `apply` method may or may not have succeeded, failed,
    or failed partially.
    '''
    def set_context(self, context: TransactionContext):
        self._context = context

    def context(self):
        return self._context

    def validate(self):
        pass

    @abc.abstractmethod
    def apply(self):
        return None

    @abc.abstractmethod
    def revert(self):
        pass

    @abc.abstractmethod
    def name(self):
        pass

class Transaction(object):
    '''This class represents a transaction using `TransactionalStep`s

    Provides aptly named methods to `validate` a series of `TransactionalStep`s and `execute`
    it atomically, performing the necessary undo actions should an error occur.

    `TransactionalStep`s are provided with access to a shared `TransactionContext` instance
    to store and retrieve (by step name) information with greater scope than a single step.
    '''
    def __init__(
        self,
        *steps: TransactionalStep,
    ):
        # create context object for this transaction
        self.context = TransactionContext()
        # validate type of args and set context
        for step in steps:
            if not isinstance(step, TransactionalStep):
                raise TypeError('Transactions may only contain instances of TransactionalStep')
            step.set_context(self.context)
        self._steps = steps

    def validate(self):
        for step in self._steps:
            info(f"Validating step '{step.name()}'")
            step.validate()

    def execute(self):
        executed_steps = list()
        for step in self._steps:
            step_name = step.name()
            # attempt to execute the step
            info(f"Applying step '{step_name}'")
            executed_steps.append(step)
            try:
                output = step.apply()
                self.context.set_step_output(step_name, output)
            except BaseException as e:
                warning(f"An error occured while applying step '{step_name}': {e}")
                traceback.print_exc()
                # revert the changes attempted, in reverse order
                self._revert(reversed(executed_steps))
                # do not execute apply for remaining steps
                break

    def _revert(self, steps):
        # attempt to revert each step. Raise an exception if not all reverts succeeded.
        all_reverted = True
        for step in steps:
            step_name = step.name()
            info(f"Reverting step {step_name}")
            try:
                step.revert()
            except BaseException as e:
                all_reverted = False
                warning(f"An error occured while reverting step '{step_name}': {e}")
                traceback.print_exc()
        if not all_reverted:
            raise RuntimeError("Unable to revert all steps.")

class ReleaseCommitStep(TransactionalStep):
    def __init__(
        self,
        git_helper: GitHelper,
        repo_dir: str,
        release_version: str,
        repository_version_file_path: str,
        repository_branch: str,
        rebase_before_release: bool,
        release_commit_callback: str=None,
    ):
        self.git_helper = not_none(git_helper)
        self.repository_branch = not_empty(repository_branch)
        self.release_version = not_empty(release_version)
        self.rebase_before_release = rebase_before_release

        repo_dir_absolute = os.path.abspath(not_empty(repo_dir))
        self.repo_dir = repo_dir_absolute
        self.repository_version_file_path = os.path.join(
            repo_dir_absolute,
            repository_version_file_path,
        )
        if release_commit_callback:
            self.release_commit_callback = os.path.join(
                repo_dir_absolute,
                release_commit_callback,
            )
        else:
            self.release_commit_callback = None

    def name(self):
        return "Create Release Commit"

    def validate(self):
        existing_dir(self.repo_dir)
        semver.parse(self.release_version)
        if(self.release_commit_callback):
            existing_file(self.release_commit_callback)
        existing_file(self.repository_version_file_path)

    def apply(self):
        if self.rebase_before_release:
            upstream_commit_sha = self.git_helper.fetch_head(
                f'refs/heads/{self.repository_branch}'
            ).hexsha
            self.git_helper.rebase(commit_ish=upstream_commit_sha)

        # clean repository if required
        worktree_dirty = bool(self.git_helper._changed_file_paths())
        if worktree_dirty:
            self.git_helper._stash_changes()

        # update version file
        with open(self.repository_version_file_path, 'w') as f:
            f.write(self.release_version)

        try:
            # call optional release commit callback
            if self.release_commit_callback:
                self._invoke_release_callback(
                    release_commit_callback=self.release_commit_callback,
                    repo_dir=self.repo_dir,
                    release_version=self.release_version,
                )

            release_commit = self.git_helper.index_to_commit(
                message=f'Release {self.release_version}',
            )

            release_commit_sha = release_commit.hexsha

            # forward head to new commit
            self.git_helper.repo.head.set_commit(release_commit_sha)

            # Push release commit to remote
            self.git_helper.push(
                from_ref=release_commit_sha,
                to_ref=self.repository_branch,
                use_ssh=True,
            )
            return {'release commit sha': release_commit_sha}
        finally:
            if worktree_dirty and self.git_helper._has_stash():
                self.git_helper._pop_stash()

    def _invoke_release_callback(
        self,
        release_commit_callback,
        repo_dir,
        release_version,
    ):
        callback_env = os.environ.copy()
        callback_env['REPO_DIR'] = repo_dir
        callback_env['EFFECTIVE_VERSION'] = release_version

        subprocess.run(
            [release_commit_callback],
            check=True,
            env=callback_env,
        )

    def revert(self):
        raise NotImplementedError('revert-method is not yet implemented')

class ReleaseTagStep(TransactionalStep):
    def __init__(
        self,
        github_helper: GitHubRepositoryHelper,
        release_version: str,
        author_name: str,
        author_email: str,
    ):
        self.github_helper = not_none(github_helper)
        self.release_version = not_empty(release_version)
        self.author_name = not_empty(author_name)
        self.author_email = not_empty(author_email)

    def validate(self):
        semver.parse(self.release_version)
        # if a tag with the given release version already exists github will not let us
        # create another one
        if self.github_helper.tag_exists(tag_name=self.release_version):
            raise RuntimeError(
                f"Cannot create tag '{self.release_version}' in preparation for release: "
                "Tag already exists"
            )

    def name(self):
        return "Create Release Tag"

    def apply(self):
        release_commit_sha = self.context().step_output('Create Release Commit').get(
            'release commit sha'
        )
        self.github_helper.create_tag(
            tag_name=self.release_version,
            tag_message=f'Release {self.release_version}',
            repository_reference=release_commit_sha,
            author_name=self.author_name,
            author_email=self.author_email
        )

    def revert(self):
        raise NotImplementedError('revert-method is not yet implemented')

class GitHubReleaseStep(TransactionalStep):
    def __init__(
        self,
        github_helper: GitHubRepositoryHelper,
        githubrepobranch: GitHubRepoBranch,
        repo_dir: str,
        release_version: str,
        component_descriptor_file_path:str = None,
    ):
        self.github_helper = not_none(github_helper)
        self.githubrepobranch = githubrepobranch
        self.release_version = not_empty(release_version)

        repo_dir_absolute = os.path.abspath(not_empty(repo_dir))
        self.repo_dir = repo_dir_absolute
        if component_descriptor_file_path:
            self.component_descriptor_file_path = os.path.abspath(
                not_empty(component_descriptor_file_path)
            )
        else:
            self.component_descriptor_file_path = None

    def name(self):
        return "Create Release"

    def validate(self):
        semver.parse(self.release_version)
        if self.component_descriptor_file_path:
            existing_file(self.component_descriptor_file_path)
            with open(self.component_descriptor_file_path) as f:
                # TODO: Proper validation
                not_empty(f.read().strip())

    def apply(
        self,
    ):
        # Create GitHub-release
        release = self.github_helper.create_release(
            tag_name=self.release_version,
            body=None,
            draft=False,
            prerelease=False,
        )

        # Upload component descriptor to GitHub-release if one has been calculated
        if self.component_descriptor_file_path:
            with open(self.component_descriptor_file_path) as f:
                component_descriptor_contents = f.read()
                release.upload_asset(
                    content_type='application/x-yaml',
                    name=product.model.COMPONENT_DESCRIPTOR_ASSET_NAME,
                    asset=component_descriptor_contents,
                    label=product.model.COMPONENT_DESCRIPTOR_ASSET_NAME,
                )

        return {}

    def revert(self):
        raise NotImplementedError('revert-method is not yet implemented')

class PrepareDevCycleStep(TransactionalStep):
    def __init__(
        self,
        github_helper: GitHubRepositoryHelper,
        repo_dir: str,
        repository_version_file_path: str,
        release_version: str,
        version_operation: str,
        prerelease_suffix: str,
    ):
        self.github_helper = not_none(github_helper)
        self.repo_dir=os.path.abspath(not_empty(repo_dir))
        self.repository_version_file_path = not_empty(repository_version_file_path)

        self.release_version = not_empty(release_version)
        self.version_operation = not_empty(version_operation)
        self.prerelease_suffix = not_empty(prerelease_suffix)

    def name(self):
        return "Create Next Cycle Commit"

    def validate(self):
        existing_dir(self.repo_dir)
        existing_file(os.path.join(self.repo_dir, self.repository_version_file_path))

        # perform version ops once to validate args
        self._calculate_next_cycle_dev_version(
            release_version=self.release_version,
            version_operation=self.version_operation,
            prerelease_suffix=self.prerelease_suffix,
        )

    def apply(
        self,
    ):
        next_cycle_dev_version = self._calculate_next_cycle_dev_version(
            release_version=self.release_version,
            version_operation=self.version_operation,
            prerelease_suffix=self.prerelease_suffix,
        )
        # Prepare version file for next dev cycle
        self.github_helper.create_or_update_file(
            file_path=self.repository_version_file_path,
            file_contents=next_cycle_dev_version,
            commit_message=f'Prepare next dev cycle {next_cycle_dev_version}'
        )

    def _calculate_next_cycle_dev_version(
        self,
        release_version: str,
        version_operation: str,
        prerelease_suffix: str,
    ):
        # calculate the next version and append the prerelease suffix
        return version.process_version(
            version_str=version.process_version(
                version_str=release_version,
                operation=version_operation,
            ),
            operation='set_prerelease',
            prerelease=prerelease_suffix,
        )

    def revert(self):
        raise NotImplementedError('revert-method is not yet implemented')

class PublishReleaseNotesStep(TransactionalStep):
    def name(self):
        return "Publish Release Notes"

    def __init__(
        self,
        githubrepobranch: GitHubRepoBranch,
        github_helper: GitHubRepositoryHelper,
        release_version: str,
        repo_dir: str,
    ):
        self.githubrepobranch = not_none(githubrepobranch)
        self.github_helper = not_none(github_helper)
        self.release_version = not_empty(release_version)
        self.repo_dir = os.path.abspath(not_empty(repo_dir))

    def validate(self):
        semver.parse(self.release_version)
        existing_dir(self.repo_dir)

        # check whether a release with the given version exists
        release = self.github_helper.repository.release_from_tag(self.release_version)
        if not release:
            raise RuntimeError(f'No release with tag {self.release_version} found')

    def apply(self):
        release_notes = fetch_release_notes(
            github_repository_owner=self.githubrepobranch.repo_owner(),
            github_repository_name=self.githubrepobranch.repo_name(),
            github_cfg=self.githubrepobranch.github_config(),
            repo_dir=self.repo_dir,
            github_helper=self.github_helper,
            repository_branch=self.githubrepobranch.branch(),
        )
        release_notes_md = release_notes.to_markdown()
        self.github_helper.update_release_notes(
            tag_name=self.release_version,
            body=release_notes_md,
        )
        return {
            'release notes': release_notes,
            'release notes markdown': release_notes_md,
        }

    def revert(self):
        raise NotImplementedError('revert-method is not yet implemented')

class CleanupDraftReleaseStep(TransactionalStep):
    def name(self):
        return "Cleanup Draft Release"

    def __init__(
        self,
        github_helper: GitHubRepositoryHelper,
        release_version: str,
    ):
        self.github_helper = not_none(github_helper)
        self.release_version = not_empty(release_version)

    def validate(self):
        semver.parse(self.release_version)

    def apply(self):
        draft_name = draft_release_name_for_version(self.release_version)
        draft_release = self.github_helper.draft_release_with_name(draft_name)

        if draft_release:
            # TODO: clean up ALL previously made draft-releases (just in case)
            draft_release.delete()

    def revert(self):
        raise NotImplementedError('revert-method is not yet implemented')

class PostSlackReleaseStep(TransactionalStep):
    def name(self):
        return "Post Slack Release"

    def __init__(
        self,
        slack_cfg_name: str,
        slack_channel: str,
        release_version: str,
        githubrepobranch: GitHubRepoBranch,
    ):
        self.slack_cfg_name = not_empty(slack_cfg_name)
        self.slack_channel = not_empty(slack_channel)
        self.release_version = not_empty(release_version)
        self.githubrepobranch = not_none(githubrepobranch)

    def validate(self):
        semver.parse(self.release_version)

    def apply(self):
        release_notes = self.context().step_output('Publish Release Notes').get('release notes')
        post_to_slack(
            release_notes=release_notes,
            github_repository_name=self.githubrepobranch.github_repo_path(),
            slack_cfg_name=self.slack_cfg_name,
            slack_channel=self.slack_channel,
            release_version=self.release_version,
        )

    def revert(self):
        raise NotImplementedError('revert-method is not yet implemented')

def release_and_prepare_next_dev_cycle(
    githubrepobranch: GitHubRepoBranch,
    repository_version_file_path: str,
    release_version: str,
    repo_dir: str,
    release_commit_callback: str=None,
    version_operation: str="bump_minor",
    prerelease_suffix: str="dev",
    author_name: str="gardener-ci",
    author_email: str="gardener.ci.user@gmail.com",
    component_descriptor_file_path: str=None,
    slack_cfg_name: str=None,
    slack_channel: str=None,
    rebase_before_release: bool=False,
):

    github_helper = GitHubRepositoryHelper.from_githubrepobranch(githubrepobranch)
    git_helper = GitHelper.from_githubrepobranch(
        githubrepobranch=githubrepobranch,
        repo_path=repo_dir,
    )

    release_commit_step = ReleaseCommitStep(
        git_helper=git_helper,
        repo_dir=repo_dir,
        release_version=release_version,
        repository_version_file_path=repository_version_file_path,
        repository_branch=githubrepobranch.branch(),
        release_commit_callback=release_commit_callback,
        rebase_before_release=rebase_before_release,
    )

    release_tag_step = ReleaseTagStep(
        github_helper=github_helper,
        release_version=release_version,
        author_email=author_email,
        author_name=author_name,
    )

    github_release_step = GitHubReleaseStep(
        github_helper=github_helper,
        githubrepobranch=githubrepobranch,
        repo_dir=repo_dir,
        release_version=release_version,
        component_descriptor_file_path=component_descriptor_file_path,
    )

    dev_cycle_commit_step = PrepareDevCycleStep(
        github_helper=github_helper,
        repo_dir=repo_dir,
        repository_version_file_path=repository_version_file_path,
        release_version=release_version,
        version_operation=version_operation,
        prerelease_suffix=prerelease_suffix,
    )

    release_transaction = Transaction(
        release_commit_step,
        release_tag_step,
        github_release_step,
        dev_cycle_commit_step,
    )

    release_transaction.validate()
    release_transaction.execute()

    publish_release_notes_step = PublishReleaseNotesStep(
        githubrepobranch=githubrepobranch,
        github_helper=github_helper,
        release_version=release_version,
        repo_dir=repo_dir,
    )

    cleanup_draft_releases_step = CleanupDraftReleaseStep(
        github_helper=github_helper,
        release_version=release_version,
    )

    release_notes_steps = [
        publish_release_notes_step,
        cleanup_draft_releases_step,
    ]

    if slack_cfg_name and slack_channel:
        post_to_slack_step = PostSlackReleaseStep(
            slack_cfg_name=slack_cfg_name,
            slack_channel=slack_channel,
            release_version=release_version,
            githubrepobranch=githubrepobranch,
        )
        release_notes_steps.append(post_to_slack_step)

    release_notes_transaction = Transaction(*release_notes_steps)
    release_notes_transaction.validate()
    release_notes_transaction.execute()


from django.conf import settings
from django.db import models
from django_countries.fields import CountryField

# Items Model(Tour Trips)
class Item(models.Model):

    title = models.CharField(max_length=200)
    slug = models.SlugField()
    descriptions = models.CharField(max_length=20000)
    adult_price = models.FloatField()
    children_price = models.FloatField()
    route_code = models.CharField(max_length=20, blank=True, null=True)
    trip_duration = models.IntegerField(null=True)
    from_city = models.CharField(max_length=100)
    to_city = models.CharField(max_length=100)
    start_date = models.DateField()
    img = models.ImageField()
    terms_conditions = models.CharField(max_length=2000)

    def __str__(self):
        return self.title

# order item in shopping cart
class OrderItem(models.Model):

    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             on_delete=models.CASCADE)
    ordered = models.BooleanField(default=False)
    item = models.ForeignKey(Item, on_delete=models.CASCADE)
    quantity = models.IntegerField(default=1)

    def __str__(self):
        return f"{self.quantity} of {self.item.title}"

    def get_final_price(self):
        return 133

# manage ordered order
class Order(models.Model):

    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             on_delete=models.CASCADE)
    ref_code = models.CharField(max_length=20, blank=True, null=True)
    items = models.ManyToManyField(OrderItem)
    start_date = models.DateTimeField(auto_now_add=True)
    ordered_date = models.DateTimeField()
    ordered = models.BooleanField(default=False)
    shipping_address = models.ForeignKey(
        'Address', related_name='shipping_address', on_delete=models.SET_NULL, blank=True, null=True)
    billing_address = models.ForeignKey(
        'Address', related_name='billing_address', on_delete=models.SET_NULL, blank=True, null=True)
    payment = models.ForeignKey(
        'Payment', on_delete=models.SET_NULL, blank=True, null=True)
    coupon = models.ForeignKey(
        'Coupon', on_delete=models.SET_NULL, blank=True, null=True)
    being_delivered = models.BooleanField(default=False)
    received = models.BooleanField(default=False)
    refund_requested = models.BooleanField(default=False)
    refund_granted = models.BooleanField(default=False)

    def __str__(self):
        return self.user.username

# addressed model
ADDRESS_CHOICES = (
    ('B', 'Billing'),
    ('S', 'Shipping'),
)

class Address(models.Model):

    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             on_delete=models.CASCADE)
    street_address = models.CharField(max_length=100)
    apartment_address = models.CharField(max_length=100)
    country = CountryField(multiple=False)
    zip_code = models.CharField(max_length=100)
    address_type = models.CharField(max_length=1, choices=ADDRESS_CHOICES)
    default = models.BooleanField(default=False)

    def __str__(self):
        return self.user.username

    class Meta:
        verbose_name_plural = 'Addresses'

# payment model
class Payment(models.Model):

    stripe_charge_id = models.CharField(max_length=50)
    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             on_delete=models.SET_NULL, blank=True, null=True)
    amount = models.FloatField()
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.user.username

# coupon

class Coupon(models.Model):

    code = models.CharField(max_length=15)
    amount = models.FloatField()

    def __str__(self):
        return self.code

# manage refund
class Refund(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    reason = models.TextField()
    accepted = models.BooleanField(default=False)
    email = models.EmailField()

    def __str__(self):
        return f"{self.pk}"

# homepage slider data

class AdItem(models.Model):
    item = models.ForeignKey(
        Item, on_delete=models.CASCADE, related_name='AdItem')
    adImage = models.ImageField()
    title = models.CharField(max_length=30)
    brief = models.CharField(max_length=150)

    def __str__(self):
        return self.title

# Trip detail images for detail page

class ItemDetailImg(models.Model):
    item = models.ForeignKey(
        Item, on_delete=models.CASCADE, related_name='images')
    image = models.ImageField()

    @property
    def image_url(self):
        return "{0}{1}".format('http://127.0.0.1:8000', self.image.url)


from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.core.urlresolvers import reverse_lazy
from django.forms.formsets import formset_factory
from collections import OrderedDict
from django.views.generic import TemplateView
from django.http import HttpResponseRedirect
import json
from django.core import serializers
from app.citas.forms import *
from app.citas.models import *
from app.informacion.models import *

# Create your views here.
def citas_crear(request):

	user = request.user.id
	if request.method == 'POST':
		form2 = citasForm(request.POST,initial={})
		form = citasGeneralesForm(request.POST,initial={})
		if form.is_valid() and form2.is_valid():
			form.save()
			form2.save()
		return HttpResponseRedirect('/')
	else:

		form2 = citasForm(initial={})
		form = citasGeneralesForm(initial={'estudiante':request.user.username})
	return render(request, 'citas/citas_crear.html', {'form':form,'form2':form2})

def citas_crear2(request):

	user = request.user.id
	if request.method == 'POST':
		form2 = citasForm(request.POST,initial={})
		form = citasGeneralesForm(request.POST,initial={})
		if form.is_valid() and form2.is_valid():
			form.save()
			form2.save()
		return HttpResponseRedirect('/')
	else:

		form2 = citasForm(initial={})
		form = citasGeneralesForm(initial={'estudiante':request.user.username})
	return render(request, 'citas/citas_crear2.html', {'form':form,'form2':form2})

class BusquedaAjaxView(TemplateView):
	def get(self,request,*args,**kwargs):
		cod = request.GET['codigo']
		nombre = datos_generales.objects.filter(cod_expediente=cod)
		citass = citas_general.objects.filter(codigo_id=cod)

		data = serializers.serialize('json', nombre, fields=('nombre_completo'))

		return HttpResponse(data, content_type='application/json')

class BusquedaAjaxView2(TemplateView):
	def get(self,request,*args,**kwargs):
		cod = request.GET['codigo']
		#nombre = datos_generales.objects.filter(cod_expediente=cod)
		citass = citas_general.objects.filter(codigo_id=cod)
		#algo = citass[0]
		#aparato2 = dict(aparato_choices).get(algo['aparato'])
		data = serializers.serialize('json', citass, fields=('aparato'))
		#data = json.dumps({
        #'aparato': aparato2,
    	#})
		return HttpResponse(data, content_type='application/json')

class BusquedaCitasListar(TemplateView):
	def get(self,request,*args,**kwargs):
		cod = request.GET['codigo']
		citas2 = citas.objects.filter(codigo_id=cod)

		data2 = serializers.serialize('json', citas2,fields=('codigo','num_cita','fecha_cita','observaciones','proxima_cita','resultados','autorizacion','tutor'))
		return HttpResponse(data2, content_type='application/json')

def registrocita(request,codi):
	user = request.user.id
	str(codi)
	entro = 0;

	num=0
	queryset = citas_general.objects.filter(codigo_id=codi)
	if queryset:
		entro = 1
		num = len(queryset)
	#	return HttpResponseRedirect('/informacion/datos_generales/editar/%s/' %codi)

	if request.method == 'POST':
		if entro == 1:
			form2 = citasForm2(request.POST)
			if form2.is_valid():
				form2.save()
			return HttpResponseRedirect('/citas/cerrar/')
		else:

			form2 = citasForm2(request.POST)
			form = citasGeneralesForm2(request.POST)
			if form.is_valid() and form2.is_valid():
				form.save()
				form2.save()
			return HttpResponseRedirect('/citas/cerrar/')
	else:

		if entro ==	 1:
			form2 = citasForm2(initial={'codigo':codi,'num_cita':num+1})
			return render(request, 'citas/ventana2.html', {'form2':form2})
		else:
			form = citasGeneralesForm2(initial={'codigo':codi,'estudiante':request.user.id})
			form2 = citasForm2(initial={'codigo':codi,'num_cita':num+1})

			return render(request, 'citas/ventana1.html', {'form':form,'form2':form2})


""" Programa que calcula distancia percorrida"""
distancia = int(input('Diga qual distância percorrica em km: '))
viagem1 = distancia * .50
viagem2 = distancia * .45
cobranca = 0

if distancia < 200:
    cobranca = viagem1
else:
    cobranca = viagem2
print(f'Sua viagem de {distancia}km, deu um total de R${cobranca}.')


import os
import h5py
import json
from device_server.device import DefaultDevice

class AndorCam(DefaultDevice):

    _data_directory = os.path.join(os.getenv('LABRADDATA'), 'data')
    _compression = 'gzip'
    _compression_level = 4

    def initialize(self, config):
        # super(AndorCam, self).initialize(config)
        # self.connect_to_labrad()
        """ To be implemented by child class """

    def config(self, record_path = None, record_type = None, record_setting={}):
        """ To be implemented by child class """

    def record(self, record_path = None, record_type = None, record_setting={}):
        """ To be implemented by child class """

    def _save(self, images, record_path):
        data_path = os.path.join(self._data_directory, record_path + '.hdf5')
        data_directory = os.path.dirname(data_path)
        if not os.path.isdir(data_directory):
            os.makedirs(data_directory)

        h5f = h5py.File(data_path, "w")
        for image in images:
            h5f.create_dataset(image, data=images[image],
                    compression=self._compression,
                    compression_opts=self._compression_level)
        h5f.close()

    def _send_update(self, record_path, record_type, record_settings):
        signal = {
            self.name: {
                'record_path': record_path,
                'record_type': record_type,
                'record_settings': record_settings,
                },
            }
        self.server.update(json.dumps(signal))


# https://atcoder.jp/contests/abc120/tasks/abc120_a

import math

a, b, c = list(map(int, input().split()))
cnt = math.floor(b / a)
if c <= cnt:
    print(c)
else:
    print(cnt)


import torch
import random
import pickle
import numpy as np
from torch.utils.data import Dataset

class Aozora(Dataset):
    def __init__(self, args, path):
        data = self.load_data(path)
        X = np.array([body for body in data["body"]])
        label = [author for author in data["author"]]
        label_names = list(set(label))
        label_names.sort()
        y = np.array([label_names.index(label[i]) for i in range(len(label))])

        self.data = list(zip(X, y))
        self.label_names = label_names
        self.char_len = args.char_len
        self.char2idx = self.get_char2idx(X)

    def __len__(self):
        return len(self.data)

    def __getitem__(self, i):
        sentence, label = self.data[i]

        sentence = self.cutout_or_padding(sentence)
        sentence = [self.char2idx[char] for char in sentence]
        sentence = np.array(sentence)
        sentence = torch.from_numpy(sentence)

        return sentence, label

    def load_data(self, path):
        with open(path, "rb") as bf:
            data = pickle.load(bf)

        return data

    def get_char2idx(self, text):
        chars = set()
        for sentence in text:
            for char in sentence:
                chars.add(char)

        return {char: idx for idx, char in enumerate(chars)}

    def get_vocab_size(self):
        return len(self.char2idx)

    def get_num_class(self):
        return len(self.label_names)

    def cutout(self, sentence):
        k = random.randint(0, len(sentence) - self.char_len)
        cutout_sentence = [c for c in sentence[k : k + self.char_len]]

        return cutout_sentence

    def padding_sentence(self, sentence):
        if len(sentence) < self.char_len:
            sentence += " " * (self.char_len - len(sentence))

        return sentence

    def cutout_or_padding(self, sentence):
        sentence = self.padding_sentence(sentence)

        return self.cutout(sentence)


import socket,pickle
from threading import Thread
from threading import Condition
import time
import numpy as np
import picamera
import picamera.array
from PIL import Image

Fotos = []
vetor = []
finliza = 0
booleano = 0
ultimaFoto = []
class Cliente(Thread):
    def run(self):
        global booleano
        #HOST = '192.168.0.108'
        #PORT = 4000
        #udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        #dest = (HOST,PORT)
        msgEnvio = "msg"
        i = 0
        while (True):
            with picamera.PiCamera() as camera:
                with picamera.array.PiRGBArray(camera) as output:
                    print(output)
                    camera.resolution = (256, 256)
                    camera.capture(output, 'rgb')
                    print("tirou")
                    #ultimaFoto = camera.capture("Ap/Foto" + str(i) +".jpg")
                    Fotos.append(np.asarray(output.array).reshape(-1))
                    print(len(Fotos[-1]))
                    vetor.append( str(Fotos[-1]) + "testePWM")
                    grava()
                    #condicao.notify()
                    #print("Tirou foto")
          #  udp.sendto(msgEnvio, dest)
        print("Acabou fotos")
        #udp.sendto("end",dest)
        #udp.close()

class Servidor(Thread):
    def run(self):
        global vetor
        global booleano
        HOST = ''              # Endereco IP do Servidor
        PORT = 5000            # Porta que o Servidor esta
        udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        orig = (HOST, PORT)
        udp.bind(orig)
        msg = "seila"
        while msg != "end":
            msg, cliente = udp.recvfrom(1024)
            Fotos[-1].append(msg)
        print("gravando")
        booleano =1

        udp.close()

class Cliente2PC(Thread):
    def run(self):
        HOST2 = '192.168.0.109'
        PORT2 = 5050
        udp2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        dest2 = (HOST2,PORT2)
        i =0
        while (booleano != 1):
            cont = 0
            while(cont<5):
                condicao.acquire()
                cont = cont + 1
                dados = Fotos.pop(0)
                fotosMsg = ' '.join(str(e) for e in dados)

                #texto = ' '.join(str(e) for e in Dados)
                #texto = texto + vetor.pop(0)
                texto = "UDP> TCP"

                udp2.sendto(fotosMsg, dest2)
        print("Acabou fotos")
        udp2.sendto("end",dest2)
        udp2.close()

class ClientePC(Thread):
    def run(self):
        global vetor
        HOST = '192.168.0.109'
        PORT = 5050
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        s.connect((HOST,PORT))
        cont = 0
        while(cont<5):
            if len(Fotos)==0:
                condicao.wait()
            condicao.acquire()
            cont = cont + 1
            Dados = Fotos.pop(0)
            print(len(Dados))
            condicao.release()
            #texto = ' '.join(str(e) for e in Dados)
            #texto = texto + vetor.pop(0)
            texto = "UDP> TCP"
            s.send(texto)
        s.close()

def grava():
    #Cliente().stop()
    #Servidor().stop()
    #arq = open("/home/pi/BancoFotos/fotos1.txt","w")
    print("abriu arquivo")
    #print(len(Fotos))
    #np.concatenate((Fotos, vetor.T), axis=1)
    cont = 0
    for i in Fotos:
        for e in i:
            arq.write(str(e))
            arq.write(",")
        arq.write(" saida ")
        arq.write(vetor[cont])
        arq.write("!")
        cont+=1
        arq.write("\n")
        print("foi uma")

    print("gravou")
    arq.close
    exit()
def grava1():
    #Cliente().stop()
    #Servidor().stop()
    print("abriu arquivo")
    #np.concatenate((Fotos, vetor.T), axis=1)
    cont = 0
    for i in Fotos:
        text = ""
        for e in i:

            text.append((e))
            text.append(" ")
        text.append((vetor[cont]))
        text.append("\n")
        cont+=1
        arq.write(text)
        print("foi uma")
    print("gravou")
    arq.close

arq = open("/home/pi/BancoFotos/fotos1.txt","w")

Cliente().start()
#Servidor().start()

#Cliente().exit()
#Servidor().exit()
while(booleano == 0):
      h=0

grava()
#Cliente2PC().start()


import numpy as np
import math

class NaiveMove:
    def __init__(self):
        self.done = False

    def moveTo(self, pos, angle, goal):
        if ((pos[0]-goal[0])**2 + (pos[1]-goal[1])**2) < 0.01:
            return [0, 0], 0
            self.done = True
        else:
            self.done = False
        MAX_ACC = 1.5 * (1/30.0)
        pos_delta = np.array([goal[0]-pos[0], goal[1]-pos[1]])
        target_angle = math.atan2(pos_delta[1], pos_delta[0])
        pos_delta = pos_delta.reshape([2, 1])
        mat_angle = np.array([
            [math.cos(angle), math.sin(angle)],
            [math.sin(angle), -math.cos(angle)]])
        v_target = np.matmul(np.linalg.inv(mat_angle), pos_delta).reshape([2])
        v_target /= np.abs(v_target).max()
        #v_now = np.array(vel)
        #v_delta = v_target - v_now
        #print(v_target, v_now, v_delta)
        #v_delta /= np.abs(v_delta).max()

        #MAX_ACC = min(MAX_ACC, np.abs(0.5 - v_now).max())
        #v_real = v_delta*MAX_ACC + v_now
        #print(goal, v_real)
        return v_target, target_angle - angle


from typing import NamedTuple

from sanic import Blueprint, response

def jsonapi(status=None, data=None, included=None, errors=None, links=None, meta=None):
    return JSONAPIResponse(status, data or [ ], included or [ ], errors or [ ], links or { }, meta or { })

class JSONAPIResponse(NamedTuple):
    status:   int
    data:     list
    influded: list
    errors:   list
    links:    dict
    meta:     dict

class Empty(object):
    pass

class JSONAPIMixin(object):

    @classmethod
    async def create(cls, request):
        raise NotImplementedError()

    @classmethod
    async def read(cls, request, id=None):
        raise NotImplementedError()

    @classmethod
    async def update(cls, request, id):
        raise NotImplementedError()

    @classmethod
    async def delete(cls, request, id):
        raise NotImplementedError()

    @classmethod
    async def read_related(cls, request, id, RelatedModel):
        raise NotImplementedError()

    @classmethod
    async def set_related(cls, request, id, RelatedModel):
        raise NotImplementedError()

    @classmethod
    async def update_related(cls, request, id, RelatedModel):
        raise NotImplementedError()

    @classmethod
    async def delete_related(cls, request, id, RelatedModel):
        raise NotImplementedError()

    @classmethod
    def from_jsonapi(cls, json):
        id = json.get('id')
        type = json.get('type')
        attributes = json.get('attributes')
        relationships = json.get('relationships')

        if not type:
            pass

        if not type == cls._table:
            pass

        if not attributes:
            pass

        model = cls(attributes)

        if id:
            model.id = id

        return model

    def to_jsonapi(self, request=None):
        data = { }

        data['type'] = self._table
        data['id'] = self.id
        data['meta'] = { 'primary_key': self._primary }

        data['attributes'] = self.serialize(validate=True)

        return data

    @classmethod
    def blueprint(cls, **kargs):
        bp = Blueprint(cls._table, **kargs)

        accepted_type = 'application/vnd.api+json'

        def endpoint(handler):
            async def decorator(request, *args, **kargs):
                response = await handler(request, *args, **kargs)

                if not type(response) == JSONAPIResponse:
                    response = jsonapi(status=500, errors=[ Error(
                        status = 500,
                        title = 'Invalid Handler Response',
                        detail = 'Handler did not respond with a JSONAPIResponse object.'
                    ) ])

                data = { }

                if response.data is Empty:
                    data['data'] = None
                elif isinstance(response.data, Model):
                    data['data'] = response.data.to_jsonapi(request)
                elif isinstance(response.data, list):
                    if len(response.data) == 1 \
                        and response.data[0] is Empty:
                        data['data'] = [ ]
                    elif len(response.data) > 1:
                        data['data'] = list(map(lambda model: \
                            model.to_jsonapi(request), response.data))
                    #else the list is empty, ignore it
                else:
                    # XXX: this is an error
                    pass

                if response.errors:
                    data['errors'] = list(map(lambda error: \
                        error.serialize(), response.errors))

                return json(data, status=response.status, content_type=accepted_type)
            return decorator

        def content_type(handler):
            async def decorator(request, *args, **kargs):
                content_type = request.headers.get('Content-Type')
                if not content_type or not content_type == accepted_type:
                    return jsonapi(status=415, errors=[ Error(
                        status = 415,
                        title = 'Invalid Content-Type Header',
                        links = {
                            'about': 'http://jsonapi.org/format/#content-negotiation'
                        }
                    ) ])
                return await handler(request, *args, **kargs)
            return decorator

        def accept(handler):
            async def decorator(request, *args, **kargs):
                accept = request.headers.get('Accept')
                if not accept or not accept == accepted_type:
                    return jsonapi(status=415, errors=[ Error(
                        status = 415,
                        title = 'Invalid Accept Header',
                        links = {
                            'about': 'http://jsonapi.org/format/#content-negotiation'
                        }
                    ) ])
                return await handler(request, *args, **kargs)
            return decorator

        def validate(handler):
            async def decorator(request, *args, **kargs):
                errors = [ ]
                json = request.json

            return decorator

        # collection routes

        @bp.get(cls._route)
        @endpoint
        @accept
        async def _(request):
            return await cls.read(request)

        @bp.post(cls._route)
        @endpoint
        @content_type
        @accept
        async def _(request):
            return await cls.create(request)

        # item routes

        @bp.get(cls._route + '/<id>')
        @endpoint
        @accept
        async def _(request, id):
            return await cls.read(request, id)

        @bp.patch(cls._route + '/<id>')
        @endpoint
        @content_type
        @accept
        async def _(request, id):
            return await cls.update(request, id)

        @bp.delete(cls._route + '/<id>')
        @endpoint
        @accept
        async def _(request, id):
            return await cls.delete(request, id)

        # relationship routes

        for field in cls._related:

            route = cls._route + '/<id>/reliationships/' + field.name

            @bp.get(route)
            @endpoint
            @accept
            async def _(request, id):
                return await cls.read_related(request, id, field.type)

            @bp.patch(route)
            @endpoint
            @content_type
            @accept
            async def _(request, id):
                return await cls.set_related(request, id, field.type)

            if field.related == 'many':

                @bp.post(route)
                @endpoint
                @content_type
                @accept
                async def _(request, id):
                    return await cls.update_related(request, id, field.type)

                @bp.delete(route)
                @endpoint
                @accept
                async def _(request, id):
                    return await cls.delete_related(request, id, field.type)

        return bp


import tkinter
import random
import tkinter.ttk
import tkinter.messagebox

#this is the first step to creating a class
class Core:
    #obvious initialize for class
    def __init__ (self): #declares the class or something. You need it though, all references in the class with require the declared holder of "self" as a prefix in order to work
        # 'self' is a necessary declaration. After the init, anything related to the class mush be declared as a member of 'self'
        #internal vars
        self.gResponse = 'Welcome!'
        self.initial = True
        self.RandNum = 50
        self.CorTot = 0
        self.TryTot = 0
        self.stop = 0
        self.Guess = 0
        #this sequence just generates the ranom number on launch, 'initial' is to prevent looping random nuber generations
        if self.initial == True:
            self.RandNum = random.randint(1,100)
            self.gResponse = 'Welcome! \n The initial random number was \n successfully generated. \n Pick a number between 1 and 100'
            self.initial = False
                #//window setup
        self.MainWindow = tkinter.Tk()
            #//declares the window instance, ie: create the window
        WinXLen = 400
            #//desired x in pixels for the window lenght
        WinYHigh = 325
            #//desired y in pixels for the window height
        MonitorX = self.MainWindow.winfo_screenwidth()
            #//fetches the screen resolution|||this gets the horizontal screen resolution
        MonitorY = self.MainWindow.winfo_screenheight()
            #//fetches the screen resolution|||this gets the vertical screen resolution
        xCenter = MonitorX/2 - WinXLen/2
            #//This calculates the horizontal center of your monitor(s)
        yCenter = MonitorY/2 - WinYHigh/2
            #This calculate the vertical center of your monitor(s)
        self.MainWindow.geometry('%dx%d+%d+%d' % (WinXLen, WinYHigh, xCenter, yCenter))
            #//this takes the previous dimensions and in order,
            #%d establishes the dimensional vars. WinXLen,WinYHigh=Window size | xCenter,yCenter=Where to spawn the window by center.
        self.MainWindow.configure(background='#b8cce4')
            #//this is just a simple background color test, given in hex r(00-ff) g(00=ff) b(00-ff)
        self.MainWindow.title('Randomulator')
            #//sets the title bar on the window
            #
            #//declarations of widgets(objects on the window)
            #//widgets have to be declared in the same manner as variables
            #// 'self' is a necessary declaration. After the init, anything related to the class mush be declared as a member of 'self'
        self.WinProgBar = tkinter.ttk.Progressbar(self.MainWindow, orient='horizontal', mode='determinate', maximum=20, variable=self.stop)
            #//Not fully implemented, but is a decent filler on the window. Not coded.
        self.RandGenBtn = tkinter.Button(self.MainWindow, text='Generate \n my \n random \n number!',command=self.RandGen)
                #//The random number generator button
        self.GuessBtn = tkinter.Button(self.MainWindow, text='Did I get it right?',command=self.answertron)
                #//The button to submit your guess
        #//Button: (self.Window's name = MainWindow, text = whatever string you want the button to say. Bemindful of the size,
                                                                                #//command(an internal method(self).Method Name)
                                                                                #//What the button does
        self.GuessEntry = tkinter.Entry(self.MainWindow)
                #//The text feild you enter your number into
        self.ScoreLbl = tkinter.Label(self.MainWindow, text='Scoreboard')
        self.sbCorLbl = tkinter.Label(self.MainWindow, text='Correct')
        self.sbTryLbl = tkinter.Label(self.MainWindow, text='Total Tries')
                #//'Static Labels' whatever you set the text= to, the lable will display permanently
        self.DynamicLbl = tkinter.Label(self.MainWindow, text=str(self.gResponse))
        self.sbCorTot = tkinter.Label(self.MainWindow,text=str(self.CorTot))
        self.sbTryTot = tkinter.Label(self.MainWindow,text=str(self.TryTot))
                #//'Dynamic Lable' difference is the text=str(self.VarName)
                                                        #This makes the window poll the variable everytime it cycles
                        #//Widget Configuration Options
        self.RandGenBtn.configure(background='#b8cce4',relief='raised')
        self.GuessBtn.configure(background='#4f90bd',relief='groove')
        self.GuessEntry.configure(relief='sunken')
        self.ScoreLbl.configure(background='#bfbfbf',relief='sunken')
        self.sbCorLbl.configure(background='#92d050',relief='sunken')
        self.sbTryLbl.configure(background='#c00000',relief='sunken')
        self.DynamicLbl.configure(background='#b8cce4',relief='sunken')
        self.sbCorTot.configure(background='#92d050',relief='sunken')
        self.sbTryTot.configure(background='#c00000',relief='sunken')
                #//For most widgets, the options are available
                #//background= '#ffffff'   This changes the backcolor of the widget,
                #//The color values are presented in hex for ease of use, R=ff=255 G and b
        self.WinProgBar.pack()
        self.RandGenBtn.pack()
        self.DynamicLbl.pack()
        self.GuessEntry.pack()
        self.GuessBtn.pack()
        self.ScoreLbl.pack()
        self.sbCorLbl.pack()
        self.sbCorTot.pack()
        self.sbTryLbl.pack()
        self.sbTryTot.pack()
                #this packs up the widget configurations
                #
                #//There are 3 ways to place widgets on the window:
                    #//Frame, some control but not absolute for widget space. empty spaces are ignored
                    #//Grid, a little more control than the frame window, empty space is still ignored
                    #//Place, My choice, total control of widget placement and widget sizes
        self.WinProgBar.place(height=25, width=350, x= 25, y= 150)
        self.RandGenBtn.place(height=100, width=100, x= 25, y= 25)
        self.DynamicLbl.place(height=100, width=200, x= 175, y= 25)
        self.GuessEntry.place(height=25, width=100, x= 25, y= 175)
        self.GuessBtn.place(height=25, width=250, x= 125, y= 175)
        self.ScoreLbl.place(height=25, width=250, x= 75  , y= 225)
        self.sbCorLbl.place(height=25, width=125, x= 75  , y= 250)
        self.sbCorTot.place(height=25, width=125, x= 75  , y= 275)
        self.sbTryLbl.place(height=25,width=125,x= 200,y= 250)
        self.sbTryTot.place(height=25,width=125,x=200,y= 275)
                    #// For the placement methods, Place only works AFTER all .pack()'s are declared
                    #//     .place(height=[widget height in pixels], width=[widget width in pixels],
                    #//             x=[from left, where to place the widget by positive valued pixels]
                    #//             y=[from top, where to place the widget by positive valued pixels] |value|=distance from window top-left
        #
        #place no methods before this declaration
        #the loop keeps the window in a constant state, one iteration would go by to quick to even notice
        tkinter.mainloop()

        #internal functions, notice the indentation
        #def Name(self, the function is slaved to the 'def __init__(self):

        #this function is to generate the random number whenever it is called by a widget's 'command=self.'Function Name'
        #to use the class level vars, self must be the root family as would be with imported functions
        #all that aside, pretty much the same.
    def RandGen(self):
        self.RandNum = random.randint(1,100)
        self.gResponse = 'Random number \n generation complete.'
        self.DynamicLbl.configure(text=str(self.gResponse))
            #this part changes the widget's configuration(option) in this case,
            #the option is to change the lable's text value.
            #the text=str(self.VAR) must be used to refrese the widget
            #
            #this funtion handles all possible guesses the-
            # user may try after pressing the guess button
    def answertron(self):
        try:
            iGuess = int(self.GuessEntry.get())
            self.Guess = iGuess
                # the int(self.GuessEntry.get()) transforms the text input into an integer value
            if self.Guess < 1:
                self.gResponse = 'Wrong, just... wrong.'
                tkinter.messagebox.showinfo('Results', 'Just a number between 1 and 100... positve!')
                self.TryTot += 1
            elif self.Guess > 100:
                self.gResponse = ('C''mon! Just a whole number between +1 and +100')
                tkinter.messagebox.showinfo('Results', 'Now you''re just just to push the limit aren''t you! \n The number must be less than or equal to 100')
                self.TryTot += 1
                #these first two functions determine the bounds of the game.
                #tkinter.messagebox.showinfo('Results(Declares the window as a result of functions)', The popup text)
                #the internals are changed here. the implementation of the variables is at the end
                #the popups are snarky, so don't be offended
                #
                #the following elif's under the try clause set responses for varying levels of the guess:randomnumber
            elif self.Guess > self.RandNum + 15 and self.RandNum < 85:
                self.gResponse = 'Way off the \n mark rocketman. \n Aim lower.'
                self.TryTot += 1
                #the next two clauses will be explained here \/
            elif self.Guess < self.RandNum +15 and self.Guess > self.RandNum:
                self.gResponse = 'Very close, but too high.'
                self.DynamicLbl.configure(text=str(self.gResponse))
                self.TryTot += 1
                #The elif clauses check the guess against the number for the following:
                #If the guess is within a threshold and if the number is with the threshold
            elif self.RandNum > 85 and self.Guess > self.RandNum:
                self.gResponse = 'Very close, but too high.'
                self.TryTot += 1
            elif self.Guess == self.RandNum:
                self.gResponse = 'Congratulations! \n You guessed the correct number!'
                self.TryTot += 1
                self.CorTot += 1
                self.RandNum=random.randint(1,100)
                    #Beginning of the threshold check
            elif self.RandNum < 15 and self.Guess < self.RandNum:
                self.gResponse ='Very close, \n but too low.'
                self.TryTot += 1
            elif self.Guess > self.RandNum - 15 and self.Guess < self.RandNum:
                self.gResponse ='Very close, \n but too low.'
                self.TryTot += 1
                    #end threshold check
            elif self.Guess < self.RandNum - 15 and self.RandNum > 15:
                self.gResponse = 'Way off the mark scuba diver. \n Try swimming towards the surface, \n you know, up.'
                self.TryTot += 1
        except ValueError:      #if the number is invalid or not even a number
            iGuess = str(self.GuessEntry.get())
                # the str(self.GuessEntry.get()) transforms whatever was entered from the field into a string, if it meets the except criteria
            tkinter.messagebox.showinfo('Results', 'Yes, "' + str(iGuess) + '" was the whole number I was thinking of')
                #These last three refresh their associated widgets
        self.DynamicLbl.configure(text=str(self.gResponse))
        self.sbTryTot.configure(text=str(self.TryTot))
        self.sbCorTot.configure(text=str(self.CorTot)) #end class
game_start = Core()
#creates an instance of the class and activates it
#much like x = input() the Core() is doing its own thing


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

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

class DQN(object):
    def __init__(self, n_states, n_actions, learning_rate=0.005, epsilon=1,
                 epsilon_min=0.001, epsilon_decay_step=300, gamma=0.95, batch_size=50):
        self.n_states = n_states
        self.n_actions = n_actions
        self.learning_rate = learning_rate
        self.epsilon = epsilon
        self.epsilon_min = epsilon_min
        self.epsilon_decay_step = epsilon_decay_step
        self.gamma = gamma
        self.batch_size = batch_size

        self.learning_step = 0
        self.params_replace_step = 50

        self.memory_size = 5000
        self.memory_counter = 0
        self.memory = np.zeros([self.memory_size, self.n_states * 2 + 3])

        self._build_net()

        self.session = tf.Session()
        self.session.run(tf.global_variables_initializer())

        self.loss_his = []

    def _build_net(self):

        k_init, b_init = tf.random_uniform_initializer(0., 0.2), tf.constant_initializer(0.1)

        # build eval net
        self.s = tf.placeholder(tf.float32, [None, self.n_states], name='s')
        self.a = tf.placeholder(tf.int32, [None], name='a')
        self.q_target = tf.placeholder(tf.float32, [None], name='q_target')
        self.s_ = tf.placeholder(tf.float32, [None, self.n_states], name='s_')

        with tf.variable_scope('eval_net'):
            hl_1 = tf.layers.dense(inputs=self.s, units=64,
                                   activation=tf.nn.relu,
                                   kernel_initializer=k_init,
                                   bias_initializer=b_init,
                                   name='hl_1')
            self.eval_net = tf.layers.dense(inputs=hl_1, units=self.n_actions,
                                            activation=None,
                                            kernel_initializer=k_init,
                                            bias_initializer=b_init,
                                            name='eval_net')

        # build target net
        with tf.variable_scope('target_net'):
            hl_1 = tf.layers.dense(inputs=self.s_, units=64,
                                   activation=tf.nn.relu,
                                   kernel_initializer=k_init,
                                   bias_initializer=b_init,
                                   name='hl_1')
            self.target_net = tf.layers.dense(inputs=hl_1, units=self.n_actions,
                                              activation=None,
                                              kernel_initializer=k_init,
                                              bias_initializer=b_init,
                                              name='target_net')

        with tf.variable_scope('loss'):
            actions_reward = tf.reduce_sum(tf.multiply(self.eval_net, tf.one_hot(indices=self.a, depth=self.n_actions)), reduction_indices=1)
            self.loss = tf.reduce_mean(tf.square(self.q_target - actions_reward))
        with tf.variable_scope('train'):
            optimizer = tf.train.GradientDescentOptimizer(self.learning_rate)
            self.train_op = optimizer.minimize(self.loss)

    def _update_params(self):
        e_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='eval_net')
        t_params = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='target_net')
        update_params_op = [tf.assign(t, e) for t, e in zip(t_params, e_params)]  # update target net params
        self.session.run(update_params_op)

    def choose_action(self, s):
        s = s[np.newaxis, :]
        if np.random.uniform() > self.epsilon:
            action_values = self.session.run(self.eval_net, feed_dict={self.s: s})
            action = np.argmax(action_values)
        else:
            action = np.random.choice(range(self.n_actions))
        return action

    def store_transition(self, s, a, r, s_, terminal):
        transition = np.hstack((s, a, r, s_, terminal))
        index = self.memory_counter % self.memory_size
        self.memory[index, :] = transition
        self.memory_counter += 1

    def learn(self):
        if self.learning_step % self.params_replace_step == 0:
            self._update_params()

        if self.memory_counter <= self.memory_size:
            index = np.random.choice(self.memory_counter, self.batch_size)
        else:
            index = np.random.choice(self.memory_size, self.batch_size)
        batch_memory = self.memory[index, :]

        bs = batch_memory[:, :self.n_states]
        ba = batch_memory[:, self.n_states]
        br = batch_memory[:, self.n_states+1]
        bs_ = batch_memory[:, -(self.n_states+1):-1]
        bt = batch_memory[:, -1]

        q_next = self.session.run(self.target_net, feed_dict={self.s_: bs_})
        q_next = np.max(q_next, axis=1)
        q_target = br + self.gamma*q_next*bt

        _, loss = self.session.run([self.train_op, self.loss],
                                   feed_dict={self.s: bs,
                                              self.a: ba,
                                              self.q_target: q_target})

        self.loss_his.append(loss)

        self.learning_step += 1
        self.epsilon = (self.epsilon - self.epsilon_min)/self.epsilon_decay_step

    def plot_result(self, data, x_label, y_label):
        plt.plot(np.arange(len(data)), data)
        plt.xlabel(x_label)
        plt.ylabel(y_label)
        plt.show()