'''
Given a linked list, swap every two adjacent nodes and return its head.

You may not modify the values in the list's nodes, only nodes itself may be changed.
'''

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
'''
Here, pre is the previous node. Since the head doesn't have a previous node, I just use self instead. Again, a is the current node and b is the next node.

To go from pre -> a -> b -> b.next to pre -> b -> a -> b.next, we need to change those three references. Instead of thinking about in what order I change them, I just change all three at once.

e.g dummy -> 1 -> 2 -> 3 -> 4 ---> dummy -> 2 -> 1 -> 3 -> 4
    pre is 1
    dummy -> 2 -> 1 -> 3 -> 4 ---> dummy -> 2 -> 1 -> 4 -> 3
    pre is 3
    3.next is None -> exit loop
'''
def swapPairs(head):
    dummy = pre = ListNode(0)
    pre.next = head
    while pre.next and pre.next.next:
        a = pre.next
        b = a.next
        pre.next, b.next, a.next = b, a, b.next
        pre = a
    return dummy.next

a = ListNode(1)
a.next = ListNode(2)
a.next.next = ListNode(3)
a.next.next.next = ListNode(4)

node = swapPairs(a)
print(node)


"""mysite URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/dev/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
# from django.conf.urls import handler404, handler500
# from django.conf import settings
# from django.conf.urls.static import static
from . import views

# Project总路由
urlpatterns = [
    path('', views.home, name='url_home'),     # project首页url: localhost:8080/
    path('admin/', admin.site.urls),
    path('blog/', include('blog.blog_urls')),   # blog app分支url: localhost:8080/blog
    path('comment/', include('comment.comment_urls')),  # comment app分支url: localhost:8080/comment
    path('user/', include('user_admin.user_urls')),   # user_admin app分支url: localhost:8080/user
    # 设置ckeditor url
    # path('ckeditor/', include('ckeditor-uploader.urls')),
]

# 自定义404、500页面
handler404 = 'mysite.views.page_not_found'
# handler500 = 'mysite.views.page_error'

# urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


#spam.py
print('from the spam.py')
__all__=['money']
money=1000

def read1():
    print('spam->read1->money',money)

def read2():
    print('spam->read2 calling read')
    read1()

def change():
    global money
    money=0

#spam.py当做脚本执行，__name__='__main__'
#spam.py当做模块导入，__name__=模块名
# print('当前文件的用途是: ',__name__)

if __name__ == '__main__':
    print('当做脚本执行')
    change()
    print(money)


# from tokenize import group
# from email.mime import image
import shutil
import tempfile
from django.contrib.auth import get_user_model
from django .core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase, Client, override_settings
from django.core.cache import cache
from django.urls import reverse
from django import forms
from django.conf import settings

from ..models import Follow, Group, Post

User = get_user_model()

POSTS_ON_PAGE = 16
POSTS_ON_FIRST_PAGE = 10
POSTS_ON_SECOND_PAGE = 5

TEMP_MEDIA_ROOT = tempfile.mkdtemp(dir=settings.BASE_DIR)

@override_settings(MEDIA_ROOT=TEMP_MEDIA_ROOT)
class PostViewTest(TestCase):
    @classmethod
    def tearDownClass(cls):
        super().tearDownClass()
        shutil.rmtree(TEMP_MEDIA_ROOT, ignore_errors=True)

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.user = User.objects.create_user(username='auth')
        cls.group = Group.objects.create(
            title='Тестовая группа',
            slug='test_slug',
            description='Тестовое описание',
        )
        small_gif = (
            b'\x47\x49\x46\x38\x39\x61\x01\x00'
            b'\x01\x00\x00\x00\x00\x21\xf9\x04'
            b'\x01\x0a\x00\x01\x00\x2c\x00\x00'
            b'\x00\x00\x01\x00\x01\x00\x00\x02'
            b'\x02\x4c\x01\x00\x3b'
        )
        uploaded = SimpleUploadedFile(
            name='small.gif',
            content=small_gif,
            content_type='image/gif'
        )
        cls.post = Post.objects.create(
            author=cls.user,
            text='Тестовый пост',
            group=cls.group,
            image=uploaded,
        )

    def setUp(self):
        # Создаем неавторизованный клиент
        self.guest_client = Client()
        # Создаем авторизованного клиента
        # self.user = User.objects.create_user(username='Somebody')
        self.authorized_client = Client()
        self.authorized_client.force_login(self.user)
        # создаем авторизованного автора поста
        self.author_client = Client()
        self.author = PostViewTest.user
        self.author_client.force_login(self.author)

    # Проверяем используемые шаблоны
    def test_pages_uses_correct_template(self):
        """URL-адрес использует соответствующий шаблон."""
        # Собираем в словарь пары "reverse(name): имя_html_шаблона"
        templates_pages_names = {
            reverse('posts:index'): 'posts/index.html',
            reverse(
                'posts:group_list',
                args=(self.group.slug,)
            ): 'posts/group_list.html',
            reverse(
                'posts:profile',
                args=(self.user.username,)
            ): 'posts/profile.html',
            reverse(
                'posts:post_detail',
                args=(self.post.id,)
            ): 'posts/post_detail.html',
            reverse(
                'posts:post_edit',
                args=(self.post.id,)
            ): 'posts/create_post.html',
            reverse('posts:post_create'): 'posts/create_post.html',
            reverse('posts:follow_index'): 'posts/follow.html',
        }

        for reverse_name, template in templates_pages_names.items():
            with self.subTest(reverse_name=reverse_name):
                response = self.author_client.get(reverse_name)
                self.assertTemplateUsed(response, template)

    # Проверка словаря context страницы index
    def test_index_page_show_correct_context(self):
        """Шаблон index сформирован с правильным контекстом."""
        response = self.authorized_client.get(reverse('posts:index'))
        first_object = response.context['page_obj'][0]
        self.assertEqual(first_object.id, self.post.id)
        self.assertEqual(first_object.text, 'Тестовый пост')
        self.assertEqual(first_object.author, self.post.author)
        self.assertEqual(first_object.group, self.post.group)
        self.assertEqual(first_object.image, self.post.image)

    # Проверка словаря context страницы group_list
    def test_group_list_page_show_correct_context(self):
        """Шаблон group_list сформирован с правильным контекстом."""
        response = self.authorized_client.get(
            reverse('posts:group_list', args=(self.group.slug,))
        )
        first_object = response.context['page_obj'][0]
        self.assertEqual(first_object.id, self.post.id)
        self.assertEqual(first_object.text, 'Тестовый пост')
        self.assertEqual(first_object.author, self.post.author)
        self.assertEqual(first_object.group, self.post.group)
        self.assertEqual(first_object.image, self.post.image)

    # Проверка словаря context страницы profile
    def test_profile_page_show_correct_context(self):
        """Шаблон profile сформирован с правильным контекстом."""
        response = self.authorized_client.get(
            reverse('posts:profile', args=(self.post.author,))
        )
        first_object = response.context['page_obj'][0]
        self.assertEqual(first_object.id, self.post.id)
        self.assertEqual(first_object.text, 'Тестовый пост')
        self.assertEqual(first_object.author, self.post.author)
        self.assertEqual(first_object.group, self.post.group)
        self.assertEqual(first_object.image, self.post.image)

    # Проверка словаря context страницы post_detail
    def test_post_detail_page_show_correct_context(self):
        """Шаблон post_detail сформирован с правильным контекстом."""
        response = self.authorized_client.get(
            reverse('posts:post_detail', args=(self.post.id,))
        )
        self.assertEqual(response.context.get('post').author, self.post.author)
        self.assertEqual(response.context.get('post').text, 'Тестовый пост')
        self.assertEqual(response.context.get('post').group, self.post.group)
        self.assertEqual(response.context.get('post').image, self.post.image)

    # Проверка словаря context страницы create_post (в нём передаётся форма)
    def test_create_post_show_correct_context(self):
        """На странице create_post сформирована
        правильная форма создания поста.
        """
        response = self.authorized_client.get(reverse('posts:post_create'))
        # Словарь ожидаемых типов полей формы:
        form_fields = {
            'text': forms.fields.CharField,
            'group': forms.fields.ChoiceField,
            'image': forms.fields.ImageField,
        }
        # Проверяем, что типы полей формы соответствуют ожиданиям
        for value, expected in form_fields.items():
            with self.subTest(value=value):
                form_field = response.context.get('form').fields.get(value)
                self.assertIsInstance(form_field, expected)

    # Проверка словаря context страницы create_post (в нём передаётся форма)
    def test_create_post_show_correct_context(self):
        """На странице create_post сформирована
        правильная форма редактирования поста.
        """
        response = self.author_client.get(
            reverse('posts:post_edit', args=(self.post.id,))
        )
        # Словарь ожидаемых типов полей формы:
        form_fields = {
            'text': forms.fields.CharField,
            'group': forms.fields.ChoiceField,
            'image': forms.fields.ImageField,
        }
        # Проверяем, что типы полей формы соответствуют ожиданиям
        for value, expected in form_fields.items():
            with self.subTest(value=value):
                form_field = response.context.get('form').fields.get(value)
                self.assertIsInstance(form_field, expected)

    # Дополнительная проверка при создании поста с группой
    def test_post_with_group_show_correct(self):
        """Если при создании поста указать группу,
        он появится на страницах index, group_list, profile.
        """
        group = Group.objects.create(
            title='Тестовая группа 1',
            slug='test_slug_1',
            description='Тестовое описание 1',
        )
        group2 = Group.objects.create(
            title='Тестовая группа 2',
            slug='test_slug_2',
            description='Тестовое описание 2',
        )
        post = Post.objects.create(
            text='Тестовый пост с группой',
            author=self.user,
            group=group,
        )
        responses = {
            'index': self.author_client.get(reverse('posts:index')),
            'group_list': self.author_client.get(
                reverse('posts:group_list', args=(group.slug,))
            ),
            'profile': self.author_client.get(
                reverse('posts:profile', args=(post.author,))
            ),
        }
        for response in responses.values():
            first_object = response.context['page_obj'][0]
            self.assertEqual(first_object.text, post.text)
            self.assertEqual(first_object.author, post.author)
            self.assertEqual(first_object.group.id, group.id)
            self.assertNotEqual(first_object.group.id, group2.id)

    # Проверка кэширования главной страницы
    def test_cache_index_page(self):
        """Тест кэширования главной страницы."""
        cache.clear()
        post_2 = Post.objects.create(
            text='Тестируем кэш',
            author=self.user,
        )
        first_response = self.guest_client.get(reverse('posts:index'))
        first_content = first_response.content
        object_before_delete = first_response.context['page_obj'][0]
        self.assertEqual(object_before_delete.text, post_2.text)
        post_2.delete()
        second_response = self.guest_client.get(reverse('posts:index'))
        second_content = second_response.content
        self.assertEqual(first_content, second_content)

class PaginatorViewTest(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.user = User.objects.create_user(username='auth')
        cls.group = Group.objects.create(
            title='Тестовая группа',
            slug='test_slug',
            description='Тестовое описание',
        )
        cls.post = Post.objects.create(
            author=cls.user,
            text='Тестовый пост',
            group=cls.group,
        )
        for i in range(2, POSTS_ON_PAGE):
            Post.objects.create(
                text=f'Тестовый пост {i}',
                group=cls.group,
                author=cls.user,
            )

    def setUp(self):
        # Создаем неавторизованный клиент
        self.guest_client = Client()
        # Создаем авторизованый клиент
        self.user = User.objects.create_user(username='Somebody')
        self.authorized_client = Client()
        self.authorized_client.force_login(self.user)

    # Проверяем паджинатор
    def test_paginator(self):
        pages_names = {
            reverse('posts:index'),
            reverse('posts:group_list', args=(self.group.slug,)),
            reverse('posts:profile', args=(self.post.author,)),
        }
        for page in pages_names:
            response_first_page = self.authorized_client.get(page)
            response_second_page = self.authorized_client.get(page + '?page=2')
            posts_on_first_page = len(response_first_page.context['page_obj'])
            posts_on_second_page = len(
                response_second_page.context['page_obj']
            )
            self.assertEqual(posts_on_first_page, POSTS_ON_FIRST_PAGE)
            self.assertEqual(posts_on_second_page, POSTS_ON_SECOND_PAGE)

class FollowViewTest(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.author = User.objects.create_user(username='author')
        cls.user_follower = User.objects.create_user(username='follower')
        cls.user_not_follower = User.objects.create_user(username='somebody')

    def setUp(self):
        self.authorized_client = Client()
        self.authorized_client_follower = Client()
        self.authorized_client_follower.force_login(self.user_follower)
        self.authorized_client_not_follower = Client()
        self.authorized_client_not_follower.force_login(self.user_not_follower)

    # Проверяем возможность подписки и отписки от авторов
    def test_follow_and_unfollow(self):
        """Авторизованный пользователь может подписываться
        на других пользователей и удалять их из подписок.
        """
        Follow.objects.create(user=self.user_follower, author=self.author)
        self.assertTrue(Follow.objects.filter(
            user=self.user_follower, author=self.author).exists()
        )
        Follow.objects.filter(
            user=self.user_follower, author=self.author
        ).delete()
        self.assertFalse(Follow.objects.filter(
            user=self.user_follower, author=self.author).exists()
        )

    # Проверка появления поста в ленте подписчика
    def test_post_show_correct_for_follower(self):
        """Новая запись пользователя появляется в ленте тех, кто подписан
        на него и не появляется в ленте тех, кто не подписан.
        """
        Follow.objects.create(user=self.user_follower, author=self.author)
        response_before_post = self.authorized_client_follower.get(
            reverse('posts:follow_index')
        )
        response_before_not_follower = self.authorized_client_not_follower.get(
            reverse('posts:follow_index')
        )
        post = Post.objects.create(author=self.author, text='Новый пост')
        response_after_post = self.authorized_client_follower.get(
            reverse('posts:follow_index')
        )
        response_after_not_follower = self.authorized_client_not_follower.get(
            reverse('posts:follow_index')
        )
        self.assertNotEqual(
            response_before_post.content,
            response_after_post.content
        )
        self.assertEqual(
            response_before_not_follower.content,
            response_after_not_follower.content
        )
        new_posts = response_after_post.context['page_obj']
        self.assertIn(post, new_posts)


'''
When we pass an object to a parameter, the parameter name becomes a reference variable.

Recollecting the balloon example, it is like creating one more ribbon to the same balloon.
Thus there is one object with two reference variable, one the formal parameter and the actual parameter.
Thus any change made through one reference variable will affect the other as well.
'''

class Mobile:
    def __init__(self, price, brand):
        self.price = price
        self.brand = brand

    def change_price(mobile_obj):
        print ("Id of object inside function", id(mobile_obj))
        mobile_obj.price=3000

mob1=Mobile(1000, "Apple")
print ("Id of object in driver code", id(mob1))

mob1.change_price()
print ("Price of mob1 ", mob1.price)


# vim: set fileencoding=utf-8 :
#
# (C) 2006-2015 Guido Günther <agx@sigxcpu.org>
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, please see
#    <http://www.gnu.org/licenses/>
#
"""Build a Debian package out of a Git repository"""

from six.moves import configparser
import errno
import os, os.path
import shutil
import sys
import time
import gbp.deb as du
from gbp.command_wrappers import (Command,
                                  RunAtCommand, CommandExecFailed,
                                  RemoveTree)
from gbp.config import (GbpOptionParserDebian, GbpOptionGroup)
from gbp.deb.git import (GitRepositoryError, DebianGitRepository)
from gbp.deb.source import DebianSource, DebianSourceError
from gbp.deb.format import DebianSourceFormat
from gbp.format import format_str
from gbp.git.vfs import GitVfs
from gbp.deb.upstreamsource import DebianUpstreamSource
from gbp.errors import GbpError
import gbp.log
import gbp.notifications
from gbp.scripts.common.buildpackage import (index_name, wc_names,
                                             git_archive_submodules,
                                             git_archive_single, dump_tree,
                                             write_wc, drop_index)
from gbp.pkg import compressor_opts, compressor_aliases, parse_archive_filename
from gbp.tmpfile import init_tmpdir, del_tmpdir

def git_archive(repo, cp, output_dir, treeish, comp_type, comp_level, with_submodules):
    "create a compressed orig tarball in output_dir using git_archive"
    try:
        comp_opts = compressor_opts[comp_type][0]
    except KeyError:
        raise GbpError("Unsupported compression type '%s'" % comp_type)

    output = os.path.join(output_dir, du.orig_file(cp, comp_type))
    prefix = "%s-%s" % (cp['Source'], cp['Upstream-Version'])

    try:
        if repo.has_submodules() and with_submodules:
            repo.update_submodules()
            git_archive_submodules(repo, treeish, output, prefix,
                                   comp_type, comp_level, comp_opts)

        else:
            git_archive_single(repo, treeish, output, prefix,
                               comp_type, comp_level, comp_opts)
    except (GitRepositoryError, CommandExecFailed):
        gbp.log.err("Error generating submodules' archives")
        return False
    except OSError as e:
        gbp.log.err("Error creating %s: %s" % (output, str(e)))
        return False
    except GbpError:
        raise
    except Exception as e:
        gbp.log.err("Error creating %s: %s" % (output, str(e)))
        return False
    return True

def prepare_upstream_tarball(repo, cp, options, tarball_dir, output_dir):
    """
    Make sure we have an upstream tarball. This involves loooking in
    tarball_dir, symlinking or building it.
    """
    options.comp_type = guess_comp_type(repo,
                                        options.comp_type,
                                        cp,
                                        options.tarball_dir)
    orig_file = du.orig_file(cp, options.comp_type)

    # look in tarball_dir first, if found force a symlink to it
    if options.tarball_dir:
        gbp.log.debug("Looking for orig tarball '%s' at '%s'" % (orig_file, tarball_dir))
        if not du.DebianPkgPolicy.symlink_orig(orig_file, tarball_dir, output_dir, force=True):
            gbp.log.info("Orig tarball '%s' not found at '%s'" % (orig_file, tarball_dir))
        else:
            gbp.log.info("Orig tarball '%s' found at '%s'" % (orig_file, tarball_dir))
    # build an orig unless the user forbids it, always build (and overwrite pre-existing) if user forces it
    if options.force_create or (not options.no_create_orig and not du.DebianPkgPolicy.has_orig(orig_file, output_dir)):
        if not pristine_tar_build_orig(repo, cp, output_dir, options):
            upstream_tree = git_archive_build_orig(repo, cp, output_dir, options)
            if options.pristine_tar_commit:
                if repo.pristine_tar.has_commit(cp.name,
                                                cp.upstream_version,
                                                options.comp_type):
                    gbp.log.debug("%s already on pristine tar branch" %
                                  orig_file)
                else:
                    archive = os.path.join(output_dir, orig_file)
                    gbp.log.debug("Adding %s to pristine-tar branch" %
                                  archive)
                    repo.pristine_tar.commit(archive, upstream_tree)

#{ Functions to handle export-dir
def write_tree(repo, options):
    """
    Write a tree of the index or working copy if necessary

    @param repo: the git repository we're acting on
    @type repo: L{GitRepository}
    @return: the sha1 of the tree
    @rtype: C{str}
    """
    if options.export_dir:
        if options.export == index_name:
            tree = repo.write_tree()
        elif options.export in wc_names:
            tree = write_wc(repo, wc_names[options.export]['force'],
                            wc_names[options.export]['untracked'])
        else:
            tree = options.export
        if not repo.has_treeish(tree):
            raise GbpError("%s is not a valid treeish" % tree)
    else:
        tree = None
    return tree

def export_source(repo, tree, source, options, dest_dir, tarball_dir):
    """
    Export a version of the source tree when building in a separate directory

    @param repo: the git repository to export from
    @type repo: L{gbp.git.GitRepository}
    @param source: the source package
    @param options: options to apply
    @param dest_dir: where to export the source to
    @param tarball_dir: where to fetch the tarball from in overlay mode
    @returns: the temporary directory
    """
    # Extract orig tarball if git-overlay option is selected:
    if options.overlay:
        if source.is_native():
            raise GbpError("Cannot overlay Debian native package")
        extract_orig(os.path.join(tarball_dir,
                                  du.orig_file(source.changelog,
                                               options.comp_type)),
                     dest_dir)

    gbp.log.info("Exporting '%s' to '%s'" % (options.export, dest_dir))
    if not dump_tree(repo, dest_dir, tree, options.with_submodules):
        raise GbpError

def move_old_export(target):
    """move a build tree away if it exists"""
    try:
        os.mkdir(target)
    except OSError as e:
        if e.errno == errno.EEXIST:
            os.rename(target, "%s.obsolete.%s" % (target, time.time()))

def extract_orig(orig_tarball, dest_dir):
    """extract orig tarball to export dir before exporting from git"""
    gbp.log.info("Extracting %s to '%s'" % (os.path.basename(orig_tarball), dest_dir))

    move_old_export(dest_dir)
    upstream = DebianUpstreamSource(orig_tarball)
    upstream.unpack(dest_dir)

    # Check if tarball extracts into a single folder:
    if upstream.unpacked != dest_dir:
        # If it extracts a single folder, move its contents to dest_dir:
        gbp.log.debug("Moving %s to %s" % (upstream.unpacked, dest_dir))
        tmpdir = dest_dir + '.new'
        os.rename(upstream.unpacked, tmpdir)
        os.rmdir(dest_dir)
        os.rename(tmpdir, dest_dir)

    # Remove debian/ from unpacked upstream tarball in case of non 1.0 format
    underlay_debian_dir = os.path.join(dest_dir, 'debian')
    format_file = os.path.join('debian', 'source', 'format')
    if os.path.exists(underlay_debian_dir) and os.path.exists(format_file):
        format = DebianSourceFormat.parse_file(format_file)
        if format.version in ['2.0', '3.0']:
            gbp.log.info("Removing debian/ from unpacked upstream source at %s" % underlay_debian_dir)
            shutil.rmtree(underlay_debian_dir)

#}

def source_vfs(repo, options, tree):
    """Init source package info either from git or from working copy"""
    # FIXME: just init the correct vfs
    try:
        if tree:
            source = DebianSource(GitVfs(repo, tree))
        else:
            source = DebianSource('.')
            source.is_native() # check early if this works
    except Exception as e:
        raise GbpError("Can't determine package type: %s" % e)
    return source

def prepare_output_dir(dir):
    """Prepare the directory where the build result will be put"""
    output_dir = dir
    if not dir:
        output_dir = '..'
    output_dir = os.path.abspath(output_dir)

    try:
        os.mkdir(output_dir)
    except OSError as e:
        if e.errno != errno.EEXIST:
            raise GbpError("Cannot create output dir %s" % output_dir)
    return output_dir

def pristine_tar_build_orig(repo, cp, output_dir, options):
    """
    build orig using pristine-tar
    @return: True: orig tarball build, False: noop
    """
    if options.pristine_tar:
        if not repo.has_branch(repo.pristine_tar_branch):
            gbp.log.warn('Pristine-tar branch "%s" not found' %
                         repo.pristine_tar.branch)
        try:
            repo.pristine_tar.checkout(cp.name,
                                       cp.upstream_version,
                                       options.comp_type,
                                       output_dir)
            return True
        except CommandExecFailed:
            if options.pristine_tar_commit:
                gbp.log.debug("pristine-tar checkout failed, "
                              "will commit tarball due to "
                              "'--pristine-tar-commit'")
            else:
                raise
    return False

def get_upstream_tree(repo, cp, options):
    """Determine the upstream tree from the given options"""
    if options.upstream_tree.upper() == 'TAG':
        if cp['Upstream-Version'] is None:
            raise GitRepositoryError("Can't determine upstream version from changelog")
        upstream_tree = repo.version_to_tag(options.upstream_tag,
                                            cp['Upstream-Version'])
    elif options.upstream_tree.upper() == 'BRANCH':
        if not repo.has_branch(options.upstream_branch):
            raise GbpError("%s is not a valid branch" % options.upstream_branch)
        upstream_tree = options.upstream_branch
    else:
        upstream_tree = options.upstream_tree
    if not repo.has_treeish(upstream_tree):
        raise GbpError("%s is not a valid treeish" % upstream_tree)
    return upstream_tree

def git_archive_build_orig(repo, cp, output_dir, options):
    """
    Build orig tarball using git-archive

    @param cp: the changelog of the package we're acting on
    @type cp: L{ChangeLog}
    @param output_dir: where to put the tarball
    @type output_dir: C{Str}
    @param options: the parsed options
    @type options: C{dict} of options
    @return: the tree we built the tarball from
    @rtype: C{str}
    """
    upstream_tree = get_upstream_tree(repo, cp, options)
    gbp.log.info("%s does not exist, creating from '%s'" % (du.orig_file(cp,
                                                            options.comp_type),
                                                            upstream_tree))
    gbp.log.debug("Building upstream tarball with compression '%s -%s'" %
                  (options.comp_type, options.comp_level))
    if not git_archive(repo, cp, output_dir, upstream_tree,
                       options.comp_type,
                       options.comp_level,
                       options.with_submodules):
        raise GbpError("Cannot create upstream tarball at '%s'" % output_dir)
    return upstream_tree

def guess_comp_type(repo, comp_type, cp, tarball_dir):
    """Guess compression type"""

    srcpkg = cp['Source']
    upstream_version = cp['Upstream-Version']

    if comp_type != 'auto':
        comp_type = compressor_aliases.get(comp_type, comp_type)
        if comp_type not in compressor_opts:
            gbp.log.warn("Unknown compression type - guessing.")
            comp_type = 'auto'

    if comp_type == 'auto':
        if not repo.has_pristine_tar_branch():
            if not tarball_dir:
                tarball_dir = '..'
            detected = None
            for comp in compressor_opts.keys():
                if du.DebianPkgPolicy.has_orig(du.orig_file(cp, comp), tarball_dir):
                    if detected is not None:
                        raise GbpError("Multiple orig tarballs found.")
                    detected = comp
            if detected is not None:
                comp_type = detected
            else:
                comp_type = 'gzip'
        else:
            regex = 'pristine-tar .* %s_%s\.orig.tar\.' % (srcpkg, upstream_version)
            commits = repo.grep_log(regex, repo.pristine_tar_branch)
            if commits:
                commit = commits[-1]
                gbp.log.debug("Found pristine-tar commit at '%s'" % commit)
            else:
                commit = repo.pristine_tar_branch
            tarball = repo.get_commit_info(commit)['subject']
            (base_name, archive_fmt, comp_type) = parse_archive_filename(tarball)
            gbp.log.debug("Determined compression type '%s'" % comp_type)
            if not comp_type:
                comp_type = 'gzip'
                gbp.log.warn("Unknown compression type of %s, assuming %s" % (tarball, comp_type))
    return comp_type

def check_tag(options, repo, source):
    """Perform specified consistency checks on git history"""
    tag = repo.version_to_tag(options.packaging_tag, source.changelog.version)
    if (options.tag or options.tag_only) and not options.retag:
        if repo.has_tag(tag):
            raise GbpError("Tag '%s' already exists" % tag)

def get_pbuilder_dist(options, repo, native=False):
    """
    Determin the dist to build for with pbuilder/cowbuilder
    """
    if options.pbuilder_dist == 'DEP14':
        branch = repo.branch
        if not branch:
            raise GbpError("Failed to setup DIST for %s. "
                           "Can't determine current branch." % options.builder)
        else:
            parts = branch.rsplit('/')
            if len(parts) == 2:
                vendor = du.get_vendor().lower()
                suite = parts[1]
                if vendor == parts[0]:
                    dist = '' if suite == 'sid' else suite
                else:
                    dist = '%s_%s' % (parts[0], suite)
            elif len(parts) == 1 and native and branch in ['master', 'sid']:
                dist = ''
            else:
                raise GbpError("DEP14 DIST: Current branch '%s' does not match vendor/suite" % branch)
    else:
        dist = options.pbuilder_dist
    return dist

def setup_pbuilder(options, repo, native):
    """
    Setup environment variables for git-pbuilder

    We return two dictionaries (pbd_env, hook_env) that can be passed
    as environment when running commands

    *pbd_env* is used for the actual build command while *hook_env* is
    passed to all hooks. They both contain the same information but
    *pbd_env* contains the depreated variable names not starting with
    *GBP_*.
    """
    pbd_env = {}

    if options.use_pbuilder or options.use_qemubuilder:
        options.builder = 'git-pbuilder'
        pr_builder = os.getenv("BUILDER") or '(cowbuilder)'
        options.cleaner = '/bin/true'

        dist = get_pbuilder_dist(options, repo, native)
        pbd_env['GBP_PBUILDER_DIST'] = pbd_env['DIST'] = pr_dist = dist
        if options.pbuilder_arch:
            arch = options.pbuilder_arch
            pbd_env['GBP_PBUILDER_ARCH'] = pbd_env['ARCH'] = arch
            pr_arch = ":%s" % arch
        else:
            pr_arch = ""
        if options.use_qemubuilder:
            pbd_env['GBP_PBUILDER_BUILDER'] = pbd_env['BUILDER'] = "qemubuilder"
            pr_builder = pbd_env["GBP_PBUILDER_BUILDER"]
        if not options.pbuilder_autoconf:
            pbd_env['GBP_PBUILDER_AUTOCONF'] = pbd_env['GIT_PBUILDER_AUTOCONF'] = "no"
        if options.pbuilder_options:
            pbd_env['GBP_PBUILDER_OPTIONS'] = pbd_env['GIT_PBUILDER_OPTIONS'] = options.pbuilder_options
        gbp.log.info("Building with %s for %s%s" % (pr_builder, pr_dist, pr_arch))

    hook_env = dict([(k, pbd_env[k]) for k in pbd_env if k.startswith("GBP_")])
    return pbd_env, hook_env

def disable_builder(options):
    """Disable builder (and postbuild hook)"""
    gbp.log.info("Disabling builder and postbuild hook")
    options.builder = ''
    options.postbuild = ''
    options.pbuilder = None
    options.qemubuilder = None

def disable_hooks(options):
    """Disable all hooks (except for builder)"""
    for hook in ['cleaner', 'postexport', 'prebuild', 'postbuild', 'posttag']:
        if getattr(options, hook):
            gbp.log.info("Disabling '%s' hook" % hook)
            setattr(options, hook, '')

def changes_file_suffix(dpkg_args):
    """
    >>> changes_file_suffix(['-A'])
    'all'
    >>> changes_file_suffix(['-S'])
    'source'
    >>> changes_file_suffix([]) == du.get_arch()
    True
    """
    if '-S' in dpkg_args:
        return 'source'
    elif '-A' in dpkg_args:
        return 'all'
    else:
        return os.getenv('ARCH', None) or du.get_arch()

def md(a, b):
    "Merge two dictionaires a and b"
    c = a.copy()
    c.update(b)
    return c

def build_parser(name, prefix=None, git_treeish=None):
    try:
        parser = GbpOptionParserDebian(command=os.path.basename(name),
                                       prefix=prefix, git_treeish=git_treeish)
    except configparser.ParsingError as err:
        gbp.log.err(err)
        return None

    tag_group = GbpOptionGroup(parser, "tag options", "options related to git tag creation")
    branch_group = GbpOptionGroup(parser, "branch options", "branch layout options")
    cmd_group = GbpOptionGroup(parser, "external command options", "how and when to invoke external commands and hooks")
    orig_group = GbpOptionGroup(parser, "orig tarball options", "options related to the creation of the orig tarball")
    export_group = GbpOptionGroup(parser, "export build-tree options", "alternative build tree related options")
    parser.add_option_group(tag_group)
    parser.add_option_group(orig_group)
    parser.add_option_group(branch_group)
    parser.add_option_group(cmd_group)
    parser.add_option_group(export_group)

    parser.add_boolean_config_file_option(option_name = "ignore-new", dest="ignore_new")
    parser.add_boolean_config_file_option(option_name = "ignore-untracked",
                                          dest="ignore_untracked")
    parser.add_option("--git-verbose", action="store_true", dest="verbose", default=False,
                      help="verbose command execution")
    parser.add_config_file_option(option_name="color", dest="color", type='tristate')
    parser.add_config_file_option(option_name="color-scheme",
                                  dest="color_scheme")
    parser.add_config_file_option(option_name="notify", dest="notify", type='tristate')
    parser.add_config_file_option(option_name="tmp-dir", dest="tmp_dir")
    tag_group.add_option("--git-tag", action="store_true", dest="tag", default=False,
                      help="create a tag after a successful build")
    tag_group.add_option("--git-tag-only", action="store_true", dest="tag_only", default=False,
                      help="don't build, only tag and run the posttag hook")
    tag_group.add_option("--git-retag", action="store_true", dest="retag", default=False,
                      help="don't fail if the tag already exists")
    tag_group.add_boolean_config_file_option(option_name="sign-tags", dest="sign_tags")
    tag_group.add_config_file_option(option_name="keyid", dest="keyid")
    tag_group.add_config_file_option(option_name="debian-tag", dest="packaging_tag")
    tag_group.add_config_file_option(option_name="debian-tag-msg", dest="debian_tag_msg")
    tag_group.add_config_file_option(option_name="upstream-tag", dest="upstream_tag")
    orig_group.add_config_file_option(option_name="upstream-tree", dest="upstream_tree")
    orig_group.add_boolean_config_file_option(option_name="pristine-tar", dest="pristine_tar")
    orig_group.add_boolean_config_file_option(option_name="pristine-tar-commit",
                                              dest="pristine_tar_commit")
    orig_group.add_config_file_option(option_name="force-create", dest="force_create",
                      help="force creation of orig tarball", action="store_true")
    orig_group.add_config_file_option(option_name="no-create-orig", dest="no_create_orig",
                      help="don't create orig tarball", action="store_true")
    orig_group.add_config_file_option(option_name="tarball-dir", dest="tarball_dir", type="path",
                      help="location to look for external tarballs")
    orig_group.add_config_file_option(option_name="compression", dest="comp_type",
                      help="Compression type, default is '%(compression)s'")
    orig_group.add_config_file_option(option_name="compression-level", dest="comp_level",
                      help="Compression level, default is '%(compression-level)s'")
    branch_group.add_config_file_option(option_name="upstream-branch", dest="upstream_branch")
    branch_group.add_config_file_option(option_name="debian-branch", dest="packaging_branch")
    branch_group.add_boolean_config_file_option(option_name = "ignore-branch", dest="ignore_branch")
    branch_group.add_boolean_config_file_option(option_name = "submodules", dest="with_submodules")
    cmd_group.add_config_file_option(option_name="builder", dest="builder",
                      help="command to build the Debian package, default is '%(builder)s'")
    cmd_group.add_config_file_option(option_name="cleaner", dest="cleaner",
                      help="command to clean the working copy, default is '%(cleaner)s'")
    cmd_group.add_config_file_option(option_name="prebuild", dest="prebuild",
                      help="hook to run before a build, default is '%(prebuild)s'")
    cmd_group.add_config_file_option(option_name="postexport", dest="postexport",
                      help="hook to run after exporting the source tree, default is '%(postexport)s'")
    cmd_group.add_config_file_option(option_name="postbuild", dest="postbuild",
                      help="hook run after a successful build, default is '%(postbuild)s'")
    cmd_group.add_config_file_option(option_name="posttag", dest="posttag",
                      help="hook run after a successful tag operation, default is '%(posttag)s'")
    cmd_group.add_boolean_config_file_option(option_name="pbuilder", dest="use_pbuilder")
    cmd_group.add_boolean_config_file_option(option_name="qemubuilder", dest="use_qemubuilder")
    cmd_group.add_config_file_option(option_name="dist", dest="pbuilder_dist")
    cmd_group.add_config_file_option(option_name="arch", dest="pbuilder_arch")
    cmd_group.add_boolean_config_file_option(option_name = "pbuilder-autoconf", dest="pbuilder_autoconf")
    cmd_group.add_config_file_option(option_name="pbuilder-options", dest="pbuilder_options")
    cmd_group.add_boolean_config_file_option(option_name="build", dest="build")
    cmd_group.add_boolean_config_file_option(option_name="hooks", dest="hooks")
    export_group.add_config_file_option(option_name="export-dir", dest="export_dir", type="path",
                      help="before building the package export the source into EXPORT_DIR, default is '%(export-dir)s'")
    export_group.add_config_file_option("export", dest="export",
                      help="export treeish object TREEISH, default is '%(export)s'", metavar="TREEISH")
    export_group.add_boolean_config_file_option(option_name="purge", dest="purge")
    export_group.add_option("--git-dont-purge", action="store_true", dest="dont_purge", default=False,
                            help="deprecated, use --git-no-purge instead")
    export_group.add_boolean_config_file_option(option_name="overlay", dest="overlay")
    return parser

def parse_args(argv, prefix, git_treeish=None):
    """Parse config and command line arguments"""
    args = [ arg for arg in argv[1:] if arg.find('--%s' % prefix) == 0 ]
    dpkg_args = [ arg for arg in argv[1:] if arg.find('--%s' % prefix) == -1 ]

    # We handle these although they don't have a --git- prefix
    for arg in [ "--help", "-h", "--version" ]:
        if arg in dpkg_args:
            args.append(arg)

    parser = build_parser(argv[0], prefix=prefix, git_treeish=git_treeish)
    if not parser:
        return None, None, None
    options, args = parser.parse_args(args)

    gbp.log.setup(options.color, options.verbose, options.color_scheme)
    if not options.build:
        disable_builder(options)
        dpkg_args = []
    if not options.hooks:
        disable_hooks(options)
    if options.retag:
        if not options.tag and not options.tag_only:
            gbp.log.err("'--%sretag' needs either '--%stag' or '--%stag-only'" % (prefix, prefix, prefix))
            return None, None, None

    if options.overlay and not options.export_dir:
        gbp.log.err("Overlay must be used with --git-export-dir")
        return None, None, None

    # --git-dont-purge is deprecated:
    if options.dont_purge:
        gbp.log.warning("--git-dont-purge is depreceted, use --git-no-purge instead")
        options.purge = False

    return options, args, dpkg_args

class Hook(RunAtCommand):
    "A hook run during the build"
    def __init__(self, name, *args, **kwargs):
        if 'shell' not in kwargs:
            kwargs['shell'] = True
        RunAtCommand.__init__(self, *args, **kwargs)
        self.run_error = '%s-hook %s' % (name, self.run_error)

def main(argv):
    retval = 0
    prefix = "git-"
    source = None
    branch = None
    hook_env = {}

    gbp.log.initialize()

    options, gbp_args, dpkg_args = parse_args(argv, prefix)

    if not options:
        return 1

    try:
        repo = DebianGitRepository(os.path.curdir)
    except GitRepositoryError:
        gbp.log.err("%s is not a git repository" % (os.path.abspath('.')))
        return 1
    else:
        repo_dir = os.path.abspath(os.path.curdir)

    # Determine tree-ish to be exported
    try:
        tree = write_tree(repo, options)
    except GbpError as err:
        gbp.log.err(err)
        return 1
    # Re-parse config options with using the per-tree config file(s) from the
    # exported tree-ish
    options, gbp_args, builder_args = parse_args(argv, prefix, tree)

    try:
        init_tmpdir(options.tmp_dir, prefix='buildpackage_')

        Command(options.cleaner, shell=True)()
        if not options.ignore_new:
            (ret, out) = repo.is_clean(options.ignore_untracked)
            if not ret:
                gbp.log.err("You have uncommitted changes in your source tree:")
                gbp.log.err(out)
                raise GbpError("Use --git-ignore-new or --git-ignore-untracked "
                               "to ignore.")

        try:
            branch = repo.get_branch()
        except GitRepositoryError:
            # Not being on any branch is o.k. with --git-ignore-branch
            if not options.ignore_branch:
                raise

        if not options.ignore_new and not options.ignore_branch:
            if branch != options.packaging_branch:
                gbp.log.err("You are not on branch '%s' but on '%s'" % (options.packaging_branch, branch))
                raise GbpError("Use --git-ignore-branch to ignore or --git-debian-branch to set the branch name.")

        head = repo.head
        source = source_vfs(repo, options, tree)

        check_tag(options, repo, source)

        if not options.tag_only:
            output_dir = prepare_output_dir(options.export_dir)
            tarball_dir = options.tarball_dir or output_dir

            # Get/build the upstream tarball if necessary. We delay this in
            # case of a postexport hook so the hook gets a chance to modify the
            # sources and create different tarballs (#640382)
            # We don't delay it in general since we want to fail early if the
            # tarball is missing.
            if not source.is_native():
                if options.postexport:
                    gbp.log.info("Postexport hook set, delaying tarball creation")
                else:
                    prepare_upstream_tarball(repo, source.changelog, options, tarball_dir,
                                             output_dir)

            build_env, hook_env = setup_pbuilder(options, repo, source.is_native())

            # Export to another build dir if requested:
            if options.export_dir:
                tmp_dir = os.path.join(output_dir, "%s-tmp" % source.sourcepkg)
                export_source(repo, tree, source, options, tmp_dir, output_dir)

                # Run postexport hook
                if options.postexport:
                    Hook('Postexport', options.postexport,
                         extra_env=md(hook_env,
                                      {'GBP_GIT_DIR': repo.git_dir,
                                       'GBP_TMP_DIR': tmp_dir})
                         )(dir=tmp_dir)

                major = (source.changelog.debian_version if source.is_native()
                         else source.changelog.upstream_version)
                export_dir = os.path.join(output_dir, "%s-%s" % (source.sourcepkg, major))
                gbp.log.info("Moving '%s' to '%s'" % (tmp_dir, export_dir))
                move_old_export(export_dir)
                os.rename(tmp_dir, export_dir)

                # Delayed tarball creation in case a postexport hook is used:
                if not source.is_native() and options.postexport:
                    prepare_upstream_tarball(repo, source.changelog, options, tarball_dir,
                                             output_dir)

            if options.export_dir:
                build_dir = export_dir
            else:
                build_dir = repo_dir

            if options.prebuild:
                Hook('Prebuild', options.prebuild,
                     extra_env=md(hook_env,
                                  {'GBP_GIT_DIR': repo.git_dir,
                                   'GBP_BUILD_DIR': build_dir})
                     )(dir=build_dir)

            # Finally build the package:
            RunAtCommand(options.builder, dpkg_args, shell=True,
                         extra_env=md(build_env,
                                      {'GBP_BUILD_DIR': build_dir})
                         )(dir=build_dir)
            if options.postbuild:
                changes = os.path.abspath("%s/../%s_%s_%s.changes" %
                                          (build_dir,
                                           source.sourcepkg,
                                           source.changelog.noepoch,
                                           changes_file_suffix(dpkg_args)))
                gbp.log.debug("Looking for changes file %s" % changes)
                Hook('Postbuild', options.postbuild,
                     extra_env=md(hook_env,
                                  {'GBP_CHANGES_FILE': changes,
                                   'GBP_BUILD_DIR': build_dir})
                     )()
        if options.tag or options.tag_only:
            tag = repo.version_to_tag(options.packaging_tag, source.changelog.version)
            gbp.log.info("Tagging %s as %s" % (source.changelog.version, tag))
            if options.retag and repo.has_tag(tag):
                repo.delete_tag(tag)
            tag_msg = format_str(options.debian_tag_msg,
                                 dict(pkg=source.sourcepkg,
                                      version=source.changelog.version))
            repo.create_tag(name=tag,
                            msg=tag_msg,
                            sign=options.sign_tags,
                            commit=head,
                            keyid=options.keyid)
            if options.posttag:
                sha = repo.rev_parse("%s^{}" % tag)
                Hook('Posttag', options.posttag,
                     extra_env=md(hook_env,
                                  {'GBP_TAG': tag,
                                   'GBP_BRANCH': branch or '(no branch)',
                                   'GBP_SHA1': sha})
                     )()
    except CommandExecFailed:
        retval = 1
    except (GbpError, GitRepositoryError) as err:
        if str(err):
            gbp.log.err(err)
        retval = 1
    except DebianSourceError as err:
        gbp.log.err(err)
        source = None
        retval = 1
    finally:
        drop_index(repo)
        del_tmpdir()

    if not options.tag_only:
        if options.export_dir and options.purge and not retval:
            RemoveTree(export_dir)()

        if source:
            summary, msg = gbp.notifications.build_msg(source.changelog,
                                                       not retval)
            if not gbp.notifications.notify(summary, msg, options.notify):
                gbp.log.err("Failed to send notification")
                retval = 1

    return retval

if __name__ == '__main__':
    sys.exit(main(sys.argv))

# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:


# This code gets the cities list per state from www.city-data.com
# And store it in data/ state-wise
import time

import requests
import xlsxwriter
from bs4 import BeautifulSoup
import csv
import openpyxl
import os
import glob
import difflib

def get_all_summed(section):
    dollars = 0
    # for all li
    lists = list(section.find_all("li"))
    for li in lists:
        val = li.text
        n = len(val)
        # print(val)

        left_par = 0
        while left_par < n:
            while left_par < n and val[left_par] != "(":
                left_par += 1

            right_par = left_par + 1
            while right_par < n and val[right_par] != ")":
                right_par += 1

            # print("$",dollars,": "+val[left_par + 2: right_par])
            # + 2 for ($

            temp = val[left_par + 2: right_par]
            if temp:
                try:
                    dollars += float(temp)
                except ValueError:
                    print("ValueError: ",temp)
            left_par = right_par + 1
    return dollars

def get_cons_and_use_data(link):
    print(link)
    # link = "https://www.city-data.com/city/Indianapolis-Indiana.html"
    html_text = requests.get(link).text
    soup = BeautifulSoup(html_text, 'html.parser')
    cityDetails = ["N" for _ in consumption_and_use]

    # id = "households-by-units"
    section = soup.find("section", id = "government-finances")
    if(not section):
        return False, cityDetails

    # id = "govFinancesE"
    govFinancesE = section.find("div", id = "govFinancesE")
    if govFinancesE:
        cityDetails[0] = get_all_summed(govFinancesE)

    # id = "govFinancesR"
    govFinancesR = section.find("div", id = "govFinancesR")
    if govFinancesR:
        cityDetails[1] = get_all_summed(govFinancesR)

    # id = "govFinancesD"
    govFinancesD = section.find("div", id = "govFinancesD")
    if govFinancesD:
        cityDetails[2] = get_all_summed(govFinancesD)

    # id = "govFinancesC"
    govFinancesC = section.find("div", id = "govFinancesC")
    if govFinancesC:
        cityDetails[3] = get_all_summed(govFinancesC)

    keys = list(section.find_all("li", class_ ="list-group-item list-group-item-info"))
    # 1+ for
Unemployment by race in 2019

    values = list(section.find_all("li", class_ ="list-group-item"))[1:]
    # negative buffer
    valIndex = 0
    for i in range(len(keys)):
        # print(keys[i].text, " male: ", values[i*2].text, "female: ", values[i*2+1].text)
        detailsList = []
        # for headers
        valIndex += 1
        while valIndex < len(values) and \
                "rate" not in values[valIndex].text.lower():
            detailsList.append(values[valIndex].text)
            valIndex += 1

        for det in detailsList:
            details = det.split("%")
            if "females" in details[1].lower():
                cityDetails[keys[i].text + " females"] = details[0]+"%"
            elif "males" in details[1].lower():
                cityDetails[keys[i].text + " males"] = details[0]+"%"

    # print(link, ": ", cityDetails)
    return True, cityDetails

# def getCitiesMaps(path):
#     citiesMap = {}
#     with open(path, "r") as readObj:
#         csv_reader = csv.reader(readObj)
#         header = next(csv_reader)
#
#         for row in csv_reader:
#             key = row[1]+":"+row[4]+":"+row[2]
#             citiesMap[key] = row
#
#     return [header, citiesMap]

def getAllCitiesMap(housesBaseURL):
    path = os.getcwd()
    excel_files = glob.glob(os.path.join("../data/", "*.xlsx"))
    cityDataCities = {}

    for file in excel_files:
        wrkbk = openpyxl.load_workbook(file)
        sh = wrkbk.active
        fileName = file.split("\\")[-1]
        stateName = " ".join(fileName.split()[:-1]).lower()

        # for testing 12 cities per state
        # for row in sh.iter_rows(min_row=0, min_col=0, max_row=12, max_col=3):
        for row in sh.iter_rows(min_row=0, min_col=0):
            cityName = row[0].value
            href = row[2].value
            if cityName and href:
                cityName = cityName.lower().replace("-", " ")
                cityDataCities[cityName + ":" + stateName] = housesBaseURL + href
                # print(cityName+ ":" + stateName)
    return cityDataCities

if __name__ == '__main__':
    #    income_base = "www.city-data.com/income/income-Andover-Florida.html"
    housesBaseURL = "https://www.city-data.com/city/"

    # As details are per races
    consumption_and_use = ["government_finances_expenditure_per_resident_in_2018($)",
    "government_finances_revenue_per_resident_in_2018($)",
    "government_finances_debt_per_resident_in_2018($)",
    "government_finances_cash_and_securities_per_resident_in_2018($)"
    ]

    exceptionsFor500 = {
        "nashville:tennessee": "nashville davidson:tennessee",
        "lexington:kentucky": "lexington fayette:kentucky",
        "san buenaventura:california": 'san buenaventura (ventura):california'
    }

    # states not present on city-data.com
    exceptionsStates = {"puerto rico", "village of islands"}

    # name of csv output file
    outputFile = open("../output/output.csv", 'w', newline='', encoding='utf-8')
    csvWriter = csv.writer(outputFile)

    def writeCityDetails(row, cityIncomeDetails):
        row.extend(cityIncomeDetails)
        print("Writing details for: ", row[:5], )
        csvWriter.writerow(row)

    # For Manual-review
    toCheck = []
    totalPassed = 0
    totalFailed = 0
    targetFailed = 0
    # generate city-data cities map
    cityDataCities = getAllCitiesMap(housesBaseURL)

    # might be used in findClosestMatch
    cityDataCitiesList = cityDataCities.keys()

    def findClosestMatch(key):
        return difflib.get_close_matches(key, cityDataCitiesList, cutoff=0.8, n=3)

    with open("../final500Cities.csv", "r") as readObj:
        csvReader = csv.reader(readObj)
        headers = next(csvReader)
        baseHeadersLen = len(headers)

        # add new columns
        def addNewColumns():
            headers.extend(consumption_and_use)

        addNewColumns()
        # writing the headers
        csvWriter.writerow(headers)
        # print("headers: ", headers)

        for row in csvReader:
            cityName = row[1].lower().replace("-", " ")
            stateName = row[2].lower()
            key = cityName + ":" + stateName
            cityHouseDetails = {}

            if key in cityDataCities:
                status, cityHouseDetails = get_cons_and_use_data(cityDataCities[key])
                if status:
                    totalPassed += 1
                else:
                    totalFailed += 1
                    toCheck.append([key, cityDataCities[key], cityHouseDetails])
                time.sleep(1)
            elif key in exceptionsFor500:
                status, cityHouseDetails = get_cons_and_use_data(cityDataCities[exceptionsFor500[key]])
                if status:
                    totalPassed += 1
                else:
                    totalFailed += 1
                    toCheck.append([key, cityDataCities[exceptionsFor500[key]], cityHouseDetails])
                time.sleep(1)
            else:
                if stateName not in exceptionsStates:
                    # closestMatchList = findClosestMatch(key)
                    # print("closest match for ", key, " are ", closestMatchList)
                    toCheck.append([key, cityHouseDetails])
                    totalFailed += 1
            writeCityDetails(row, cityHouseDetails)
            # break

    # todo
    # Target cities score (check with 500 cities)

    # print("toCheck ", toCheck)
    print("totalCities= ", len(cityDataCities))
    print("totalPassed= ", totalPassed, " and totalFailed= ", totalFailed)
    print("toCheck: ", toCheck)


#!/usr/bin/env python3

import os

import numpy as np

import knn.kNN as knn

'''
数字识别系统
准备数据阶段
将32*32的二进制图像矩阵转换为一个1*1024的向量
'''
def img2vector(filename):
    #创建一个1*1024的numpy数组
    returnVect=np.zeros((1,1024));
    #读取文件
    with open(filename) as fr:
        for i in range(32):
            lineStr=fr.readline();#读取文本文件中的每一行
            for j in range(32):
                returnVect[0,32*i+j]=int(lineStr[j]);
    return returnVect;
'''
测试算法阶段
'''
def handwritingClassTest():
    #1、准备样本数据
    labelNums=[];#文本对应的数组列表
    #读取样本数据文件
    listdir=os.listdir('trainingDigits')
    m=len(listdir);
    dataset=np.zeros((m,1024))
    for i in range(m):
        currFileStr=listdir[i];
        labelNums.append(currFileStr.split('.')[0].split('_')[0])
        dataset[i,:]=img2vector('trainingDigits/%s'%currFileStr)
    #2、准备测试数据
    testListdir=os.listdir('testDigits')
    errorCount=0.0; #错误次数
    testM=len(testListdir)
    testDataset = np.zeros((testM, 1024))
    for j in range(testM):
        currFileStr = testListdir[j];
        currNum=int(currFileStr.split('.')[0].split('_')[0]);
        testData = img2vector('testDigits/%s' % currFileStr)
        resultNum=int(knn.classify0(testData,dataset,labelNums,3));
        if (resultNum!=currNum):
            errorCount+=1;
        print('预测结果数字为%s,实际数字为%s'%(resultNum,currNum))
    print("预测结束，错误率为：%s"%(errorCount/float(testM)))

if __name__ == '__main__':
    handwritingClassTest();


import socket
import json
import time
from encodeJson import getEncode,getDecode

enc = 'utf-8'

def connect(addr,port):
    clientsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    clientsocket.connect((addr, port))
    return clientsocket

def sendDict(connection,dataDict):
    try:
        data = json.dumps(dataDict).encode('utf-8')
        connection.send(data)
    except Exception as e:
        return e

def sendList(connection,aList):
    aList.append('endofalldata')
    for item in aList:
        #print('Sending',item)
        sendDict(connection,item)
        connection.recv(1024)
        #print('False')

    #sendDict(connection,'endofalldata')

def connectSendList(addr,port,someList):
    try:
        sendList(connect(addr,port),someList)
        return True
    except Exception as e:
        print(str(e))
        return False

def getDataFromServer(addr,port,data):
    conn = connect(addr,port)
    conn.sendall(getEncode(data))
    msg = conn.recv(4096)
    if len(msg) > 0:
        data = getDecode(msg)
        try:
            return data.pop(0)
        except:
            return []

def getBestCompClient(addr,port,details):

    print(getDataFromServer(addr,port,details))

if __name__=='__main__':
    myList = [str(x) for x in range(0,100,2)]
    #conn = connect('localhost',8089)
    #sendList(conn,myList)
    #sendDict(conn,{'Hi':'Bye'})
    #connectSendList('localhost',8089,myList)
    getBestCompClient('localhost',8091,{'fileType':'png','initialSize':500})


import copy

import numpy as np

from collections import defaultdict

from .dataset import Dataset

class KelpieDataset:
    def __init__(self, dataset: Dataset, entity):
        self.dataset = dataset
        self.to_filter = copy.deepcopy(dataset.to_filter)
        self.train_to_filter = copy.deepcopy(dataset.train_to_filter)
        self.entity_to_id = copy.deepcopy(dataset.entity_to_id)
        self.id_to_entity = copy.deepcopy(dataset.id_to_entity)
        self.relation_to_id = copy.deepcopy(dataset.relation_to_id)
        self.id_to_relation = copy.deepcopy(dataset.id_to_relation)

        self.num_entities = dataset.num_entities + 1
        self.num_relations = dataset.num_relations

        self.original_entity = entity
        self.original_entity_label = self.id_to_entity[entity]
        self.kelpie_entity = self.num_entities - 1
        self.kelpie_entity_label = "kelpie_" + self.original_entity_label
        self.entity_to_id[self.kelpie_entity_label] = self.kelpie_entity
        self.id_to_entity[self.kelpie_entity] = self.kelpie_entity_label

        self.kelpie_training_triples = Dataset.replace_entity_in_triples(
            dataset.entity_to_training_triples[self.original_entity],
            self.original_entity,
            self.kelpie_entity,
        )
        self.kelpie_validation_triples = Dataset.replace_entity_in_triples(
            dataset.entity_to_validation_triples[self.original_entity],
            self.original_entity,
            self.kelpie_entity,
        )
        self.kelpie_testing_triples = Dataset.replace_entity_in_triples(
            dataset.entity_to_testing_triples[self.original_entity],
            self.original_entity,
            self.kelpie_entity,
        )
        self.kelpie_training_triples_copy = copy.deepcopy(self.kelpie_training_triples)
        self.kelpie_validation_triples_copy = copy.deepcopy(
            self.kelpie_validation_triples
        )
        self.kelpie_testing_triples_copy = copy.deepcopy(self.kelpie_testing_triples)

        triples_to_stack = [self.kelpie_training_triples]
        if len(self.kelpie_validation_triples) > 0:
            triples_to_stack.append(self.kelpie_validation_triples)
        if len(self.kelpie_testing_triples) > 0:
            triples_to_stack.append(self.kelpie_testing_triples)
        all_kelpie_triples = np.vstack(triples_to_stack)
        for s, p, o in self.kelpie_training_triples:
            self.train_to_filter[(s, p)].append(o)
            self.train_to_filter[(o, p + self.num_relations)].append(s)
        for s, p, o in all_kelpie_triples:
            self.to_filter[(s, p)].append(o)
            self.to_filter[(o, p + self.num_relations)].append(s)

        self.kelpie_triple_to_index = {}
        for i in range(len(self.kelpie_training_triples)):
            s, p, o = self.kelpie_training_triples[i]
            self.kelpie_triple_to_index[(s, p, o)] = i

        self.last_added_triples = []
        self.last_added_triples_number = 0
        self.last_filter_additions = defaultdict(list)
        self.last_added_kelpie_triples = []

        self.last_removed_triples = []
        self.last_removed_triples_number = 0
        self.last_filter_removals = defaultdict(list)
        self.last_removed_kelpie_triples = []

    def as_kelpie_triple(self, original_triple):
        if not self.original_entity in original_triple:
            raise Exception(
                f"Could not find the original entity {str(self.original_entity)} "
                f"in the passed triple {str(original_triple)}"
            )

        return Dataset.replace_entity_in_triple(
            triple=original_triple,
            old_entity=self.original_entity,
            new_entity=self.kelpie_entity,
        )

    def add_training_triples(self, triples_to_add: np.array):
        """
        Add a set of training triples to the training triples of the kelpie entity of this KelpieDataset.
        The triples to add must still feature the original entity id; this method will convert them before addition.
        The KelpieDataset will keep track of the last performed addition so it can be undone if necessary
        calling the undo_last_training_triples_addition method.

        :param triples_to_add: the triples to add, still featuring the id of the original entity,
                               in the form of a numpy array
        """

        for s, _, o in triples_to_add:
            assert self.original_entity == s or self.original_entity == o

        self.last_added_triples = triples_to_add
        self.last_added_triples_number = len(triples_to_add)
        self.last_filter_additions = defaultdict(list)
        self.last_added_kelpie_triples = []

        kelpie_triples_to_add = Dataset.replace_entity_in_triples(
            triples_to_add,
            old_entity=self.original_entity,
            new_entity=self.kelpie_entity,
        )
        for s, rel, o in kelpie_triples_to_add:
            self.to_filter[(s, rel)].append(o)
            self.to_filter[(o, rel + self.num_relations)].append(s)
            self.train_to_filter[(s, rel)].append(o)
            self.train_to_filter[(o, rel + self.num_relations)].append(s)

            self.last_added_kelpie_triples.append((s, rel, o))
            self.last_filter_additions[(s, rel)].append(o)
            self.last_filter_additions[(o, rel + self.num_relations)].append(s)

        self.kelpie_training_triples = np.vstack(
            (self.kelpie_training_triples, np.array(kelpie_triples_to_add))
        )

    def remove_training_triples(self, triples: np.array):
        for s, _, o in triples:
            assert self.original_entity == s or self.original_entity == o

        self.last_removed_triples = triples
        self.last_removed_triples_number = len(triples)
        self.last_filter_removals = defaultdict(list)
        self.last_removed_kelpie_triples = []

        kelpie_triples_to_remove = Dataset.replace_entity_in_triples(
            triples=triples,
            old_entity=self.original_entity,
            new_entity=self.kelpie_entity,
        )

        for s, rel, o in kelpie_triples_to_remove:
            self.to_filter[(s, rel)].remove(o)
            self.to_filter[(o, rel + self.num_relations)].remove(s)
            self.train_to_filter[(s, rel)].remove(o)
            self.train_to_filter[(o, rel + self.num_relations)].remove(s)

            self.last_removed_kelpie_triples.append((s, rel, o))
            self.last_filter_removals[(s, rel)].append(o)
            self.last_filter_removals[(o, rel + self.num_relations)].append(s)

        idxs = [self.kelpie_triple_to_index[x] for x in kelpie_triples_to_remove]
        self.kelpie_training_triples = np.delete(
            self.kelpie_training_triples, idxs, axis=0
        )

    def undo_removal(self):
        """
        This method undoes the last removal performed on this KelpieDataset
        calling its add_training_triples method.

        The purpose of undoing the removals performed on a pre-existing KelpieDataset,
        instead of creating a new KelpieDataset from scratch, is to improve efficiency.
        """
        if self.last_removed_triples_number <= 0:
            raise Exception("No removal to undo.")

        self.kelpie_training_triples = copy.deepcopy(self.kelpie_training_triples_copy)
        for key in self.last_filter_removals:
            for x in self.last_filter_removals[key]:
                self.to_filter[key].append(x)
                self.train_to_filter[key].append(x)

        self.last_removed_triples = []
        self.last_removed_triples_number = 0
        self.last_filter_removals = defaultdict(list)
        self.last_removed_kelpie_triples = []

    def undo_addition(self):
        """
        This method undoes the last addition performed on this KelpieDataset
        calling its add_training_triples method.

        The purpose of undoing the additions performed on a pre-existing KelpieDataset,
        instead of creating a new KelpieDataset from scratch, is to improve efficiency.
        """

        if self.last_added_triples_number <= 0:
            raise Exception("No addition to undo.")

        self.kelpie_training_triples = copy.deepcopy(self.kelpie_training_triples_copy)
        for key in self.last_filter_additions:
            for x in self.last_filter_additions[key]:
                self.to_filter[key].remove(x)
                self.train_to_filter[key].remove(x)

        self.last_added_triples = []
        self.last_added_triples_number = 0
        self.last_filter_additions = defaultdict(lambda: [])
        self.last_added_kelpie_triples = []

    def as_original_triple(self, kelpie_triple):
        if not self.kelpie_entity in kelpie_triple:
            raise Exception(
                f"Could not find the original entity {str(self.kelpie_entity)} "
                f"in the passed triple {str(kelpie_triple)}"
            )
        return Dataset.replace_entity_in_triple(
            triple=kelpie_triple,
            old_entity=self.kelpie_entity,
            new_entity=self.original_entity,
        )

    def invert_triples(self, triples):
        return self.dataset.invert_triples(triples)

    def printable_triple(self, triple):
        return self.dataset.printable_triple(triple)


#practice emotions
import dlib
import cv2
import numpy as np
import os

def detect_face_landmarks(image_path, output_folder):
    # Load the face detector and landmark predictor models from dlib
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor(r"C:\Users\ahj28\Desktop\Python\shape_predictor_68_face_landmarks.dat")  # You need to download this model file

    # Load the image using OpenCV
    image = cv2.imread(image_path)
    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Detect faces in the grayscale image
    faces = detector(gray_image)

    if len(faces) == 0:
        raise ValueError("No face detected in the image.")

    # Assuming there is only one face in the image
    face = faces[0]

    # Predict 68 facial landmarks for the detected face
    landmarks = predictor(gray_image, face)

    # Extract the coordinates of the required points
    left_eye_x, left_eye_y = landmarks.part(36).x, landmarks.part(37).y
    right_eye_x, right_eye_y = landmarks.part(45).x, landmarks.part(46).y
    nose_x, nose_y = landmarks.part(30).x, landmarks.part(30).y

    leftEye_high = max(landmarks.part(38).y,landmarks.part(39).y)
    rightEye_high = max(landmarks.part(44).y,landmarks.part(45).y)
    leftr = landmarks.part(20).y - leftEye_high
    rightr = landmarks.part(25).y - rightEye_high
    leftPoint = [ landmarks.part(19).x , landmarks.part(20).y + leftr//2 ]
    rightPoint = [landmarks.part(24).x, landmarks.part(24).y + rightr//2 ]

    # Calculate the points as specified
    left_cheek_x = left_eye_x
    left_cheek_y = nose_y

    right_cheek_x = right_eye_x
    right_cheek_y = nose_y

    # Draw the points on the image for visualization
    cv2.circle(image, (leftPoint[0], leftPoint[1]), 20, (255, 0, 0), -1)
    cv2.circle(image, (rightPoint[0], rightPoint[1]),20, (0, 0, 0), -1)
    cv2.circle(image, (left_cheek_x, left_cheek_y), 20, (0, 255, 0), -1)
    cv2.circle(image, (right_cheek_x, right_cheek_y), 20, (0, 0, 255), -1)

    # Save the image with points in the output folder
    filename = os.path.basename(image_path)
    output_image_path = os.path.join(output_folder, "marked_" + filename)
    cv2.imwrite(output_image_path, image)

    # Return the points as an array
    return [
        [leftPoint[0], leftPoint[1]],
        [rightPoint[0], rightPoint[1]],
        [left_cheek_x, left_cheek_y],
        [right_cheek_x, right_cheek_y]
    ]

if __name__ == "__main__":
    image_path = r"C:\Users\ahj28\Desktop\Garcia DISC Data\Twins\2697\CroppedRect\002.png"  # Replace with the path to the image you want to process
    output_folder = r"C:\Users\ahj28\Desktop\Garcia DISC Data\Twins\2697"

    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    points = detect_face_landmarks(image_path, output_folder)
    print(points)


import os
import json

from constants import *
from os.path import join
from data.helpers import tokenize
from data.base import DataInstance

def read_split(file_path, type_info, tokenizer):
    with open(file_path, 'r') as f:
        data = json.loads(f.read())

    # Construct data_insts
    data_insts = []
    for raw_inst in data:
        id = raw_inst['orig_id']
        tokens, raw_entities, raw_relations = raw_inst['tokens'], raw_inst['entities'], raw_inst['relations']
        tokenization = tokenize(tokenizer, tokens)
        startchar2token, endchar2token = tokenization['startchar2token'], tokenization['endchar2token']

        # Initialize inst_data
        inst_data = {
            'text': ' '.join(tokens), 'id': id, 'entities':[], 'interactions': []
        }

        # Compute mappings from original tokens to char offsets
        otoken2startchar, otoken2endchar, char_offset = {}, {}, 0
        for ix in range(len(tokens)):
            otoken2startchar[ix] = char_offset
            otoken2endchar[ix] = char_offset + len(tokens[ix])
            char_offset += (1 + len(tokens[ix]))

        # Compute entities
        entities = []
        if len(raw_entities) > 0:
            mid = 0
            for eid, e in enumerate(raw_entities):
                text = ' '.join(tokens[e['start']:e['end']])
                start, end = otoken2startchar[e['start']], otoken2endchar[e['end']-1]
                start_token, end_token = startchar2token[start], endchar2token[end]
                entities.append({
                    'label': ADE_ENTITY_TYPES.index(e['type']),
                    'entity_id': eid, 'mentions': [{
                        'name': text, 'mention_id': mid, 'entity_id': eid,
                        'start_char': start, 'end_char': end,
                        'start_token': start_token, 'end_token': end_token
                    }]
                })
                inst_data['entities'].append({
                    'label': e['type'],
                    'names': {
                        text: {
                            'is_mentioned': True,
                            'mentions': [[start, end]]
                        }
                    },
                    'is_mentioned': True
                })
                mid += 1

        # Compute relations
        relations = []
        if len(raw_relations) > 0:
            for relation in raw_relations:
                p1, p2 = relation['head'], relation['tail']
                label = relation['type']
                relations.append({
                                  'participants': [p1, p2],
                                  'label': ADE_RELATION_TYPES.index(label)
                                })
                inst_data['interactions'].append({
                                  'participants': [p1, p2],
                                  'label': label
                                })

        # Create a new DataInstance
        text = ' '.join(tokens)
        data_insts.append(DataInstance(inst_data, id, text, tokenization, False, entities, relations))

    return data_insts

def load_ade_dataset(base_path, tokenizer, split_nb):
    # Determine absolute file paths
    assert(split_nb in list(range(10)))
    train_fp = join(base_path, 'ade_split_{}_train.json'.format(split_nb))
    test_fp = join(base_path, 'ade_split_{}_test.json'.format(split_nb))
    types_fp = join(base_path, 'ade_types.json')

    # Read types info
    with open(types_fp, 'r') as f:
        type_info = json.loads(f.read())

    # Read splits
    train = read_split(train_fp, type_info, tokenizer)
    dev = read_split(test_fp, type_info, tokenizer)

    return train, dev


# Imports
import sys
import time
import math

from PyQt5.QtWidgets import (QApplication, QPushButton, QToolTip, QWidget, QLabel)
from PyQt5.QtGui import (QPainter, QColor, QIcon, QFont, QPalette, QBrush, QPixmap, QImage)
from PyQt5 import QtCore
from PyQt5.QtCore import (QSize, QTimer)

#############################################################################################
# Calss definition for the drawing grid
#############################################################################################

class CalculatePoints (QWidget):

    def __init__ (self, parent=None):
        super(CalculatePoints, self).__init__(parent)
        self.bufn = 10000
        self.buffer = [[None for x in range(2)] for y in range(self.bufn)]
        self.readPointer = 0
        self.writePointer = 0
        self.currentPosition = [0]*2
        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self.handleTimer)
        self.startTimer()

    def startTimer (self):
        self.timer.start(10)

    def handleTimer (self):
        if (self.buffer[self.readPointer][0] != None):
            posX = self.buffer[self.readPointer][0]
            posY = self.buffer[self.readPointer][1]
            self.buffer[self.readPointer][0] = None
            self.buffer[self.readPointer][1] = None
            if (self.readPointer < (self.bufn - 1)):
                self.readPointer += 1
            else:
                readPointer = 0
        else:
            posX = self.currentPosition[0]
            posY = self.currentPosition[1]
        print (posX, posY)

    def setCurrentPosition (self, posX, posY):
        self.currentPosition[0] = posX
        self.currentPosition[1] = posY

    def writePoint (self, posX, posY):
        while True:
            if (self.buffer[self.writePointer][0] == None):
                self.buffer[self.writePointer][0] = posX
                self.buffer[self.writePointer][1] = posY
                if (self.writePointer < (self.bufn - 1)):
                    self.writePointer += 1
                else:
                    self.writePointer = 0
                break

    def setPoints (self, start, end):
        x1 = start.x()
        y1 = -start.y()
        x2 = end.x()
        y2= -end.y()
        dx = x2 - x1
        dy = y2 - y1
        if (math.fabs(dx) > math.fabs(dy)):
            s = dy/dx
            y = y1
            for x in range(x1,x2):
                self.writePoint(math.ceil(x), math.ceil(y))
                y = y + s
        elif (math.fabs(dx) < math.fabs(dy)):
            s = dx/dy
            x = x1
            if (y1 < y2):
                for y in range(y1,y2):
                    self.writePoint(math.ceil(x), math.ceil(y))
                    x = x + s
            elif (y1 > y2):
                for y in range(y1,y2):
                    self.writePoint(math.ceil(x), math.ceil(y))
                    x = x - s

    def setPath (self, start, path, end):
        self.setPoints(start, path[0])
        for i in range(1,len(path)):
            self.setPoints(path[i], path[i-1])
        self.setPoints(path[len(path)-1], end)

    #def setDirection (self, dir):

#############################################################################################
# Calss definition for the drawing grid
#############################################################################################

class Grid (QPushButton):

    def __init__ (self, parent=None):
        super(Grid, self).__init__(parent)
        self.resize(826,478)
        self.move(856,10)
        self.startCircle = QLabel("", self)
        self.endCircle = QLabel("", self)
        self.pathCircle = []
        self.resetGrid()

    def resetGrid (self):
        self.setStyleSheet("background: transparent; border-image: ;")
        self.initPoints()
        self.removeEventFilter(self)
        self.captureSignal = None
        self.startPoint = None
        self.endPoint = None
        self.pathPoints = []

    def initPoints (self):
        for point in self.pathCircle:
            point.hide()
        del self.pathCircle[:]
        self.startCircle.move(0,0)
        self.endCircle.move(0,0)
        self.startCircle.resize(20,20)
        self.endCircle.resize(20,20)
        self.startCircle.setStyleSheet("border-image: url(startPoint.png);")
        self.endCircle.setStyleSheet("border-image: url(endPoint.png);")
        self.startCircle.hide()
        self.endCircle.hide()

    def moveStartPoint (self, pos):
        self.startCircle.move(pos.x(),pos.y())
        self.startCircle.show()

    def moveEndPoint (self, pos):
        self.endCircle.move(pos.x(),pos.y())
        self.endCircle.show()

    def eventFilter (self, object, event):
        if event.type() == QtCore.QEvent.MouseButtonPress:
            if (self.captureSignal == 0):
                self.startPoint = event.pos()
                self.moveStartPoint(event.pos())
            elif (self.captureSignal == 1):
                self.endPoint = event.pos()
                self.moveEndPoint(event.pos())
            elif (self.captureSignal == 2):
                self.startPoint = event.pos()
                self.moveStartPoint(event.pos())
            return True
        elif event.type() == QtCore.QEvent.MouseMove:
            if (self.captureSignal == 2):
                self.pathPoints.append(event.pos())
                point = QLabel("", self)
                point.move(event.pos().x(),event.pos().y())
                point.resize(5,5)
                point.setStyleSheet("border-image: url(pathPoint.png);")
                point.show()
                self.pathCircle.append(point)
            return True
        elif event.type() == QtCore.QEvent.MouseButtonRelease:
            if (self.captureSignal == 2):
                self.endPoint = event.pos()
                self.moveEndPoint(event.pos())
                self.turnOffGrid()
            return True

        return False;

    def turnOnGrid (self, signal):
        self.captureSignal = signal
        self.installEventFilter(self)
        self.setStyleSheet("background: transparent; border-image: url(grid.png);")

    def turnOffGrid (self):
        self.removeEventFilter(self)
        self.setStyleSheet("background: transparent; border-image: ;")

    def getStartPoint (self):
        return self.startPoint

    def getEndPoint (self):
        return self.endPoint

    def getPathPoints (self):
        return self.pathPoints

#############################################################################################
# Calss definition for the the side buttons
#############################################################################################

class SideButton (QPushButton):

    def __init__ (self, parent=None):
        super(SideButton, self).__init__(parent)
        self.setFont(QFont('Times', 17))
        self.resize(150,115)
        self.resetButton()

    def resetButton (self):
        self.setStyleSheet("border-image: url(sideButtonOff.png); color: white;")
        self.removeEventFilter(self)
        self.captureSignal = None

    def eventFilter (self, object, event):

        if event.type() == QtCore.QEvent.HoverMove:
            self.setStyleSheet("border-image: url(sideButtonHover.png); color: white;")
            return True

        elif event.type() == QtCore.QEvent.HoverLeave:
            self.setStyleSheet("border-image: url(sideButtonOn.png); color: white;")
            return True

        elif event.type() == QtCore.QEvent.MouseButtonPress:
            if object.pos().y() == 40:
                self.handleButton5Press()
            elif object.pos().y() == 190:
                self.handleButton6Press()
            elif object.pos().y() == 340:
                self.handleButton7Press()
            return True

        return False;

    def turnOnButton (self, signal):
        self.captureSignal = signal
        self.setStyleSheet("border-image: url(sideButtonOn.png); color: white;")
        self.installEventFilter(self)

    def turnOffButton (self):
        self.removeEventFilter(self)
        self.setStyleSheet("border-image: url(sideButtonOff.png); color: white;")

    def handleButton5Press (self):
        startPoint = mainWindow.frame3.getStartPoint()
        if (startPoint != None):
            mainWindow.frame3.turnOnGrid(1)
            mainWindow.instr.changeText("Click on the endpoint in the grid and hit the 'Send' button.")
            self.turnOffButton()
            mainWindow.button6.turnOnButton(0)
        else:
            mainWindow.instr.changeText("Please select a startpoint before pressing the 'Fix' button.")

    def handleButton6Press (self):
        if (self.captureSignal == 0):
            endPoint = mainWindow.frame3.getEndPoint()
            if (endPoint != None):
                startPoint = mainWindow.frame3.getStartPoint()
                mainWindow.button7.handleButton7Press()
                mainWindow.sendPoints.setPoints(startPoint, endPoint)
                time.sleep(2)
            else:
                mainWindow.instr.changeText("Please select an endpoint before pressing the 'Send' button.")
        elif (self.captureSignal == 1):
            startPoint = mainWindow.frame3.getStartPoint()
            if (startPoint != None):
                endPoint = mainWindow.frame3.getEndPoint()
                pathPoints = mainWindow.frame3.getPathPoints()
                mainWindow.button7.handleButton7Press()
                mainWindow.sendPoints.setPath(startPoint, pathPoints, endPoint)
                time.sleep(2)
            else:
                mainWindow.instr.changeText("Please enter a path before pressing the 'Send' button.")

    def handleButton7Press (self):
        mainWindow.button1.resetButton()
        mainWindow.button2.resetButton()
        mainWindow.button3.resetButton()
        mainWindow.button4.resetButton()
        mainWindow.button5.resetButton()
        mainWindow.button6.resetButton()
        mainWindow.button7.resetButton()
        mainWindow.frame3.resetGrid()
        mainWindow.instr.changeText("")

#############################################################################################
# Class definition for the manual control button
#############################################################################################

class ManualButton (QPushButton):

    def __init__ (self, parent=None):
        super(ManualButton, self).__init__(parent)
        self.resize(166,160)
        self.resetButton()

    def resetButton (self):
        self.basePoint = {'x': 332, 'y': 750}
        self.move(332,750)
        self.setStyleSheet("border-image: url(manualButtonOff.png);")
        self.removeEventFilter(self)

    def eventFilter (self, object, event):
        if event.type() == QtCore.QEvent.MouseButtonPress:
            return True
        elif event.type() == QtCore.QEvent.MouseMove:
            posX = self.mapToParent(event.pos()).x()
            posY = self.mapToParent(event.pos()).y()
            relX = 415 - posX
            relY = 830 - posY
            dirX = 0
            dirY = 0
            if (math.ceil(math.sqrt(math.pow(relX,2) + math.pow(relY,2))) >= 10):
                # Calculate the position of the button
                if (math.ceil(math.sqrt(math.pow(relX,2) + math.pow(relY,2))) <= 40):
                    self.basePoint['x'] = 332 - relX
                    self.basePoint['y'] = 750 - relY
                else:
                    self.basePoint['x'] = 332 - math.floor(relX/math.sqrt(math.pow(relX,2) + math.pow(relY,2))*40)
                    self.basePoint['y'] = 750 - math.floor(relY/math.sqrt(math.pow(relX,2) + math.pow(relY,2))*40)
                self.move(self.basePoint['x'],self.basePoint['y'])

                # Calculate the direction of motion
                if (relX != 0):
                    angle = math.atan(-relY/relX)*180/math.pi
                    if (relX > 0):
                        angle = angle + 180
                    elif (relY < 0):
                        angle = angle + 360
                    if ((angle <= 67.5) or (angle >= 292.5)):
                        dirX = 1
                    elif ((angle >= 112.5) and (angle <= 247.5)):
                        dirX = -1
                    if ((angle >= 22.5) and (angle <= 157.5)):
                        dirY = 1
                    elif ((angle >= 202.5) and (angle <= 337.5)):
                        dirY = -1
            print (dirX, dirY)
            # Do the control
            # Send the direction
            return True
        elif event.type() == QtCore.QEvent.MouseButtonRelease:
            self.move(332,750)
            return True
        return False;

    def turnOnButton (self):
        self.setStyleSheet("border-image: url(manualButtonOn.png); color: white;")
        self.installEventFilter(self)

    def turnOffButton (self):
        self.removeEventFilter(self)
        self.setStyleSheet("border-image: url(manualButtonOff.png); color: white;")

#############################################################################################
# Class definition for the three main control buttons
#############################################################################################

class ControlButton (QPushButton):

    def __init__ (self, parent=None):
        super(ControlButton, self).__init__(parent)
        self.setFont(QFont('Times', 17))
        self.resize(150,115)
        self.resetButton()

    def resetButton (self):
        self.setStyleSheet("border-image: url(controlButton.png); color: white;")
        self.installEventFilter(self)

    def eventFilter (self, object, event):

        if event.type() == QtCore.QEvent.HoverMove:
            self.setStyleSheet("border-image: url(controlButtonHover.png); color: white;")
            return True

        elif event.type() == QtCore.QEvent.HoverLeave:
            self.setStyleSheet("border-image: url(controlButton.png); color: white;")
            return True

        elif event.type() == QtCore.QEvent.MouseButtonPress:
            self.setStyleSheet("border-image: url(controlButtonClicked.png); color: white;")
            if object.pos().x() == 143:
                self.handleButton1Press()
            elif object.pos().x() == 343:
                self.handleButton2Press()
            elif object.pos().x() == 543:
                self.handleButton3Press()
            return True

        return False;

    def turnOnButton (self):
        self.setStyleSheet("border-image: url(controlButton.png); color: white;")
        self.installEventFilter(self)

    def turnOffButton (self):
        self.removeEventFilter(self)
        self.setStyleSheet("border-image: url(sideButtonOff.png); color: white;")

    def handleButton1Press (self):
        self.removeEventFilter(self)
        mainWindow.button2.turnOffButton()
        mainWindow.button3.turnOffButton()
        mainWindow.button5.turnOnButton(2)
        mainWindow.button7.turnOnButton(2)
        mainWindow.frame3.turnOnGrid(0)
        mainWindow.instr.changeText("Click on the startpoint in the grid and hit the 'Fix' button.")

    def handleButton2Press (self):
        self.removeEventFilter(self)
        mainWindow.button1.turnOffButton()
        mainWindow.button3.turnOffButton()
        mainWindow.button6.turnOnButton(1)
        mainWindow.button7.turnOnButton(2)
        mainWindow.frame3.turnOnGrid(2)
        mainWindow.instr.changeText("Draw the path of the grid and hit the 'Send' button.")

    def handleButton3Press (self):
        self.removeEventFilter(self)
        mainWindow.button1.turnOffButton()
        mainWindow.button2.turnOffButton()
        mainWindow.button4.turnOnButton()
        mainWindow.button7.turnOnButton(2)
        mainWindow.instr.changeText("Press, hold and drag the blue button below for manual control. Release the button to stop.")

#############################################################################################
# Class definition for the instructions panel
#############################################################################################

class InstrPanel (QLabel):
    def __init__(self,parent=None):
        super(InstrPanel, self).__init__(parent)
        self.setWordWrap(True)
        self.setFont(QFont('Courier', 15))
        self.setStyleSheet("background: transparent; color: white;")
        self.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
        self.resize(683,136)
        self.move(82,501)
        self.text = ''
        self.index = 0
        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self.handleTimer)

    def changeText(self, text):
        self.text = text
        self.index = 0
        self.timer.start(18)

    def handleTimer(self):
        self.index += 1
        self.setText(self.text[:self.index])
        if self.index > len(self.text):
            self.timer.stop()

#############################################################################################
# Class definition for the main window
#############################################################################################

class Window (QWidget):

    def __init__ (self):
        super().__init__()
        self.initUX()

    def initUX (self):

        QToolTip.setFont(QFont('Times', 14))

        # Set window size, title and icon
        self.setWindowState(QtCore.Qt.WindowMaximized)
        self.setWindowTitle('TARDIS UI')
        self.setWindowIcon(QIcon('rover.png'))

        # Set main window's background
        bgImage = QImage("mainWindow.png")
        bgImage = bgImage.scaled(QSize(1919, 986))
        palette	= QPalette()
        palette.setBrush(QPalette.Background,QBrush(bgImage))
        self.setPalette(palette)

        # Initialize the Instruction Panel
        self.initTextFrames()

        # Initialize all buttons
        self.initButtons()

        # Initialize video frames
        self.initFrames()

        # Start the timer to send points
        self.sendPoints = CalculatePoints(self)

        # Display the window
        self.show()

    def initTextFrames (self):
        self.instr = InstrPanel(self)

        self.tempHead = QLabel("<b>On-Site Temperature:</b>", self)
        self.tempHead.setWordWrap(True)
        self.tempHead.setFont(QFont('Courier', 12))
        self.tempHead.setStyleSheet("background: transparent; color: white;")
        self.tempHead.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
        self.tempHead.resize(170,60)
        self.tempHead.move(1740,501)

        self.temp = QLabel("", self)
        self.temp.setWordWrap(True)
        self.temp.setFont(QFont('Courier', 32))
        self.temp.setStyleSheet("background: transparent; color: white;")
        self.temp.setText("25°C")
        self.temp.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
        self.temp.resize(170,80)
        self.temp.move(1740,570)

    def initButtons (self):
        # Set "Enter Points" button
        self.button1 = ControlButton(self)
        self.button1.setText('Enter\nPoints')
        self.button1.move(143,277)

        # Set "Draw Path" button
        self.button2 = ControlButton(self)
        self.button2.setText('Draw\nPath')
        self.button2.move(343,277)

        # Set "Manual Control" button
        self.button3 = ControlButton(self)
        self.button3.setText('Manual\nControl')
        self.button3.move(543,277)

        # Set "Round Manual Control" button
        self.button4 = ManualButton(self)

        # Set "Fix" button
        self.button5 = SideButton(self)
        self.button5.setText('Fix')
        self.button5.move(1740,40)

        # Set "Send" button
        self.button6 = SideButton(self)
        self.button6.setText('Send')
        self.button6.move(1740,190)

        # Set "Cancel" button
        self.button7 = SideButton(self)
        self.button7.setText('Cancel')
        self.button7.move(1740,340)

    def initFrames (self):
        # Set "Overhead Camera" video frame
        self.frame1 = QLabel("", self)
        self.frame1.setStyleSheet("background: grey;")
        self.frame1.resize(826,478)
        self.frame1.move(856,10)

        # Set "Onboard Camera" video frame
        self.frame2 = QLabel("", self)
        self.frame2.setStyleSheet("background: grey;")
        self.frame2.resize(826,478)
        self.frame2.move(856,498)

        # Frame for the grid superimposed on the overhead footage
        self.frame3 = Grid(self)

#############################################################################################
# Main function initialization
#############################################################################################

if __name__ == '__main__':

    # Initialize the application
    mainApp = QApplication(sys.argv)

    # Initialize the main window object
    mainWindow = Window()

    # Exit command
    sys.exit(mainApp.exec_())