# encoding: utf-8
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from django.contrib import messages
from project.views import busca_configuracoes

from enderecos.forms import BairroForm, CidadeForm
from enderecos.models import Bairro, Cidade

# Create your views here.
template_bairro_novo = 'enderecos/bairro/bairro.html'
template_bairro_add = 'enderecos/bairro/bairro_add.html'

mensagem_geral = ''

def bairro_home(request, dados={}):
    dados['lista_bairros'] = Bairro.objects.all().order_by('nome')
    form = BairroForm()
    dados['form'] = form
    busca_configuracoes(request, dados)
    return render(request, template_bairro_novo, dados)

def bairro_editar(request, id):
    dados = {}
    bairro = get_object_or_404(Bairro, id=id)

    form = BairroForm(instance=bairro)
    dados['form'] = form

    dados['bairro'] = bairro
    dados['detalhe'] = 'detalhe'
    dados['modo'] = 'EDICAO'
    return render(request, template_bairro_add, dados)

def bairro_detalhe(request, id):
    dados = {}
    bairro = get_object_or_404(Bairro, id=id)

    form = BairroForm(instance=bairro)
    for field in form.fields.values():
        field.widget.attrs['disabled'] = 'True'
    dados['form'] = form

    dados['bairro'] = bairro
    dados['detalhe'] = 'detalhe'
    return render(request, template_bairro_add, dados)

def bairro_adiciona(request):
    dados = {}
    form = BairroForm(request.POST or None)

    if request.method == 'POST':
        if form.is_valid():
            bairro = form.save()
            dados['mensagem'] =\
                u'Bairro {nome} cadastrado com sucesso'.format(nome=bairro.nome)
            return bairro_home(request, dados)
        else:
            dados['form'] = form
            return render(request, template_bairro_add, dados)
    else:
        dados['form'] = form
        return render(request, template_bairro_add, dados)

def bairro_update(request, id):
    dados = {}
    form = BairroForm(request.POST or None)
    if form.is_valid():
        bairro = form.save(commit=False)
        bairro.id = id
        bairro.save()
        dados['mensagem'] =\
            u'Bairro {nome} alterado com sucesso'.format(nome=bairro.nome)
        return bairro_home(request)
    else:
        dados = {}
        dados['form'] = form

class BairroDelete(DeleteView):
    model = Bairro
    success_url = reverse_lazy('app_enderecos_bairro_home')
    template_name =\
        'enderecos/bairro/bairro_confirm_delete.html'

# Views de cidade
class CidadeList(ListView):
    template_name = 'enderecos/cidade/cidade_list.html'
    model = Cidade

class CidadeCreate(CreateView):
    model = Cidade
    template_name = 'enderecos/cidade/cidade_form.html'
    success_url = reverse_lazy('app_enderecos_cidade_home')
    success_message = "was created successfully"

class CidadeUpdate(UpdateView):
    model = Cidade
    success_url = reverse_lazy('app_enderecos_cidade_home')
    template_name = 'enderecos/cidade/cidade_form.html'

class CidadeDelete(DeleteView):
    model = Cidade
    success_url = reverse_lazy('app_enderecos_cidade_home')
    template_name = 'enderecos/cidade/cidade_confirm_delete.html'

def cidade_detalhe(request, id):
    dados = {}
    cidade = get_object_or_404(Cidade, id=id)
    form = CidadeForm(instance=cidade)
    for field in form.fields.values():
        field.widget.attrs['disabled'] = True
    dados['modo'] = 'DETALHE'
    dados['form'] = form
    dados['cidade'] = cidade
    return render(
        request, 'enderecos/cidade/cidade_form.html', dados)


from earth_system.altimetry import io
from unittest import mock

format_description = (
    {
        'description': 'julian day epoch 2000.0',
        'abbreviation': 'jday',
        'precision': 5,
        'type': 'i4',
        'bytes': 4,
        'ID': 1,
        'unit': 'day',
        },
    {
        'description': 'geodetic latitude of satellite footprint',
        'abbreviation': 'glat',
        'precision': 6,
        'type': 'i4',
        'bytes': 4,
        'ID': 2,
        'unit': 'degree',
        },
    {
        'description': 'longitude of satellite footprint',
        'abbreviation': 'glon',
        'precision': 6,
        'type': 'I4',
        'bytes': 4,
        'ID': 3,
        'unit': 'degree',
        },
    )
dtype = [
    ('jday', '<i4'),
    ('glat', '<i4'),
    ('glon', '<I4'),
    ]
precisions = (5, 6, 6)

class fake_path(object):
    def __init__(self, _path, type="dir"):
        self.pathname = _path
        self.content = []
        self.content_types = []
        self._is_dir = type == "dir"

    def with_suffix(self, suffix):
        return fake_path(self.pathname + suffix)

    def __str__(self):
        return self.pathname

    def __lt__(self, other):
        return str(self) < str(other)

    def iterdir(self):
        for entry, type_ in zip(self.content, self.content_types):
            yield fake_path(entry, type=type_)

    def is_dir(self):
        return self._is_dir

@mock.patch.object(io, 'pathlib')
@mock.patch.object(io, 'data')
@mock.patch.object(io, 'description')
def test_cycle(description, data, pathlib):
    pathname = "abc"
    faked_path = fake_path(pathname)
    faked_path.content = [
        "d",
        "e",
        "f",
        ]
    faked_path.content_types = [
        "dir",
        "dir",
        "file",
        ]
    directories = [
        entry
        for entry, type_ in zip(faked_path.content, faked_path.content_types)
        if type_ == "dir"
        ]
    expected_dataframes = ['df1', 'df2']

    pathlib.Path.return_value = faked_path
    description.read_description.return_value = format_description
    description.format2dtype.return_value = dtype
    description.format2precisions.return_value = precisions
    data.read_cycle.side_effect = expected_dataframes

    returned_cycles = io.cycles(pathname)

    for dataframe, expected_frame in zip(returned_cycles, expected_dataframes):
        assert dataframe == expected_frame

    assert pathlib.Path.called_once_with(pathname)
    assert description.read_description.called_once_with(pathname + ".rmp")
    assert description.format2dtype.called_once_with(format_description)
    assert description.format2precisions.called_once_with(format_description)
    assert data.read_cycle.call_args_list == [
        mock.call(_, dtype, precisions) for _ in directories
        ]


import numpy as np
import os

T = [10, 20, 50, 100, 200]
T = np.array(T)

roh = [0.001, 0.005, 0.02, 0.1, 0.5]
roh = np.array(roh)

for i in range(len(T)):
    for j in range(len(roh)):
        os.system("./a.out {} {}".format(T[i], roh[j]))


import os
from setuptools import setup, find_packages
import simplenamespace as module

def walker(base, *paths):
    file_list = set([])
    cur_dir = os.path.abspath(os.curdir)

    os.chdir(base)
    try:
        for path in paths:
            for dname, dirs, files in os.walk(path):
                for f in files:
                    file_list.add(os.path.join(dname, f))
    finally:
        os.chdir(cur_dir)
    return list(file_list)

requires = (
    'pyqt5',
)

setup(
    name=module.__name__.replace("_", "-"),
    version=module.__version__,
    author=module.__author__,
    description=module.package_info,
    platforms="all",
    classifiers=(
        'License :: Other',
        'Natural Language :: English',
        'Operating System :: MacOS',
        'Operating System :: POSIX',
        'Operating System :: Microsoft :: Windows',
        'Programming Language :: Python',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3 :: Only',
        'Programming Language :: Python :: 3.5',
        'Programming Language :: Python :: Implementation :: CPython',
        'Topic :: Internet',
        'Topic :: Internet :: WWW/HTTP',
        'Topic :: Internet :: WWW/HTTP :: HTTP Servers',
        'Topic :: Software Development',
    ),
    long_description=open('README.md').read(),
    packages=find_packages(exclude=('tests', 'tests.*')),
    package_data={
        module.__name__: walker(
            os.path.dirname(module.__file__)
        ),
    },
    install_requires=requires,
    extras_require={
        'develop': [
            'coverage!=4.3',
            'pylama',
            'pytest',
            'pytest-cov',
            'tox>=2.4',
        ],
    },
)


from django.conf.urls import url

from . import views

urlpatterns = [

    url(r'^$', views.blog_posts, name='wordscramble'),
    url(r'^posts/(?P<article_id>[0-9]+)$', views.post_view, name='post-view'),
    url(r'^posts/(?P<new_id>[0-9]+)$', views.prev_view, name='prev-view'),
    url(r'^posts/(?P<new_id>[0-9]+)$', views.next_view, name='next-view')

]


import sys
import numpy as np
import os.path

###---- Main

##-- Parameters
indir='./data/'
fname=indir+'storm_track.txt'

data=[]; time_info=[]
with open(fname,'r') as f:
    for i,line in enumerate(f):
        words=line.strip().split()
        #print(i,words)

        if i>0:  ### Exclude header
            flos=list(map(float,words[:4]))
            ints=list(map(int,words[4:]))

            data.append(flos)
            time_info.append(ints)

data=np.asarray(data)
time_info=np.asarray(time_info)

print(data.shape, time_info.shape)

###-------------

###--- Linear Regression
from sklearn import linear_model

## For linear-regression
regr=linear_model.LinearRegression()   ### Initiate Regression Object

xdata=data[:,2].reshape([-1,1])  ## wind speed
ydata=data[:,3].reshape([-1,1])  ## surface pressure

regr.fit(xdata,ydata)
r2score=regr.score(xdata,ydata)
print(u"Coeff.={:.2f}, Intercept={:.2f}, R\u00B2 Score={:.3f}".format(regr.coef_[0][0], regr.intercept_[0],r2score))

#y_pred=regr.predict(xcoord)
regr.__init__()     ### Re-initiate in order to use next time with different data

###-------------

### Calculate density of data
from scipy.stats import kde

xdata=data[:,2]  ## wind speed
ydata=data[:,3]  ## surface pressure
k=kde.gaussian_kde([xdata,ydata])
xi,yi=np.mgrid[xdata.min():xdata.max():100j,ydata.min():ydata.max():100j]
zi=k(np.vstack([xi.flatten(),yi.flatten()]))

print(zi.shape, zi.argmax())

j,i=np.unravel_index(zi.argmax(),xi.shape)
xloc= xdata.min()+(xdata.max()-xdata.min())/100*i
yloc= ydata.min()+(ydata.max()-ydata.min())/100*j
print("Max Density is {:.05f} when wind speed={:.2f} and pressure={:.2f}".format(zi.max(),xloc,yloc))

###-------------

### Write to text file

outdir = indir
outfn = outdir+'text_write_ex1.txt'

##-- Protect existing file
if os.path.isfile(outfn):
    sys.exit("Already Exist: "+outfn)
else:
    with open(outfn,'w') as f:
        header="Longitude, Wind, Year, Month"
        f.write(header+"\n")

        for i in range(data.shape[0]):
            data_txt="{:.2f}, {:.2f}, {:d}, {:02d}".format(data[i,0],data[i,2],time_info[i,0],time_info[i,1])
            f.write(data_txt+"\n")


def song_decoder(song):
    x_list = song.split('WUB')
    y_list = []
    for items in x_list:
        if items != '':
            y_list.append(items)

    y_list_len = len(y_list)

    output = ''
    for index, items in enumerate(y_list):
        if index != y_list_len - 1:
            output = output + items + ' '
        else:
            output += items

    return output


from Crawler import Crawler
from RedisClient import RedisClient

FULL_COUNT = 2000

class Getter(object):

    def __init__(self):
        self.redis_client = RedisClient()
        self.crawler = Crawler()

    def is_full(self):
        """
            判断代理池是否满了
        """
        if self.redis_client.get_proxy_count() >= FULL_COUNT:
            return True
        else:
            return False

    def run(self):
        """
            将爬取到的代理存入redis
        """
        if not self.is_full():
            proxy_list = self.crawler.get_crawler_proxy()
            for proxy in proxy_list:
                self.redis_client.add(proxy)


"""
Each ListNode holds a reference to its previous node
as well as its next node in the List.
"""
''' # This was done in class
class ListNode:
    def __init__(self, value, prev=None, next=None):
        self.prev = prev
        self.value = value
        self.next = next

    def __str__(self):
        return str(self.value)

    # Added code they started with
    def insert_after(self, value):
        current_next = self.next
        self.next = ListNode(value, self, current_next)
        if current_next:
            current_next.prev = self.next

    def insert_before(self, value):
        current_prev = self.prev
        self.prev = ListNode(value, current_prev, self)
        if current_prev:
            current_prev.next = self.prev

    def delete(self):
        if self.prev:
            self.prev.next = self.next
        if self.next:
            self.next.prev = self.prev

"""
Our doubly-linked list class. It holds references to
the list's head and tail nodes.
"""
class DoublyLinkedList:
    def __init__(self, node=None):
        self.head = node
        self.tail = node
        self.length = 1 if node is not None else 0

    def __len__(self):
        return self.length

    def print(self):
        curr_node = self.head
        print(curr_node)
        while curr_node.next is not None:
            curr_node = curr_node.next
            print(curr_node)

    """
    Wraps the given value in a ListNode and inserts it
    as the new head of the list. Don't forget to handle
    the old head node's previous pointer accordingly.
    """
    def add_to_head(self, value):
        new_node = ListNode(value)
        self.length += 1
        # Check if this is an empty list
        if not self.head and not self.tail:
            self.head = new_node
            self.tail = new_node
        else:
            new_node.next = self.head
            self.head.prev = new_node
            self.head = new_node

    """
    Removes the List's current head node, making the
    current head's next node the new head of the List.
    Returns the value of the removed Node.
    """
    def remove_from_head(self):
        value = self.head.value
        self.delete(self.head)
        return value

    """
    Wraps the given value in a ListNode and inserts it
    as the new tail of the list. Don't forget to handle
    the old tail node's next pointer accordingly.
    """
    def add_to_tail(self, value):
        new_node = ListNode(value)
        self.length += 1
        # Check if this is an empty list
        if not self.head and not self.tail:
            self.head = new_node
            self.tail = new_node
        else:
            new_node.prev = self.tail
            self.tail.next = new_node
            self.tail = new_node

    """
    Removes the List's current tail node, making the
    current tail's previous node the new tail of the List.
    Returns the value of the removed Node.
    """
    def remove_from_tail(self):
        value = self.tail.value
        self.delete(self.tail)
        return value

    """
    Removes the input node from its current spot in the
    List and inserts it as the new head node of the List.
    """
    def move_to_front(self, node):
        if node is self.head:
            return
        value = node.value
        self.delete(node)
        self.add_to_head(value)

    """
    Removes the input node from its current spot in the
    List and inserts it as the new tail node of the List.
    """
    def move_to_end(self, node):
        if node is self.tail:
            return
        value = node.value
        self.delete(node)
        self.add_to_tail(value)

    """
    Deletes the input node from the List, preserving the
    order of the other elements of the List.
    """
    def delete(self, node):
        if not self.head and not self.tail:
            return

        if self.head == self.tail:
            self.head = None
            self.tail = None
        elif node == self.head:
            self.head = node.next
        elif node == self.tail:
            self.tail = node.prev
        self.length -= 1
        node.delete()

    """
    Finds and returns the maximum value of all the nodes
    in the List.
    """
    def get_max(self):
        # Attempted on my own
        max = self.head.value
        current_node = self.head
        while current_node.next is not None:
            current_node = current_node.next
            if current_node.value > max:
                max = current_node.value
        return max

# Singly Linked List Implementation on my own
class ListNode:
    def __init__(self, value, next=None):
        self.value = value
        self.next = next

    def __str___(self):
        return str(self.value)

class LinkedList:
    def __init__(self, node=node):
        self.head = node
        self.tail = node
        self.size = 1 if not Node else 0

    def __len__(self):
        return self.size

    def add_to_head(self, value):
        self.size += 1
        new_node = ListNode(value)
        if self.size == 0:
            self.head = new_node
            self.tail = new_node
        else:
            new_node.next = self.head
            self.head = new_node

    def add_to_tail(self, value):
        self.size += 1
        new_node = ListNode(value)
        if self.size == 0:
            self.head = new_node
            self.tail = new_node
        else:
            self.tail.next = new_node
            self.tail = new_node

    def remove_from_head(self, node):
        self.size -= 1
        old_head = self.head
        self.head = self.head.next
        return old_head
'''

# Doubly Linked List Implemented on my own
class ListNode:
    def __init__(self, value, next=None, prev=None):
        self.value = value
        self.next = next
        self.prev = prev

    def __str__(self):
        return str(self.value)

    def delete(self):
        if self.prev:
            self.prev.next = self.next
        if self.next:
            self.next.prev = self.prev

class DoublyLinkedList:
    def __init__(self, node=None):
        self.head = node
        self.tail = node
        self.size = 1 if node is not None else 0

    def __len__(self):
        return self.size

    def add_to_head(self, value):
        self.size += 1
        new_node = ListNode(value)

        if not self.head and not self.tail:  # Empty List
            self.head = new_node
            self.tail = new_node
        else:   # List contains at least one element
            new_node.next = self.head
            self.head.prev = new_node
            self.head = new_node

    def add_to_tail(self, value):
        self.size += 1
        new_node = ListNode(value)

        if not self.head and not self.tail:
            self.head = new_node
            self.tail = new_node
        else:
            new_node.prev = self.tail
            self.tail.next = new_node
            self.tail = new_node

    def remove_from_head(self):
        # Check for empty list
        if not self.head:
            return None

        head_value = self.head.value
        self.delete(self.head)
        return head_value

    def remove_from_tail(self):
        # Check for empty list
        if not self.head:
            return None

        tail_value = self.tail.value
        self.delete(self.tail)
        return tail_value

    def move_to_front(self, node):
        # This saves time if already at the front
        if node == self.head:
            return

        self.delete(node)
        self.add_to_head(node.value)

    def move_to_end(self, node):
        # This saves time if already at the end
        if node == self.tail:
            return

        self.delete(node)
        self.add_to_tail(node.value)

    def delete(self, node):
        if not self.head and not self.tail:  # Empty List
            return

        self.size -= 1
        if node == self.head and node == self.tail:  # Only one node in list
            self.head = None
            self.tail = None

        elif node == self.head:  # Node is only head
            self.head = node.next
            # Added this to keep the head from still pointing back at 'deleted' node
            self.head.prev = None
            # Added this to remove the pointers of the node being deleted
            node.delete()

        elif node == self.tail:  # Node is only tail
            self.tail = node.prev
            # Added this to keep the head from still pointing to 'deleted' node
            self.tail.next = None
            # Added this to remove the pointers of the node being deleted
            node.delete()

        else:
            # Node is none of the above (Also should check that the node is in the list
            node.prev.next = node.next
            node.next.prev = node.prev
            # Added this to remove the pointers of the node being deleted
            node.delete()

    def get_max(self):
        # Check for empty List
        if not self.head:
            return None

        max_value = self.head.value
        current_node = self.head
        while current_node.next:
            current_node = current_node.next
            if current_node.value > max_value:
                max_value = current_node.value
        return max_value


from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
from django.db.models import Q
from django.urls import reverse
from django.utils.translation import gettext_lazy as _

from appaccounts import functions as AccountsFunctions
from appaccounts.models import Profile

class Skill(models.Model):

    title = models.CharField(max_length=250, verbose_name=_('Навык'))
    avatar = models.ImageField(null=True, blank=True, upload_to='apptasks/images/skills/', verbose_name=_('Аватар'))
    description = models.TextField(null=True, blank=True, verbose_name='Описание', default='')
    description_min = models.CharField(null=True, blank=True, max_length=250, verbose_name=_('Краткое описание'), default='')

    class Meta:
        verbose_name = 'Skill'
        verbose_name_plural = 'Skills'

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('apptasks:skill_detail', args=[str(self.id)])

    def get_avatar_url(self):
        if self.avatar:
            return self.avatar.url
        else:
            return ''

class Task(models.Model):
    STATUS_CHOICES = (
        ('active', 'Active'),
        ('inactive', 'Inactive'),
    )
    CODE_STORAGE_CHOICES = (
        ('1', 'Github'),
        ('2', 'Cloud'),
        ('3', 'Comment'),
    )
    BUILD_STORAGE_CHOICES = (
        ('1', 'None'),
        ('2', 'Github'),
        ('3', 'Heroku'),
        ('4', 'Github_Heroku'),
    )

    title = models.CharField(max_length=150, verbose_name='Название задачи')
    description = models.TextField(max_length=settings.TASK_DESCRIPTION_LEN_MAX, verbose_name='Описание задачи')
    description_short = models.CharField(max_length=settings.TASK_DESCRIPTION_LEN_SHORT, verbose_name='Краткое описание', default='')
    description_HTML = models.TextField(verbose_name='Форматированное описание', default='')
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    status = models.CharField(max_length=50, choices=STATUS_CHOICES, default='inactive')
    author = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='author')
    skill = models.ForeignKey(Skill, null=True, on_delete=models.SET_NULL, related_name='skill')
    extra_skill1 = models.ForeignKey(Skill, null=True, blank=True, on_delete=models.SET_NULL, related_name='extra_skill1')
    extra_skill2 = models.ForeignKey(Skill, null=True, blank=True, on_delete=models.SET_NULL, related_name='extra_skill2')
    extra_skill3 = models.ForeignKey(Skill, null=True, blank=True, on_delete=models.SET_NULL, related_name='extra_skill3')
    code_storage = models.CharField(max_length=50, null=True, blank=True, choices=CODE_STORAGE_CHOICES, default='1')
    build_storage = models.CharField(max_length=50, null=True, blank=True, choices=BUILD_STORAGE_CHOICES, default='1')

    class Meta:
        verbose_name = 'Задача'
        verbose_name_plural = 'Задачи'

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        if self.description:
            self.description_short=self.description[0:settings.TASK_DESCRIPTION_LEN_SHORT]
        super(Task, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('apptasks:task_detail', args=[str(self.id)])

    def get_update_url(self):
        return reverse('apptasks:task_update', args=[str(self.id)])

    def need_code(self):
        if self.code_storage and int(self.code_storage) < 3:
            return True
        else:
            return False

    def need_build(self):
        if self.build_storage and int(self.build_storage) > 1:
            return True
        else:
            return False

    def get_rating(self):
        task_ratings = TaskRatings.objects.filter(task=self)
        task_rate = 0
        if task_ratings:
            count = task_ratings.count()
            value = 0
            for rate in task_ratings:
                value += rate.value
            task_rate = value / count
        return task_rate

    def get_extra_skill_count(self):
        count = 0
        if self.extra_skill1:
            count += 1
        if self.extra_skill2:
            count += 1
        if self.extra_skill3:
            count += 1
        return count

    def is_favorite(self, user):
        result = False
        if user and user.is_authenticated:
            result = TaskFavourites.objects.filter(task=self, user=user).exists()
        return result

    def is_like(self, user):
        result = False
        if user and user.is_authenticated:
            result = TaskLike.objects.filter(task=self, user=user).exists()
        return result

    def get_favourite_count(self):
        return TaskFavourites.objects.filter(task=self).count()

    def get_like_count(self):
        return TaskLike.objects.filter(task=self).count()

class CheckPoint(models.Model):
    task = models.ForeignKey(Task, on_delete=models.CASCADE, null=True, blank=True)
    title = models.CharField(max_length=250, verbose_name='Checkpoint')
    order = models.IntegerField(null=True, blank=True, default=1, verbose_name='Порядок')

    class Meta:
        verbose_name = 'Checkpoint'
        verbose_name_plural = 'Checkpoints'

    def __str__(self):
        return self.title

class TaskRatings(models.Model):

    task = models.ForeignKey(Task, on_delete=models.CASCADE, null=True, blank=True, related_name='task_rating')
    user = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='user')
    value = models.IntegerField(null=True, blank=True)
    updated = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = 'Рейтинг задачи'
        verbose_name_plural = 'Рейтинги задач'

    def __str__(self):
        return f'{self.task}::{self.user}={self.value}'

class TaskFavourites(models.Model):

    task = models.ForeignKey(Task, on_delete=models.CASCADE, null=True, blank=True, related_name='task_favourites', related_query_name='task_favourites')
    user = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL)
    created = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = 'Избранная задачи'
        verbose_name_plural = 'Избранные задач'

    def __str__(self):
        return f'{self.task}::{self.user}'

class TaskLike(models.Model):

    task = models.ForeignKey(Task, on_delete=models.CASCADE, null=True, blank=True, related_name='task_like')
    user = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL)
    created = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = 'Лайк задачи'
        verbose_name_plural = 'Лайки задач'

    def __str__(self):
        return f'{self.task}::{self.user}'


# coding:utf-8
from uiautomator import Device
from Repo import *
import time, datetime, random
from zservice import ZDevice

class MobilqqPraiseII:
    def __init__(self):
        self.repo = Repo()

    def action(self, d,z,args):
        z.heartbeat()
        d.server.adb.cmd("shell", "am force-stop com.tencent.mobileqq").communicate()  # 强制停止
        d.server.adb.cmd("shell", "am start -n com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity").communicate()  # 拉起来
        z.sleep(8)
        z.heartbeat()
        d(description='快捷入口').click()
        d(textContains='加好友').click()
        d(textContains='附近的人').click()
        while not d(textContains='等级').exists:
            z.sleep(2)
        getGender = args['gender']
        if getGender !='不限':
            d(resourceId='com.tencent.mobileqq:id/ivTitleBtnRightImage').click()
            d(text='筛选附近的人').click()
            d(text=getGender).click()
            d(text='完成').click()
            while not d(textContains='等级').exists:
                z.sleep(2)
        z.heartbeat()

        count = int(args['concernnum'])
        t = 0
        i = 3
        while t<count:
            forClick = d(className='android.widget.AbsListView').child(className='android.widget.LinearLayout',index=i).child(className='android.widget.RelativeLayout')
            if forClick.child(className='android.widget.LinearLayout',index=2).exists:
                z.heartbeat()
                if forClick.child(text='直播中').exists:
                    i = i+1
                    continue

                forClick.click()

                while not d(textContains='关注').exists:
                    z.sleep(2)
                    if d(text='知道了').exists:
                        d(text='知道了').click()

                for j in range( 0, 10 ):
                    if d( descriptionContains='赞' ).exists:
                        d( descriptionContains='赞' ).click()
                        if d(textContains='今日免费赞数已达').exists:
                            d(text='取消').click()
                            break
                z.sleep(2)

                if d(text='关注').exists:
                    d(text='关注').click()

                d(text='返回').click()
                i = i+1
                t = t+1
                continue

            elif d(className='android.widget.AbsListView').child(className='android.widget.RelativeLayout',index=i).child(text='广告').exists:  #被点击条件不存在的情况
                z.heartbeat()
                i =i+1
                continue
            else:
                str = d.info  # 获取屏幕大小等信息
                width = str["displayWidth"]
                clickCondition = d(className='android.widget.AbsListView')
                obj = clickCondition.info
                obj = obj['visibleBounds']
                top = int(obj['top'])
                bottom = int(obj['bottom'])
                y = bottom - top
                d.swipe(width / 2, y, width / 2, 0)
                z.sleep(3)
                i = 1

        if (args["time_delay"]):
            z.sleep(int(args["time_delay"]))

def getPluginClass():
    return MobilqqPraiseII

if __name__ == "__main__":
    import sys
    reload(sys)
    sys.setdefaultencoding('utf8')
    clazz = getPluginClass()
    o = clazz()
    d = Device("HT4AVSK00885")
    z = ZDevice("HT4AVSK00885")
    d.server.adb.cmd("shell", "ime set com.zunyun.qk/.ZImeService").communicate()

    args = {"concernnum":"20",'gender':"男","time_delay":"3"};    #cate_id是仓库号，length是数量

    o.action(d,z, args)


# https://data-flair.training/blogs/python-ordereddict/
# https://pymotw.com/3/collections/ordereddict.html
# https://pymotw.com/2/collections/ordereddict.html

from collections import OrderedDict
 # from collections

class UseOrderedDict:

    def __init__(self):
        self.orderedDict = OrderedDict()
        self.regDict = dict()

    def AddToHashMapWithOrder(self, key, val):

        self.orderedDict[key] = val

    def AddToHashMap(self, key, val):
        self.regDict[key] = val

    def printHashMapsContent(self):

        print(" regular Hashmap -> ", self.regDict)
        print(" Ordered Hashmap -> ", self.orderedDict)
        for k, v in self.regDict.items():
            print(" reg hashmap -> key ", k, " val -> ", v)

        for k, v in self.orderedDict.items():
            print(" ordered hashmap -> key ", k, " val -> ", v)

    def compareDicts(self):

        d1 = {}
        d1['b'] = 'B'
        d1['a'] = 'A'

        d2 = {}
        d2['a'] = 'A'
        d2['b'] = 'B'

        print(" comparing 2 hashmaps (Does Not Remember order in which items were added) -> ", (d1 == d2))

    def compareOrderedDicts(self):

        od1 = OrderedDict()
        od1['a'] = 'A'
        od1['b'] = 'B'

        od2 = OrderedDict()
        od2['b'] = 'B'
        od2['a'] = 'A'

        print(" comparing OrderedDicts (remembers order in which items were added) -> ", (od1 == od2))

    def moveItemToEnd_OrderedDict(self):

        od1 = OrderedDict()
        od1['a'] = 'A'
        od1['b'] = 'B'
        od1['c'] = 'C'
        od1['d'] = 'D'

        print(" before moving item ")
        for k, v in od1.items():
            print(" k -> ", k, " v -> ", v)

        od1.move_to_end('b', last=True)
        print(" before moving item, last=True ")
        for k, v in od1.items():
            print(" k -> ", k, " v -> ", v)

        print(" before moving item, last=False ")
        od1.move_to_end('b', last=False)
        for k, v in od1.items():
            print(" k -> ", k, " v -> ", v)

    def deleteItemFromHashMap(self):

        od3 = OrderedDict()
        od3['a'] = 'A'
        od3['b'] = 'B'
        od3['c'] = 'C'
        od3['d'] = 'D'
        od3['e'] = 'E'
        od3['f'] = 'F'
        od3['g'] = 'G'

        print(" before removing item ")
        for k, v in od3.items():
            print(" k -> ", k, " v -> ", v)

        print(" after removing item ")
        del od3['a']
        for k, v in od3.items():
            print(" k -> ", k, " v -> ", v)

        print(" od3.pop ")
        od3.pop('d')
        for k, v in od3.items():
            print(" k -> ", k, " v -> ", v)

        print(" od3.popitem, last = True ")
        od3.popitem(last=True)
        for k, v in od3.items():
            print(" k -> ", k, " v -> ", v)

        print(" od3.popitem, last = False ")
        od3.popitem(last=False)
        for k, v in od3.items():
            print(" k -> ", k, " v -> ", v)

        d3 = {}
        d3['a'] = 'A1'
        d3['b'] = 'B1'
        d3['c'] = 'C1'
        d3['d'] = 'D1'

        print(" before removing item ")
        for k, v in d3.items():
            print(" k -> ", k, " v -> ", v)

        print(" after removing item ")
        del d3['b']
        for k, v in d3.items():
            print(" k -> ", k, " v -> ", v)

od = UseOrderedDict()
od.AddToHashMapWithOrder('a', 'A')
od.AddToHashMapWithOrder('c', 'C')
od.AddToHashMapWithOrder('d', 'D')
od.AddToHashMapWithOrder('e', 'E')
od.AddToHashMapWithOrder('b', 'B')

od.AddToHashMap('a', 'A')
od.AddToHashMap('c', 'C')
od.AddToHashMap('d', 'D')
od.AddToHashMap('e', 'E')
od.AddToHashMap('b', 'B')

od.printHashMapsContent()

od.compareDicts()
od.compareOrderedDicts()

od.moveItemToEnd_OrderedDict()

od.deleteItemFromHashMap()


from click.testing import CliRunner
from datasette import cli
from unittest import mock
from subprocess import PIPE
import pytest

class FakeCompletedProcess:
    def __init__(self, stdout, returncode=0):
        self.stdout = stdout
        self.returncode = returncode

@mock.patch("shutil.which")
def test_publish_fly_requires_flyctl(mock_which):
    mock_which.return_value = False
    runner = CliRunner()
    with runner.isolated_filesystem():
        open("test.db", "w").write("data")
        result = runner.invoke(cli.cli, ["publish", "fly", "test.db", "-a", "app"])
        assert result.exit_code == 1
        assert "Publishing to Fly requires flyctl" in result.output

@mock.patch("shutil.which")
@mock.patch("datasette_publish_fly.run")
def test_publish_now_app_name_not_available(mock_run, mock_which):
    mock_which.return_value = True
    runner = CliRunner()

    def run_side_effect(*args, **kwargs):
        if args == (["flyctl", "apps", "list"],):
            return FakeCompletedProcess(b"  NAME")
        else:
            print(args)
            return FakeCompletedProcess(b"", 1)

    mock_run.side_effect = run_side_effect

    with runner.isolated_filesystem():
        open("test.db", "w").write("data")
        result = runner.invoke(cli.cli, ["publish", "fly", "test.db", "-a", "app"])
        assert 1 == result.exit_code
        assert "Error: That app name is not available" in result.output
        assert [
            mock.call(["flyctl", "apps", "list"], stdout=PIPE, stderr=PIPE),
            mock.call(["flyctl", "apps", "create", "--name", "app"]),
        ] == mock_run.call_args_list

@pytest.mark.parametrize(
    "flyctl_apps_list", [b"  NAME", b"Update available 0.0.108 -> 0.0.109\n  NAME",]
)
@mock.patch("shutil.which")
@mock.patch("datasette_publish_fly.run")
def test_publish_now(mock_run, mock_which, flyctl_apps_list):
    mock_which.return_value = True
    runner = CliRunner()

    def run_side_effect(*args, **kwargs):
        if args == (["flyctl", "apps", "list"],):
            print(flyctl_apps_list)
            return FakeCompletedProcess(flyctl_apps_list)
        else:
            print(args)
            return FakeCompletedProcess(b"", 0)

    mock_run.side_effect = run_side_effect

    with runner.isolated_filesystem():
        open("test.db", "w").write("data")
        result = runner.invoke(cli.cli, ["publish", "fly", "test.db", "-a", "app"])
        assert 0 == result.exit_code
        assert [
            mock.call(["flyctl", "apps", "list"], stdout=PIPE, stderr=PIPE),
            mock.call(["flyctl", "apps", "create", "--name", "app"]),
            mock.call(["flyctl", "deploy", "--remote-only"]),
        ] == mock_run.call_args_list


import numpy as np
from gammapy.image import SkyImageList, SkyImage
import pylab as pt
from gammapy.utils.scripts import make_path
import math
import astropy.units as u
from scipy.optimize import curve_fit
from sherpa_models import normgauss2dint
import os
from sherpa.astro.ui import *
from astropy.io import fits
from astropy.table import Table
from astropy.table import Column
import astropy.units as u
from IPython.core.display import Image
import astropy.units as u
import pylab as pt
from gammapy.background import fill_acceptance_image
from gammapy.utils.energy import EnergyBounds
from astropy.coordinates import Angle
from astropy.units import Quantity
import numpy as np
from astropy.wcs.utils import pixel_to_skycoord, skycoord_to_pixel
from astropy.coordinates import SkyCoord
#from utilities import *
from sherpa.models import Gauss2D, NormGauss2D

pt.ion()

def make_outdir_data(source_name, name_bkg,config_name,image_size,for_integral_flux, ereco,etrue=None,use_cube=False, use_etrue=False):
    """

    Parameters
    ----------
    source_name: name of the source you want to compute the image
    name_bkg: name of the bkg model you use to produce your bkg image
    config_name:
    image_size:
    for_integral_flux: True if you want to compute the exposure to get the integral flux
    ereco: Tuple for the energy reco bin: (Emin,Emax,nbins)
    etrue: Tuple for the energy true bin: (Emin,Emax,nbins)
    use_cube: True if you want to compute cube analisys
    use_etrue: True if you want to compute the exposure cube and psf mean cube in true energy

    Returns
    -------
    directory where your fits file will go
    """
    n_binE=ereco[2]
    emin_reco=ereco[0].value
    emax_reco=ereco[1].value
    outdir = os.path.expandvars('$Image') +"/"+config_name + "/Image_" + source_name + "_bkg_" + name_bkg + "/binE_" + str(n_binE) +"_min_"+str(emin_reco)+"_max_"+str(emax_reco)+"_size_image_"+str(image_size)+"_pix"
    if not for_integral_flux:
        outdir+= "_exposure_flux_diff"
    if use_cube:
        outdir+= "_cube_images"
        if use_etrue:
            n_binE_true=etrue[2]
            emin_true=etrue[0].value
            emax_true=etrue[1].value
            outdir+= "_use_etrue_min_"+str(emin_true)+"_max_"+str(emax_true)+"_bin_"+str(n_binE_true)
    if os.path.isdir(outdir):
        return outdir
    else:
        print("The directory" + outdir + " doesn't exist")

def make_outdir_profile(source_name, name_bkg,config_name,image_size,for_integral_flux,ereco,etrue=None,use_cube=False, use_etrue=False):
    """
    directory where we will store the profiles on lattitutde and longitude
    Parameters
    ----------
    source_name: name of the source you want to compute the image
    name_bkg: name of the bkg model you use to produce your bkg image

    Returns
    -------
    directory where your fits file ill go
    """
    outdir = make_outdir_plot(source_name, name_bkg,config_name,image_size,for_integral_flux,ereco,etrue,use_cube,use_etrue) + "/profiles"
    if os.path.isdir(outdir):
        return outdir
    else:
        make_path(outdir).mkdir()
        return outdir

def make_outdir_plot(source_name, name_bkg,config_name, image_size,for_integral_flux, ereco,etrue=None,use_cube=False, use_etrue=False):
    """
    directory where we will store the plots
    Parameters
    ----------
    source_name: name of the source you want to compute the image
    name_bkg: name of the bkg model you use to produce your bkg image

    Returns
    -------
    directory where your fits file ill go
    """
    outdir = make_outdir_data(source_name, name_bkg, config_name, image_size,for_integral_flux,ereco,etrue,use_cube,use_etrue) + "/plot"
    if os.path.isdir(outdir):
        return outdir
    else:
        make_path(outdir).mkdir()
        return outdir

def make_outdir_filesresult(source_name, name_bkg, config_name, image_size,for_integral_flux, ereco,etrue=None,use_cube=False, use_etrue=False):
    """
    directory where we will store the plots
    Parameters
    ----------
    source_name: name of the source you want to compute the image
    name_bkg: name of the bkg model you use to produce your bkg image

    Returns
    -------
    directory where your fits file ill go
    """
    outdir = make_outdir_data(source_name, name_bkg, config_name, image_size,for_integral_flux,ereco,etrue,use_cube,use_etrue) + "/files_result"
    if os.path.isdir(outdir):
        return outdir
    else:
        make_path(outdir).mkdir()
        return outdir

def histo_significance(significance_map, exclusion_mask):
    """

    Parameters
    ----------
    significance_map: SkyImage
        significance map
    exclusion_mask: SkyMask
        exlusion mask to use for excluding the source to build the histogram of the resulting significance of the map
        without the source (normally centered on zero)

    Returns
    -------

    """
    significance_map.data[np.isnan(significance_map.data)] = -1000
    i = np.where((exclusion_mask.data != 0) & (significance_map.data != -1000))
    #n, bins, patches = pt.hist(significance_map.data[i], range=[-3,3],bins=100)
    n, bins, patches = pt.hist(significance_map.data[i],bins=100)

    #import IPython; IPython.embed()
    return n, bins, patches

def norm(x, A, mu, sigma):
    """
    Norm of a gaussian
    Parameters
    ----------
    x
    A
    mu
    sigma

    Returns
    -------

    """
    y = A / (sigma * np.sqrt(2 * math.pi)) * np.exp(-(x - mu) ** 2 / (2 * (sigma) ** 2))
    return y

def source_Gauss2D(name, fwhm_init, fwhm_frozen, ampl_init, ampl_frozen, xpos_init, xpos_frozen,
                          ypos_init, ypos_frozen,ellep_init=None, ellep_frozen=None, ampl_max=None,fwhm_min=None):
    mygaus = Gauss2D(name)
    set_par(mygaus.fwhm, val=fwhm_init, min=fwhm_min, max=None, frozen=fwhm_frozen)
    set_par(mygaus.ampl, val=ampl_init, min=0, max=ampl_max, frozen=ampl_frozen)
    set_par(mygaus.xpos, val=xpos_init, min=None, max=None, frozen=xpos_frozen)
    set_par(mygaus.ypos, val=ypos_init, min=None, max=None, frozen=ypos_frozen)
    return mygaus

def source_NormGauss2D(name, fwhm_init, fwhm_frozen, ampl_init, ampl_frozen, xpos_init, xpos_frozen,
                       ypos_init, ypos_frozen, ellep_fit=False, ellep_init=None, ellep_frozen=None, ampl_max=None, fwhm_min=None):
    mygaus = NormGauss2D(name)
    set_par(mygaus.ampl, val=ampl_init, min=0, max=ampl_max, frozen=ampl_frozen)
    set_par(mygaus.fwhm, val=fwhm_init, min=fwhm_min, max=None, frozen=fwhm_frozen)
    set_par(mygaus.xpos, val=xpos_init, min=None, max=None, frozen=xpos_frozen)
    set_par(mygaus.ypos, val=ypos_init, min=None, max=None, frozen=ypos_frozen)
    if ellep_fit:
        mygaus.ellip = ellep_init
        if ellep_frozen:
            freeze(mygaus.ellip)
        else:
            thaw(mygaus.ellip)

    return mygaus

def source_punctual_model(name, fwhm_init, fwhm_frozen, ampl_init, ampl_frozen, xpos_init, xpos_frozen,
                          ypos_init, ypos_frozen,ellep_init=None, ellep_frozen=None, ampl_max=None):
    """

    Parameters
    ----------
    name: str
        name of the gaussian in the fit result
    fwhm_init: float
        value initial of the fwhm
    fwhm_frozen: bool
        True if you want to froze the parameter
    ampl_init: float
        value initial of the amplitude
    ampl_frozen: bool
        True if you want to froze the parameter
    xpos_init: float
        value initial of the xpos of the source
    xpos_frozen: bool
        True if you want to froze the parameter
    ypos_init: float
        value initial of the ypos of the source
    ypos_frozen: bool
        True if you want to froze the parameter

    Returns
    -------

    """
    mygaus = normgauss2dint(name)
    set_par(mygaus.fwhm, val=fwhm_init, min=None, max=None, frozen=fwhm_frozen)
    set_par(mygaus.ampl, val=ampl_init, min=0, max=ampl_max, frozen=ampl_frozen)
    set_par(mygaus.xpos, val=xpos_init, min=None, max=None, frozen=xpos_frozen)
    set_par(mygaus.ypos, val=ypos_init, min=None, max=None, frozen=ypos_frozen)
    return mygaus

def source_punctual_model_test(name, fwhm_init, fwhm_frozen, ampl_init, ampl_frozen, xpos_init, xpos_frozen,
                          ypos_init, ypos_frozen,ellep_init=None, ellep_frozen=None, ampl_max=None):
    """

    Parameters
    ----------
    name: str
        name of the gaussian in the fit result
    fwhm_init: float
        value initial of the fwhm
    fwhm_frozen: bool
        True if you want to froze the parameter
    ampl_init: float
        value initial of the amplitude
    ampl_frozen: bool
        True if you want to froze the parameter
    xpos_init: float
        value initial of the xpos of the source
    xpos_frozen: bool
        True if you want to froze the parameter
    ypos_init: float
        value initial of the ypos of the source
    ypos_frozen: bool
        True if you want to froze the parameter

    Returns
    -------

    """
    mygaus = normgauss2dint(name)
    set_par(mygaus.fwhm, val=fwhm_init, min=None, max=None, frozen=fwhm_frozen)
    set_par(mygaus.ampl, val=ampl_init, min=None, max=ampl_max, frozen=ampl_frozen)
    set_par(mygaus.xpos, val=xpos_init, min=None, max=None, frozen=xpos_frozen)
    set_par(mygaus.ypos, val=ypos_init, min=None, max=None, frozen=ypos_frozen)
    return mygaus

def make_exposure_model(outdir, E1, E2):
    """

    Parameters
    ----------
    outdir: str
        directory chere are stored the data
    E1: float
        energy min
    E2: float
        energy max

    Returns
    -------

    """
    exp = SkyImageList.read(outdir + "/fov_bg_maps" + str(E1) + "_" + str(E2) + "_TeV.fits")["exposure"]
    exp.write(outdir + "/exp_maps" + str(E1) + "_" + str(E2) + "_TeV.fits", clobber=True)
    load_table_model("exposure", outdir + "/exp_maps" + str(E1) + "_" + str(E2) + "_TeV.fits")
    exposure.ampl = 1
    freeze(exposure.ampl)
    return exposure

def make_bkg_model(outdir, E1, E2, freeze_bkg, ampl_init=1):
    """

    Parameters
    ----------
    outdir: str
        directory chere are stored the data
    E1: float
        energy min
    E2: float
        energy max
    freeze_bkg: bool
        True if you want to froze the norm of the bkg in the fit

    Returns
    -------

    """
    bkgmap = SkyImageList.read(outdir + "/fov_bg_maps" + str(E1) + "_" + str(E2) + "_TeV.fits")["bkg"]
    bkgmap.write(outdir + "/off_maps" + str(E1) + "_" + str(E2) + "_TeV.fits", clobber=True)
    load_table_model("bkg", outdir + "/off_maps" + str(E1) + "_" + str(E2) + "_TeV.fits")
    set_par(bkg.ampl, val=ampl_init, min=0, max=None, frozen=freeze_bkg)
    return bkg

def make_psf_model(outdir, E1, E2, data_image, source_name):
    """

    Parameters
    ----------
    outdir: str
        directory chere are stored the data
    E1: float
        energy min
    E2: float
        energy max
    data_image: SkyImage
        on map to reproject the psf
    source_name: str
        name of the source to load the psf file

    Returns
    -------

    """
    psf_file = Table.read(outdir + "/psf_table_" + source_name + "_" + str(E1) + "_" + str(E2) + ".fits")
    header = data_image.to_image_hdu().header
    psf_image = fill_acceptance_image(header, data_image.center, psf_file["theta"].to("deg"),
                                      psf_file["psf_value"].data, psf_file["theta"].to("deg")[-1])
    psf_image.writeto(outdir + "/psf_image.fits", clobber=True)
    load_psf("psf", outdir + "/psf_image.fits")
    return psf

def make_EG_model(outdir, data_image, start_value, frozen):
    """

    Parameters
    ----------
    outdir: str
        directory chere are stored the data
    data_image: SkyImage
        on map to reproject the psf

    Returns
    -------

    """
    EmGal_map = SkyImage.read("HGPS_large_scale_emission_model.fits", ext=1)
    emgal_reproj = EmGal_map.reproject(data_image)
    emgal_reproj.data[np.where(np.isnan(emgal_reproj.data))] = 0
    #import IPython; IPython.embed()
    emgal_reproj.write(outdir + "/emgal_reproj.fits", clobber=True)
    load_table_model("EmGal", outdir + "/emgal_reproj.fits")
    set_par(EmGal.ampl, val=start_value, min=0, max=None, frozen=frozen)
    return EmGal

def make_CS_model(outdir, data_image, ampl_init,ampl_frozen, threshold_zero_value):
    CS_map = SkyImage.read("CStot.fits")
    if 'COMMENT' in CS_map.meta:
        del CS_map.meta['COMMENT']
    cs_reproj = CS_map.reproject(data_image)
    cs_reproj.data[np.where(np.isnan(cs_reproj.data))] = 0
    cs_reproj.data[np.where(cs_reproj.data < threshold_zero_value)] = 0
    cs_reproj.data = cs_reproj.data / cs_reproj.data.sum()
    cs_reproj.write(outdir + "/cs_map_reproj.fits", clobber=True)
    load_table_model("CS", outdir + "/cs_map_reproj.fits")
    set_par(CS.ampl, val=ampl_init, min=0, max=None, frozen=ampl_frozen)
    return  CS

def region_interest(source_center, data_image, height, width):
    """

    Parameters
    ----------
    source_center: SkyCoord
        coordinates of the source
    data_image: SkyImage
        on map to determine the source position in pixel
    height: int
        size in pixel of the height of the region we want to use around the source for the fit
    width: int
        size in pixel of the width of the region we want to use around the source for the fit

    Returns
    -------

    """
    x_pix = skycoord_to_pixel(source_center, data_image.wcs)[0]
    y_pix = skycoord_to_pixel(source_center, data_image.wcs)[1]
    name_interest = "box(" + str(x_pix) + "," + str(y_pix) + "," + str(width) + "," + str(height) + ")"
    return name_interest

def make_name_model(model, additional_component):
    """

    Parameters
    ----------
    model: sherpa.model
        initial model
    additional_component: sherpa.model
        additional model we want to fit

    Returns
    -------

    """
    model = model + additional_component
    return model

def result_table(result, energy):
    """

    Parameters
    ----------
    result : `~sherpa.fit.FitResults`
        result object from sherpa fit()
    energy : float
        energy of the band
    Returns
    -------
    table : `astropy.table.Table`
        containes the fitted parameters value of the sherpa model
    """
    list_result_vals=list(result.parvals)
    list_result_vals.insert(0, energy.value)
    list_result_vals.append(result.dof)
    list_result_vals.append(result.statval)
    list_result_names=list(result.parnames)
    list_result_names.insert(0,'energy')
    list_result_names.append('dof')
    list_result_names.append('statval')
    table=Table(np.asarray(list_result_vals), names= list_result_names)
    return table

def covar_table(covar, energy):
    """

    Parameters
    ----------
    covar : `~sherpa.fit.ErrorEstResults`
        covariance object from sherpa covar()

    Returns
    -------
    table : `astropy.table.Table`
        containes the error min and max on each fitted parameters of the model
    """
    list_covar_names=list()
    list_covar_vals=list()
    list_covar_vals.insert(0, energy.value)
    list_covar_names.insert(0,'energy')
    for i_covar,name in enumerate(covar.parnames):
        list_covar_names.append(name+"_min")
        list_covar_names.append(name+"_max")
        if not covar.parmins[i_covar]:
             list_covar_vals.append(0)
        else:
            list_covar_vals.append(covar.parmins[i_covar])
        if not covar.parmaxes[i_covar]:
            list_covar_vals.append(0)
        else:
            list_covar_vals.append(covar.parmaxes[i_covar])
    table=Table(np.asarray(list_covar_vals), names= list_covar_names)
    return table

def result_table_CG(result, step):
    """

    Parameters
    ----------
    result : `~sherpa.fit.FitResults`
        result object from sherpa fit()
    step : int
        integer matching with a particular model
    Returns
    -------
    table : `astropy.table.Table`
        containes the fitted parameters value of the sherpa model
    """
    list_result_vals=list(result.parvals)
    list_result_vals.insert(0, step)
    list_result_vals.append(result.dof)
    list_result_vals.append(result.statval)
    list_result_names=list(result.parnames)
    list_result_names.insert(0,'step')
    list_result_names.append('dof')
    list_result_names.append('statval')
    table=Table(np.asarray(list_result_vals), names= list_result_names)
    return table

def covar_table_CG(covar, step):
    """

    Parameters
    ----------
    covar : `~sherpa.fit.ErrorEstResults`
        covariance object from sherpa covar()

    Returns
    -------
    table : `astropy.table.Table`
        containes the error min and max on each fitted parameters of the model
    """
    list_covar_names=list()
    list_covar_vals=list()
    list_covar_vals.insert(0, step)
    list_covar_names.insert(0,'step')
    for i_covar,name in enumerate(covar.parnames):
        list_covar_names.append(name+"_min")
        list_covar_names.append(name+"_max")
        if not covar.parmins[i_covar]:
             list_covar_vals.append(0)
        else:
            list_covar_vals.append(covar.parmins[i_covar])
        if not covar.parmaxes[i_covar]:
            list_covar_vals.append(0)
        else:
            list_covar_vals.append(covar.parmaxes[i_covar])
    table=Table(np.asarray(list_covar_vals), names= list_covar_names)
    return table

def rebin_profile2(value, nrebin):
    """

    Parameters
    ----------
    value
    bin
    err
    nrebin

    Returns
    -------

    """

    i_rebin = np.arange(0, len(value), nrebin)
    value_rebin = np.array([])
    for i in range(len(i_rebin[:-1])):
        value_rebin = np.append(value_rebin, np.mean(value[i_rebin[i]:i_rebin[i + 1]]))
    value_rebin = np.append(value_rebin, np.mean(value[i_rebin[i + 1]:]))
    return value_rebin

def rebin_profile(value, bin, err, nrebin):
    """

    Parameters
    ----------
    value
    bin
    err
    nrebin

    Returns
    -------

    """

    i_rebin = np.arange(0, len(value), nrebin)
    value_rebin = np.array([])
    bin_rebin = np.array([])
    err_rebin = np.array([])
    for i in range(len(i_rebin[:-1])):
        value_rebin = np.append(value_rebin, np.mean(value[i_rebin[i]:i_rebin[i + 1]]))
        bin_rebin = np.append(bin_rebin, np.mean(bin[i_rebin[i]:i_rebin[i + 1]]))
        err_rebin = np.append(err_rebin, np.mean(err[i_rebin[i]:i_rebin[i + 1]]))
    value_rebin = np.append(value_rebin, np.mean(value[i_rebin[i + 1]:]))
    bin_rebin = np.append(bin_rebin, np.mean(bin[i_rebin[i + 1]:]))
    err_rebin = np.append(err_rebin, np.mean(err[i_rebin[i + 1]:]))
    return value_rebin, bin_rebin, err_rebin


from sklearn.model_selection import GridSearchCV, KFold, StratifiedKFold, cross_val_score
from sklearn.preprocessing import MinMaxScaler, StandardScaler, RobustScaler
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score
from sklearn.decomposition import PCA
from collections import Counter
import numpy as np

def decode_time_step(X_i, y, y_dict, clf, scaler, n_splits=5, sampler=[],
                     do_pca=False, n_components=0.95, permute_train_labels=False,
                     compute_auc=False):
    """ Run a classification of data ``X_i`` with labels ``y`` using a Stratified K-Folds cross-validation
    where ``n_splits`` is the number of folds.
    Classification pipeline, for each one of the Stratified K-Folds :
        1. If ``do_pca`` is True, first do a standardization scaling and then apply PCA and keep only the first ``n_components``
        2. Apply the ``scaler``. Fit the transform on the training set and apply it on the test set
        3. Resample the train set so that the train set is balanced between classes, using the ``sampler`` argument
        4. Train the classifier on the train set (If ``permute_train_labels`` is True, permute the training labels first)
        5. Predict labels on the test set
        6. Evaluate the performances with several scores

    See also :func:`timedecoder.TimeDecoder.decode`

    Parameters
    ----------
    X_i : 2D array [n_features, n_trials]
        Feature array
    y : array [n_trials]
        Label of each trial in ``X_i``
    y_dict : dict
        Label dictionnary
    clf : sklearn classifier
        Scikit-Learn classifier
    scaler : sklearn scaler
        Scikit-Learn scaler
    n_splits : int
        Number of folds for the Stratified K-Folds cross-validation
    sampler : sklearn sampler
        Scikit learn sampler - see :func:`timedecoder.get_sampler`
    do_pca : bool (default: False)
        If True, apply a PCA decomposition and keep only a certain amount of components given ``n_components``
    n_components : int | float
        Number of components to keep when running the PCA
        If ``0 < n_components < 1`` and ``svd_solver == 'full'``, select the
        number of components such that the amount of variance that needs to be
        explained is greater than the percentage specified by n_components.
    permute_train_labels : bool (default: False)
        If True, permute the training labels. Used for computing the chance level.
    compute_auc : bool (default: False)
        If True, will try to compute the Area Under the Curve score

    Returns
    -------
    accuracy_mean : float
        Accuracy, mean over the K-folds
    f1_mean : float
        F1-score, mean over the K-folds
    precision_mean : float
        Precision, mean over the K-folds
    recall_mean : float
        Recall, mean over the K-folds
    class_acc_mean : array [n_classes]
        Class-accuracy for each class, mean over the K-folds
    auc_mean : float
        Area under the curve, mean over the K-folds
    """
    if X_i.ndim != 2:
        raise ValueError('X_i argument must have 2 dimensions [n_features, n_trials]')
    # Check there are only 2 classes
    y_unique = np.unique(y)
    n_classes = y_unique.size
    if not n_classes == 2:
        raise ValueError('Decoding only works with 2 classes')
    if sampler and hasattr(clf, 'class_weight') and clf.class_weight is not None:
        raise ValueError('Cannot combine class_weight with resampling methods')
    skf = StratifiedKFold(n_splits=n_splits, shuffle=True)
    # Get train and test sets
    precision, recall, f1, accuracy, auc = np.zeros((5, n_splits))
    class_acc = np.zeros((n_splits, n_classes))
    imbalanced_class = False
    if do_pca:
        pca = PCA(n_components=n_components)
    for i_split, (train_idx, test_idx) in enumerate(skf.split(X_i, y)):
        X_train, X_test = X_i[train_idx, :], X_i[test_idx, :]
        y_train, y_test = y[train_idx], y[test_idx]
        if permute_train_labels:
            y_train = np.random.permutation(y_train)
        # If PCA, do standardization scaling and PCA
        if do_pca:
            std_scaler = StandardScaler()
            X_train = std_scaler.fit_transform(X_train)
            X_test = std_scaler.transform(X_test)
            X_train = pca.fit_transform(X_train)
            X_test = pca.transform(X_test)
        # Scale train set
        X_train_scaled = scaler.fit_transform(X_train, y_train)
        X_test_scaled = scaler.transform(X_test)
        # Resample X_train so that the train set is balanced between classes and fit the model
        if sampler:
            X_train_scaled_re, y_train_re = sampler.fit_sample(X_train_scaled, y_train)
        else:
            X_train_scaled_re, y_train_re = X_train_scaled, y_train
        if not imbalanced_class and np.unique(list(Counter(y_train_re).values())).size > 1:
            imbalanced_class = True
        clf.fit(X_train_scaled_re, y_train_re)
        # Test the model on the test set
        y_test_predict = clf.predict(X_test_scaled)
        accuracy[i_split] = accuracy_score(y_test, y_test_predict)
        class_acc[i_split] = [np.sum((y_test == y_i) & (y_test_predict == y_i)) / np.sum(y_test == y_i) for y_i in y_unique]
        try:
            f1[i_split] = f1_score(y_test, y_test_predict)
            recall[i_split] = recall_score(y_test, y_test_predict)
            precision[i_split] = precision_score(y_test, y_test_predict)
        except:
            print('Could not compute f1 or recall or precision score')
        if compute_auc:
            y_prob = clf.predict_proba(X_test_scaled)
            auc[i_split] = roc_auc_score(y_test == clf.classes_[0], y_prob[:, 0])
    return accuracy.mean(), f1.mean(), precision.mean(), recall.mean(), class_acc.mean(0), auc.mean(0)

def temporal_generalization_step(X, i_time, y, y_dict, clf, scaler, n_splits=5, sampler=[], do_pca=False,
                                 n_components=0.95, permute_train_labels=False):
    """ Temporal generalization step.
    Train at time ``i_time`` and test for all time points. Use a stratified K-folds cross validation.

    Pipeline, for each stratified K-folds:
      1. If ``do_pca`` is True, first do a standardization scaling and then apply PCA and keep only the first ``n_components`` on the train set
      2. Apply the ``scaler``. Fit the transform on the training set
      3. Resample the train set so that the train set is balanced between classes, using the ``sampler`` argument
      4. Train the classifier on the train set (If ``permute_train_labels`` is True, permute the training labels first)
      5. For each time point :
        * If ``do_pca`` is True, do a standardization scaling and then apply PCA on the test set
        * Apply the ``scaler`` on the test set
        * Predict labels on the test set
        * Evaluate the performances with several scores

    See also :func:`timedecoder.TimeDecoder.temporal_generalization`

    Parameters
    ----------
    X : 3D array [n_features, n_pnts, n_trials]
        Temporal feature array
    i_time : int
        Training time point
    y : array [n_trials]
        Label array
    y_dict : dict
        Label dictionnary
    clf : sklearn classifier
        Scikit-Learn classifier
    scaler : sklearn scaler
        Scikit-Learn scaler
    n_splits : int
        Number of folds for the Stratified K-Folds cross-validation
    sampler : sklearn sampler
        Scikit learn sampler - see :func:`timedecoder.get_sampler`
    do_pca : bool (default: False)
        If True, apply a PCA decomposition and keep only a certain amount of components given ``n_components``
    n_components : int | float
        Number of components to keep when running the PCA
        If ``0 < n_components < 1`` and ``svd_solver == 'full'``, select the
        number of components such that the amount of variance that needs to be
        explained is greater than the percentage specified by n_components.
    permute_train_labels : bool (default: False)
        If True, permute the training labels. Used for computing the chance level.

    Returns
    -------
    accuracy_mean : float
        Accuracy, mean over the K-folds
    class_acc_mean : array [n_classes]
        Class-accuracy for each class, mean over the K-folds
    """
    (n_features, n_pnts, n_trials) = X.shape
    skf = StratifiedKFold(n_splits=n_splits, shuffle=True)
    # Get train and test sets
    accuracy, auc = np.zeros((2, n_splits, n_pnts))
    X_i = np.atleast_2d(X[:, i_time, :].squeeze()).T[:, :]
    if do_pca:
        pca = PCA(n_components=n_components)
    for i_split, (train_idx, test_idx) in enumerate(skf.split(X_i, y)):
        # --- TRAINING of the model at time i ---
        X_train, y_train, y_test = X_i[train_idx, :], y[train_idx], y[test_idx]
        if permute_train_labels:
            y_train = np.random.permutation(y_train)
        # If PCA, do standardization scaling and PCA
        if do_pca:
            std_scaler = StandardScaler()
            X_train = std_scaler.fit_transform(X_train)
            X_train = pca.fit_transform(X_train)
        # Scaling
        X_train_scaled = scaler.fit_transform(X_train, y_train)
        # Resample X_train so that the train set is balanced between classes and fit the model
        if sampler:
            X_train_scaled, y_train = sampler.fit_sample(X_train_scaled, y_train)
        clf.fit(X_train_scaled, y_train)
        # --- TEST for each time ----
        for j_time in range(n_pnts):
            X_test_j = np.atleast_2d(X[:, j_time, test_idx].squeeze()).T[:, :]
            # If PCA, do standardization scaling and PCA
            if do_pca:
                X_test_j = std_scaler.transform(X_test_j)
                X_test_j = pca.transform(X_test_j)
            # Scale train set
            X_test_scaled_j = scaler.transform(X_test_j)
            # Test the model on the test set
            y_test_predict_j = clf.predict(X_test_scaled_j)
            y_prob_j = clf.predict_proba(X_test_scaled_j)
            accuracy[i_split, j_time] = accuracy_score(y_test, y_test_predict_j)
            auc[i_split, j_time] = roc_auc_score(y_test == clf.classes_[0], y_prob_j[:, 0])
    return accuracy.mean(0), auc.mean(0)


from math import floor

# Hp: n%2 = 0 ==> n is even
# Later, we'll define not even problem

def merge(ary1, ary2):
    queue = []
    while len(ary1) > 0 and len(ary2) > 0:

        min_val = min(ary1[0][1], ary2[0][1])
        if min_val == ary1[0][1]:
            queue.append(ary1[0]) # append index of the smallest
            flag1 = 1
        else:
            queue.append(ary2[0]) # append index of the smallest
            flag1 = 2

        # delete the number ust added to the queue
        if flag1 == 1:
            del ary1[0]
        else:
            del ary2[0]

    # if one array is empty, just extend queue with the remaining sorted portion of the other array
    if len(ary1) > 0:
        queue.extend(ary1)
    else:
        queue.extend(ary2)

    return queue

def mergesort(reads_tuples): # list of tuple, each tuple formatted as (read_id, 'sequence')
    if len(reads_tuples) == 1:
        return reads_tuples

    else:  # split and apply double recursion
        n = floor(len(reads_tuples) / 2)
        return merge(mergesort(reads_tuples[:n]), mergesort(reads_tuples[n:]))


from pymongo import MongoClient

from bs4 import BeautifulSoup

from flask import Flask, render_template, jsonify, request

from my_project.static import config

app = Flask(__name__)

client = MongoClient('localhost', 27017)
db = client.medihelper

import requests

headers = {
    'Authorization': 'KakaoAK ' + config.kakao_api_key
}

# HTML 화면 보여주기
@app.route('/')
def home():
    return render_template('index.html')

@app.route('/search_pharmacy')
def ph():
    return render_template('pharmacy.html')

@app.route('/search_medicine')
def medic():
    return render_template('medicine.html')

# 의약품 상세정보 가져오기
@app.route('/detail&seq=<id>')
def get_detail(id):
    from urllib.request import Request, urlopen
    from urllib.parse import urlencode, quote_plus, unquote

    service_key = unquote(config.dataset_api_key)

    url = 'http://apis.data.go.kr/1471057/MdcinPrductPrmisnInfoService/getMdcinPrductItem'

    queryParams = '?' + urlencode(
        {
            quote_plus('ServiceKey'): service_key,
            quote_plus('item_seq'): id,
            quote_plus('induty'): '의약품',
            quote_plus('spclty_pblc'): '전문의약품'
        })

    requests = Request(url + queryParams)
    requests.get_method = lambda: 'GET'
    response_body = urlopen(requests).read()
    res = response_body.decode('utf-8')

    xmlobj = BeautifulSoup(res, 'lxml-xml')

    rows = xmlobj.find('item')

    datas = []

    # 의약품 정보(고유번호, 품목명, 업체명, 성상, 원료성분, 저장방법, 유효기간) 가져오기
    item_seq = rows.select_one('ITEM_SEQ').text
    item_name = rows.select_one('ITEM_NAME').text
    entp_name = rows.select_one('ENTP_NAME').text

    chart = rows.select_one('CHART').text
    material_name = rows.select_one('MATERIAL_NAME').text
    storage_method = rows.select_one('STORAGE_METHOD').text
    valid_term = rows.select_one('VALID_TERM').text

    # 효능효과 / 용법용량 / 주의사항 가져오기
    ee = rows.select_one('EE_DOC_DATA')
    ud = rows.select_one('UD_DOC_DATA')
    nb = rows.select_one('NB_DOC_DATA')

    ee_doc = ee.select('ARTICLE')
    ud_doc = ud.select('ARTICLE')
    nb_doc = nb.select('ARTICLE')

    elen = len(ee_doc)
    ulen = len(ud_doc)
    nlen = len(nb_doc)

    ee_doc_data = ""
    ud_doc_data = ""
    nb_doc_data = ""

    for i in range(0, elen):
        if ee_doc_data != "":
            ee_doc_data += ' '
        ee_doc_data += ee_doc[i]['title']

        if ee_doc[i].text != "":
            ee_doc_data += ' ' + ee_doc[i].text.strip()

    # print(ee_doc_data)

    for i in range(0, ulen):
        if ud_doc_data != "":
            ud_doc_data += ' '
        ud_doc_data += ud_doc[i]['title']

        para = ud_doc[i].select('PARAGRAPH')

        for j in range(0, len(para)):
            if para[j]['tagName'] == 'p':
                ud_doc_data += ' ' + para[j].text.strip()

        # if ud_doc[i].text != "":
        #    ud_doc_data += ' ' + ud_doc[i].text.strip()

    # print(ud_doc_data)

    for i in range(0, nlen):
        if nb_doc_data != "":
            nb_doc_data += ' '
        nb_doc_data += nb_doc[i]['title']

        para = nb_doc[i].select('PARAGRAPH')

        for j in range(0, len(para)):
            if para[j]['tagName'] == 'p':
                nb_doc_data += ' ' + para[j].text.strip()

        # if nb_doc[i].text != "":
        #   nb_doc_data += ' ' + nb_doc[i].text.strip()

    # print(nb_doc_data)

    doc = {
        'item_seq': item_seq,
        'item_name': item_name,
        'entp_name': entp_name,
        'chart': chart,
        'material_name': material_name,
        'storage_method': storage_method,
        'valid_term': valid_term,
        'ee_doc_data': ee_doc_data,
        'ud_doc_data': ud_doc_data,
        'nb_doc_data': nb_doc_data
    }

    #print(doc)

    return render_template('detail.html', data=doc)

perPage_list = 10

@app.route('/medicine', methods=['POST'])
def search_medicine():
    word = request.form['keyword']
    option = request.form['option']

    from urllib.request import Request, urlopen
    from urllib.parse import urlencode, quote_plus, unquote

    service_key = unquote(config.dataset_api_key)

    url = 'http://apis.data.go.kr/1471057/MdcinPrductPrmisnInfoService/getMdcinPrductItem'

    init_page=1

    if option == '품목명':
        queryParams = '?' + urlencode(
            {
                quote_plus('ServiceKey'): service_key,
                quote_plus('item_name'): word,
                quote_plus('induty'): '의약품',
                quote_plus('spclty_pblc'): '전문의약품',
                quote_plus('pageNo'): init_page,
                quote_plus('numOfRows'): perPage_list
            })

    if option == '업체명':
        queryParams = '?' + urlencode(
            {
                quote_plus('ServiceKey'): service_key,
                quote_plus('entp_name'): word,
                quote_plus('induty'): '의약품',
                quote_plus('spclty_pblc'): '전문의약품',
                quote_plus('pageNo'): init_page,
                quote_plus('numOfRows'): perPage_list
            })

    requests = Request(url + queryParams)
    requests.get_method = lambda: 'GET'
    response_body = urlopen(requests).read()
    res = response_body.decode('utf-8')

    xmlobj = BeautifulSoup(res, 'lxml-xml')

    total = xmlobj.find('totalCount').text

    rows = xmlobj.findAll('item')

    rowsLen = len(rows)

    datas = []

    for data in range(0, rowsLen):
        # 의약품 정보(고유번호, 품목명, 업체명, 성상, 원료성분, 저장방법, 유효기간) 가져오기
        item_seq = rows[data].select_one('ITEM_SEQ').text
        item_name = rows[data].select_one('ITEM_NAME').text
        entp_name = rows[data].select_one('ENTP_NAME').text

        doc = {
            'item_seq': item_seq,
            'item_name': item_name,
            'entp_name': entp_name
        }

        datas.append(doc)

    #print(datas)

    return jsonify({'result': 'success', 'data': datas, 'total': total})

@app.route('/medicine/page', methods=['POST'])
def get_medic_page():
    word = request.form['area']
    option = request.form['option']
    page = request.form['page']

    from urllib.request import Request, urlopen
    from urllib.parse import urlencode, quote_plus, unquote

    service_key = unquote(config.dataset_api_key)

    url = 'http://apis.data.go.kr/1471057/MdcinPrductPrmisnInfoService/getMdcinPrductItem'

    if option == '품목명':
        queryParams = '?' + urlencode(
            {
                quote_plus('ServiceKey'): service_key,
                quote_plus('item_name'): word,
                quote_plus('induty'): '의약품',
                quote_plus('spclty_pblc'): '전문의약품',
                quote_plus('pageNo'): page,
                quote_plus('numOfRows'): perPage_list
            })

    if option == '업체명':
        queryParams = '?' + urlencode(
            {
                quote_plus('ServiceKey'): service_key,
                quote_plus('entp_name'): word,
                quote_plus('induty'): '의약품',
                quote_plus('spclty_pblc'): '전문의약품',
                quote_plus('pageNo'): page,
                quote_plus('numOfRows'): perPage_list
            })

    requests = Request(url + queryParams)
    requests.get_method = lambda: 'GET'
    response_body = urlopen(requests).read()
    res = response_body.decode('utf-8')

    xmlobj = BeautifulSoup(res, 'lxml-xml')

    rows = xmlobj.findAll('item')

    rowsLen = len(rows)

    datas = []

    for data in range(0, rowsLen):
        # 의약품 정보(고유번호, 품목명, 업체명, 성상, 원료성분, 저장방법, 유효기간) 가져오기
        item_seq = rows[data].select_one('ITEM_SEQ').text
        item_name = rows[data].select_one('ITEM_NAME').text
        entp_name = rows[data].select_one('ENTP_NAME').text

        doc = {
            'item_seq': item_seq,
            'item_name': item_name,
            'entp_name': entp_name
        }

        datas.append(doc)

    return jsonify({'result': 'success', 'data': datas})

@app.route('/place', methods=['POST'])
def search_pharmacy():
    area = request.form['area']

    params = {
        'query': area
    }

    response = requests.get('https://dapi.kakao.com/v2/local/search/address.json', headers=headers, params=params)

    data2 = response.json()

    address = data2['documents'][0]['address']

    x = address['x']
    y = address['y']

    is_end = False
    page = 0

    while is_end == False:
        page += 1

        params2 = {
            'y': y,
            'x': x,
            'radius': '20000',
            'query': '약국',
            'page': page,
            'size': perPage_list,
            'sort': "distance"
        }

        response = requests.get('https://dapi.kakao.com/v2/local/search/keyword.json', headers=headers, params=params2)

        is_end = response.json()['meta']['is_end']

        if page == 1:
            data = response.json()['documents']

    total = page * perPage_list

    return jsonify({'result': 'success', 'total': total, 'data': data, 'x': x, 'y': y})

@app.route('/page', methods=['POST'])
def search_list():
    area = request.form['area']
    page = request.form['page']

    params = {
        'query': area
    }

    response = requests.get('https://dapi.kakao.com/v2/local/search/address.json', headers=headers, params=params)

    data2 = response.json()

    address = data2['documents'][0]['address']

    x = address['x']
    y = address['y']

    params2 = {
        'y': y,
        'x': x,
        'radius': '20000',
        'query': '약국',
        'page': page,
        'size': perPage_list,
        'sort': "distance"
    }

    response = requests.get('https://dapi.kakao.com/v2/local/search/keyword.json', headers=headers, params=params2)

    data = response.json()['documents']

    return jsonify({'result': 'success', 'data': data, 'x': x, 'y': y})

if __name__ == '__main__':
    app.run('0.0.0.0', port=5000, debug=True)


from ranger.api.commands import *
import os

class my_edit(Command):
    """:my_edit <filename>

    A sample command for demonstration purposes that opens a file in an editor.
    """

    def execute(self):
        if self.arg(1):
            target_filename = self.rest(1)
        else:
            target_filename = self.fm.thisfile.path

        self.fm.notify("Let's edit the file " + target_filename + "!")

        if not os.path.exists(target_filename):
            self.fm.notify("The given file does not exist!", bad=True)
            return

        self.fm.edit_file(target_filename)

    def tab(self, tabnum):
        return self._tab_directory_content()


"""
https://leetcode.com/problems/number-of-steps-to-reduce-a-number-to-zero/
Given a non-negative integer num, return the number of steps to reduce it to zero.
If the current number is even, you have to divide it by 2, otherwise, you have to subtract 1 from it.

Input: num = 14
Output: 6
Explanation:
Step 1) 14 is even; divide by 2 and obtain 7.
Step 2) 7 is odd; subtract 1 and obtain 6.
Step 3) 6 is even; divide by 2 and obtain 3.
Step 4) 3 is odd; subtract 1 and obtain 2.
Step 5) 2 is even; divide by 2 and obtain 1.
Step 6) 1 is odd; subtract 1 and obtain 0.

Input: num = 8
Output: 4

Input: num = 123
Output: 12
"""

def number_of_steps(num: int) -> int:
    steps = 0
    while num != 0:
        if num % 2 == 0:
            num = num / 2
        else:
            num = num - 1
        steps = steps + 1
    return steps

def number_of_steps2(num: int) -> int:
    """viết gọn hơn sử dụng ternary operator"""
    steps = 0
    while num != 0:
        num = num / 2 if num % 2 == 0 else num - 1
        steps = steps + 1
    return steps

def number_of_steps3(num: int) -> int:
    """
    sử dụng đệ quy recursive
    case: điều kiện dừng
    case: trả về cái gì sau mỗi lần lặp
        -> chính là cái ta quan tâm: ở đây là số bước lặp. số bước lặp = số bước lặp cũ + 1
    """

    if num == 0:
        return 0
    if num % 2 == 0:
        return 1 + number_of_steps3(num / 2)
    else:
        return 1 + number_of_steps3(num - 1)

if __name__ == '__main__':
    num = 123
    print(number_of_steps3(num))


"""This module provides support for calculating AHP weights and
consistency ratios (CR)"""

from decimal import Decimal as D
from numpy.linalg import eig

# Random index devised by Saaty. Used for Consistency Ratio (CR) calculation.

RI = (0, 0, D('0.58'), D('0.9'), D('1.12'),
      D('1.24'), D('1.32'), D('1.41'), D('1.45'), D('1.49'),
      D('1.51'), D('1.48'), D('1.56'), D('1.57'), D('1.59')
)

def calculate_weights(arr, rounding=4):
   """Given pairwise comparisons array, calculate weights using the AHP method.

   Take the following example array:

   +-----+-----+---+
   |  1  | 1/3 | 5 |
   +-----+-----+---+
   |  3  |  1  | 7 |
   +-----+-----+---+
   | 1/5 | 1/7 | 1 |
   +-----+-----+---+

   Set up the array:

   >>> from numpy import array
   >>> arr = array([ [1, 1./3, 5], [3,1,7], [1./5,1./7,1] ])

   Calculate the weights (= normalized primary eigenvector):

   >>> calculate_weights(arr, rounding=4)
   [Decimal('0.2790'), Decimal('0.6491'), Decimal('0.0719')]
   """

   PLACES = D(10) ** -(rounding)

   # get eigenvalues and vectors
   evas, eves = eig(arr)

   # get primary eigenvalue and vector
   eva = max(evas)
   eva_idx = evas.tolist().index(eva)
   eve = eves.take((eva_idx,), axis=1)

   # priority vector = normalized primary eigenvector
   normalized = eve / sum(eve)

   # turn into list of real part values
   vector = [abs(e[0]) for e in normalized]

   # return nice rounded Decimal values
   return [ D( str(v) ).quantize(PLACES) for v in vector ]

def calculate_consistency(arr):
   """Given pairwise comparisons array, calculate consistency ratio (CR)
   for the comparisons.

   Example:

   >>> from numpy import array
   >>> arr = array([ [1, 1./3, 1./9, 1./5], [3,1,1,1], [9,1,1,3], [5,1,1./3,1] ])
   >>> print calculate_consistency(arr)
   0.0557579272574

   """

   # get largest (ie. primary) eigenvalue
   eva = max(eig(arr)[0]).real

   # calculate consistency index (CI)
   n = len(arr)
   CI = (eva-n) / (n-1)

   # return CR
   return CI / float(RI[n])

if __name__ == "__main__":
   import doctest
   doctest.testmod()


class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """

        for i in range(len(nums)):
            for j in range(i+1,len(nums)):
                if nums[i] + nums[j] == target:
                    return [i,j]

        return None

if __name__ == '__main__':

    test = Solution()
    print(test.twoSum([0,2,4,8],12))