import numpy as np, random, math, time
from scipy.stats import norm
import matplotlib

class Settings():
    def __init__(self):
        self.min_dist = 100
        self.initial_num = 150
        self.tick_time = 0 #time between updates during run mode

        #Max initial energy is 723
        self.efficiency_stdev = 10 #50 is less selective, 10 is very selective, 20 is less shocking
        self.area_energy_cost = 30
        self.height_growth_cost = 300
        self.area_growth_cost = 20
        self.seed_cost = 100

        #mutation_rate out of 1
        self.mutation_rate = 0.3

        self.max_age = 20
        self.leaf_obscurity = 0.8

        self.x_size = 300
        self.y_size = 300

        #initial light grids
        self.understory_light = np.full((self.x_size,self.y_size), 100)
        self.floor_light = np.full((self.x_size, self.y_size), 100)

        #initial
        # self.ph_board = np.full((self.x_size, self.y_size),50)
        ph_row = [np.concatenate([np.full((int(self.x_size / 2), 1),25), np.full((int(self.x_size / 2), 1), 75)])]
        self.ph_board = ph_row
        for _ in range(self.y_size-1):
            self.ph_board = np.append(self.ph_board, ph_row, axis = 0)

    def update_light_boards(self, plant_list):
        '''updates light boards on the floor and understory.
        At the same time, calculates plants energy'''
        new_understory_light = np.full((self.x_size,self.y_size), 100)
        new_floor_light = np.full((self.x_size, self.y_size), 100)

        for plant in plant_list:
            new_energy = 100 * np.pi * (plant.radius_canopy)

            #Checks through squares on all levels to see if it the squares lie within its radius adds to the energy the brightness of the light at that level
            largest_radius = max(plant.radius_understory, plant.radius_floor, plant.radius_canopy)
            for boxx in range(plant.x_pos-largest_radius, plant.x_pos + largest_radius):
                for boxy in range(plant.y_pos -largest_radius, plant.y_pos + largest_radius):
                    if boxx >= 0 and boxy >=0 and boxy < self.y_size and boxx < self.x_size:
                        distance = (plant.x_pos - boxx)**2 + (plant.y_pos - boxy)**2

                        if distance <= plant.radius_canopy ** 2 and plant.radius_canopy != 0:
                            new_understory_light[boxy, boxx] = new_understory_light[boxy, boxx] * (1-self.leaf_obscurity)
                            new_floor_light[boxy, boxx] = new_floor_light[boxy, boxx] * (1-self.leaf_obscurity)

                        if distance <= plant.radius_understory ** 2 and plant.radius_understory != 0:
                            new_floor_light[boxy, boxx] = new_floor_light[boxy, boxx] * (1-self.leaf_obscurity)
                            new_energy += self.understory_light[boxy, boxx]

                        if distance <= plant.radius_floor ** 2 and plant.radius_floor != 0:
                            new_energy += self.floor_light[boxy, boxx]

            required_sustenance = np.pi * (plant.radius_floor**2 + plant.radius_understory**2 + plant.radius_canopy**2) * self.area_energy_cost

            #Calculates plant energy with pdf centered at the
            plant.energy = new_energy * (norm.pdf(self.ph_board[plant.y_pos, plant.x_pos], plant.soil_ph, self.efficiency_stdev)/norm.pdf(plant.soil_ph, plant.soil_ph, self.efficiency_stdev)) - required_sustenance

        self.understory_light = new_understory_light
        self.floor_light = new_floor_light

    def next_year(self, plant_list):
        '''Runs the simulation for one year. Updates boards etc'''

        self.update_light_boards(plant_list)
        male_list = []
        female_list = []

        #Loop through all plants
        for plant in plant_list:
            if plant.age == self.max_age or plant.energy < 0 : #kill all plants which do not reach a minimum energy input
                plant_list.remove(plant) #kill all plants above max_age
            else:
                plant.age += 1 #age all plants

                #Grows height and radius if not maximized
                if plant.height <= plant.growth_height and plant.energy > self.height_growth_cost:

                    plant.height += 1
                    plant.energy -= self.height_growth_cost

                #test interaction by looping through all distances
                can_grow_floor, can_grow_understory, can_grow_canopy = plant.check_can_grow(plant_list) #
                #grow all plants which have the energy to do so, have not reached their growth limit and do not interact with other trees
                if plant.height == 3 and plant.radius_canopy < plant.max_rad_can and can_grow_canopy and plant.energy > np.pi * (2 * plant.radius_canopy + 1) * self.area_growth_cost:
                    plant.radius_canopy += 1
                    plant.energy -= np.pi * (2 * plant.radius_canopy + 1) * self.area_growth_cost #area_growth_cost times the change in area of the canopy

                if plant.height >= 2 and plant.radius_understory < plant.max_rad_und and can_grow_understory and plant.energy > np.pi * (2 * plant.radius_understory + 1) * self.area_growth_cost:
                    plant.radius_understory += 1
                    plant.energy -= np.pi * (2 * plant.radius_understory + 1) * self.area_growth_cost

                if plant.radius_floor < plant.max_rad_flo and can_grow_floor and plant.energy > np.pi * (2 * plant.radius_understory + 1) * self.area_growth_cost:
                    plant.radius_floor += 1
                    plant.energy -= np.pi * (2 * plant.radius_floor + 1) * self.area_growth_cost

                if plant.gender:#adds to male or female plant lists
                    for _ in range(int(min(plant.seed_production, plant.energy//self.seed_cost))):
                        male_list.append(plant)
                else:
                    female_list.append(plant)

        random.shuffle(male_list)

        for seed in male_list:
            if len(plant_list) < self.y_size * self.x_size:
                random.shuffle(female_list)
                for female in female_list:
                    if seed.check_viable_mate(self.min_dist, female):
                        not_chosen = True
                        #generates random x,y variable which is not yet taken up
                        while not_chosen:
                            new_x = random.randint(0, self.x_size -1)
                            new_y = random.randint(0, self.y_size -1)
                            if (new_y,new_x) not in plant_list:
                                not_chosen = False
                        plant_list.append(create_seed(seed, female, new_x, new_y, self.mutation_rate))
                        break
            else:
                break
        return(plant_list)

class Plant:
    def __init__(self, soil_ph, seed_production, growth_height, max_rad_flo, max_rad_und, max_rad_can, gender:bool, x_pos = None , y_pos = None):

        #Genetic Information
        self.soil_ph = soil_ph
        self.seed_production = seed_production
        self.growth_height = growth_height
        self.max_rad_flo = max_rad_flo
        self.max_rad_und = max_rad_und
        self.max_rad_can = max_rad_can
        self.gender = gender # True is Male, False is Female

        #Plant information
        self.height = 1
        self.radius_canopy = 0
        self.radius_understory = 0
        self.radius_floor = 2
        self.x_pos = x_pos
        self.y_pos = y_pos
        self.age = 0
        self.display_color = (0, min(255, math.floor(255/100 * self.soil_ph)), 0)
        self.energy = None

    def __eq__(self, coords):
        '''returns true if tuple is equal to x,y coordinates'''

        if isinstance(coords, tuple):
            if coords[0] == self.y_pos and coords[1] == self.x_pos:
                return True
            return False
        if coords.y_pos == self.y_pos and coords.x_pos == self.x_pos:
            return True
        return False

    def check_viable_mate(self, min_dist, mate):
        '''Returns whether two plants can mate(are of the same species)'''
        dist_to_mate = (self.soil_ph - mate.soil_ph)**2 + ((self.growth_height - mate.growth_height)*100/3)**2 + (self.seed_production - mate.seed_production)**2
        if dist_to_mate <= min_dist:
            return True
        return False

    def check_can_grow(self, plant_list):
        '''Outputs a tuple of booleans determining whether the plant has space to grow'''
        can_grow_floor = True
        can_grow_understory = True
        can_grow_canopy = True

        for p in plant_list:
            if not self.__eq__(p):
                distance = ((p.x_pos - self.x_pos)**2 + (p.y_pos - self.y_pos)**2)**0.5

                if can_grow_floor:
                    can_grow_floor = (distance - p.radius_floor) > (self.radius_floor + 1) or distance < self.radius_floor

                if can_grow_understory and self.height >= 2 and p.height >= 2:
                    can_grow_understory = (distance - p.radius_understory) > (self.radius_understory + 1) or distance < self.radius_understory

                if can_grow_canopy == True and self.height == 3 and p.height == 3:
                    can_grow_canopy = (distance - p.radius_canopy) > (self.radius_canopy + 1) or distance < self.radius_canopy

        return(can_grow_floor, can_grow_understory, can_grow_canopy)

def create_seed(parent1, parent2, x, y, mutation_rate):
    '''Creates a new seed in the plant class.
    All of the seeds variables are selected using a normal distribution where the average of the
    parents variables is the mean and the mutation_rate is the standard deviation
    '''

    seed_soil_ph = np.random.normal((parent1.soil_ph + parent2.soil_ph)/2, mutation_rate * 20)
    if seed_soil_ph < 0:
        seed_soil_ph = 0

    seed_seed_production = math.ceil(np.random.normal((parent1.seed_production + parent2.seed_production)/2, mutation_rate * 10))
    if seed_seed_production < 0:
        seed_seed_production = 0

    seed_growth_height = random.choice([random.choice([parent1.growth_height, parent2.growth_height]),random.randint(1,3)]) # 4/9 times

    seed_rad_flo = math.ceil(np.random.normal((parent1.max_rad_flo + parent2.max_rad_flo)/2, mutation_rate * 10))
    if seed_rad_flo <1:
        seed_rad_flo = 1

    seed_rad_und = math.ceil(np.random.normal((parent1.max_rad_und + parent2.max_rad_und)/2, mutation_rate * 10))
    if seed_rad_und <1:
        seed_rad_und = 1

    seed_rad_can = math.ceil(np.random.normal((parent1.max_rad_can + parent2.max_rad_can)/2, mutation_rate * 10))
    if seed_rad_can <1:
        seed_rad_can = 1

    seed = Plant(seed_soil_ph, seed_seed_production, seed_growth_height, seed_rad_flo, seed_rad_und, seed_rad_can, bool(random.getrandbits(1)), x, y)
    return seed

def initiate_plants(num_plants: int, y_size: int, x_size):
    x_list = np.random.choice(range(x_size), num_plants, replace= False).tolist()
    y_list = np.random.choice(range(y_size), num_plants, replace= False).tolist()
    plant_list = []

    for _ in range(num_plants):

        soil_ph = random.uniform(1,100)
        growth_height = random.randint(1,3)
        seed_production = random.randint(1, 5)

        #need to finish
        rad_flo = random.randint(1, 30)
        rad_und = random.randint(1, 30)
        rad_can = random.randint(1, 30)
        x = x_list.pop()
        y = y_list.pop()

        plant_list.append(Plant(soil_ph, seed_production, growth_height, rad_flo, rad_und, rad_can, bool(random.getrandbits(1)),x, y))

    return plant_list


"""
Задача 2. Я стал новым пиратом!
Что нужно сделать

Старому капитану необходимо пополнить команду. Но попадут на его корабль только достойные!
Он отобрал 10 человек и те, кто из них крикнет слово “Карамба”, попадут на борт.
Пользователь вводит 10 слов. Напишите программу, которая определяет, сколько из них совпадают со словом «Карамба».
"""

score = 0
for _ in range(10):
    word = input('Какое слово скажет пират: ')
    if word == 'Карамба' or word == 'карамба':
        score += 1
        print('Ты принят в команду!')
print('В команду набрали', score, 'пиратов!')

Модуль 9/Домашнее задание/task 2.py


import logging
import numpy as np
import unittest
from unittest import mock

from detectron2.config import get_cfg
from detectron2.data import detection_utils
from detectron2.data import transforms as T
from detectron2.utils.logger import setup_logger

logger = logging.getLogger(__name__)

class TestTransforms(unittest.TestCase):
    def setUp(self):
        setup_logger()

    def test_apply_rotated_boxes(self):
        np.random.seed(125)
        cfg = get_cfg()
        is_train = True
        augs = detection_utils.build_augmentation(cfg, is_train)
        image = np.random.rand(200, 300)
        image, transforms = T.apply_augmentations(augs, image)
        image_shape = image.shape[:2]  # h, w
        assert image_shape == (800, 1200)
        annotation = {"bbox": [179, 97, 62, 40, -56]}

        boxes = np.array([annotation["bbox"]], dtype=np.float64)  # boxes.shape = (1, 5)
        transformed_bbox = transforms.apply_rotated_box(boxes)[0]

        expected_bbox = np.array([484, 388, 248, 160, 56], dtype=np.float64)
        err_msg = "transformed_bbox = {}, expected {}".format(transformed_bbox, expected_bbox)
        assert np.allclose(transformed_bbox, expected_bbox), err_msg

    def test_apply_rotated_boxes_unequal_scaling_factor(self):
        np.random.seed(125)
        h, w = 400, 200
        newh, neww = 800, 800
        image = np.random.rand(h, w)
        augs = []
        augs.append(T.Resize(shape=(newh, neww)))
        image, transforms = T.apply_augmentations(augs, image)
        image_shape = image.shape[:2]  # h, w
        assert image_shape == (newh, neww)

        boxes = np.array(
            [
                [150, 100, 40, 20, 0],
                [150, 100, 40, 20, 30],
                [150, 100, 40, 20, 90],
                [150, 100, 40, 20, -90],
            ],
            dtype=np.float64,
        )
        transformed_boxes = transforms.apply_rotated_box(boxes)

        expected_bboxes = np.array(
            [
                [600, 200, 160, 40, 0],
                [600, 200, 144.22205102, 52.91502622, 49.10660535],
                [600, 200, 80, 80, 90],
                [600, 200, 80, 80, -90],
            ],
            dtype=np.float64,
        )
        err_msg = "transformed_boxes = {}, expected {}".format(transformed_boxes, expected_bboxes)
        assert np.allclose(transformed_boxes, expected_bboxes), err_msg

    def test_print_augmentation(self):
        t = T.RandomCrop("relative", (100, 100))
        self.assertTrue(str(t) == "RandomCrop(crop_type='relative', crop_size=(100, 100))")

        t = T.RandomFlip(prob=0.5)
        self.assertTrue(str(t) == "RandomFlip(prob=0.5)")

        t = T.RandomFlip()
        self.assertTrue(str(t) == "RandomFlip()")

    def test_random_apply_prob_out_of_range_check(self):
        test_probabilities = {0.0: True, 0.5: True, 1.0: True, -0.01: False, 1.01: False}

        for given_probability, is_valid in test_probabilities.items():
            if not is_valid:
                self.assertRaises(AssertionError, T.RandomApply, None, prob=given_probability)
            else:
                T.RandomApply(T.NoOpTransform(), prob=given_probability)

    def test_random_apply_wrapping_aug_probability_occured_evaluation(self):
        transform_mock = mock.MagicMock(name="MockTransform", spec=T.Augmentation)
        image_mock = mock.MagicMock(name="MockImage")
        random_apply = T.RandomApply(transform_mock, prob=0.001)

        with mock.patch.object(random_apply, "_rand_range", return_value=0.0001):
            transform = random_apply.get_transform(image_mock)
        transform_mock.get_transform.assert_called_once_with(image_mock)
        self.assertIsNot(transform, transform_mock)

    def test_random_apply_wrapping_std_transform_probability_occured_evaluation(self):
        transform_mock = mock.MagicMock(name="MockTransform", spec=T.Transform)
        image_mock = mock.MagicMock(name="MockImage")
        random_apply = T.RandomApply(transform_mock, prob=0.001)

        with mock.patch.object(random_apply, "_rand_range", return_value=0.0001):
            transform = random_apply.get_transform(image_mock)
        self.assertIs(transform, transform_mock)

    def test_random_apply_probability_not_occured_evaluation(self):
        transform_mock = mock.MagicMock(name="MockTransform", spec=T.Augmentation)
        image_mock = mock.MagicMock(name="MockImage")
        random_apply = T.RandomApply(transform_mock, prob=0.001)

        with mock.patch.object(random_apply, "_rand_range", return_value=0.9):
            transform = random_apply.get_transform(image_mock)
        transform_mock.get_transform.assert_not_called()
        self.assertIsInstance(transform, T.NoOpTransform)

    def test_augmentation_input_args(self):
        input_shape = (100, 100)
        output_shape = (50, 50)

        # define two augmentations with different args
        class TG1(T.Augmentation):
            input_args = ("image", "sem_seg")

            def get_transform(self, image, sem_seg):
                return T.ResizeTransform(
                    input_shape[0], input_shape[1], output_shape[0], output_shape[1]
                )

        class TG2(T.Augmentation):
            def get_transform(self, image):
                assert image.shape[:2] == output_shape  # check that TG1 is applied
                return T.HFlipTransform(output_shape[1])

        image = np.random.rand(*input_shape).astype("float32")
        sem_seg = (np.random.rand(*input_shape) < 0.5).astype("uint8")
        inputs = T.StandardAugInput(image, sem_seg=sem_seg)  # provide two args
        tfms = inputs.apply_augmentations([TG1(), TG2()])
        self.assertIsInstance(tfms[0], T.ResizeTransform)
        self.assertIsInstance(tfms[1], T.HFlipTransform)
        self.assertTrue(inputs.image.shape[:2] == output_shape)
        self.assertTrue(inputs.sem_seg.shape[:2] == output_shape)

        class TG3(T.Augmentation):
            input_args = ("image", "nonexist")

            def get_transform(self, image, nonexist):
                pass

        with self.assertRaises(AttributeError):
            inputs.apply_augmentations([TG3()])


import discord
from discord.ext import commands

import asyncio
import random
import youtube_dl

from collections import deque

import re
from bs4 import BeautifulSoup

import functools

ANILIST_API = 'https://graphql.anilist.co'
ANILIST_QUERY = '''query GetAnimeList($name: String) {MediaListCollection(userName: $name, type: ANIME) {
    lists {
        entries{
            media{
                idMal
                seasonYear
                title {
                    romaji
                    english
                }
                synonyms
                coverImage {
                    extraLarge
                }
            }
        }
    }
}}'''

wiki = "https://www.reddit.com/r/AnimeThemes/wiki/"

ytdl_format_options = {
    'format': 'bestaudio/best',
    'outtmpl': '%(extractor)s-%(id)s-%(title)s.%(ext)s',
    'restrictfilenames': True,
    'noplaylist': True,
    'nocheckcertificate': True,
    'ignoreerrors': False,
    'logtostderr': False,
    'quiet': True,
    'no_warnings': True,
    'default_search': 'auto',
    'source_address': '0.0.0.0' # bind to ipv4 since ipv6 addresses cause issues sometimes
}

ffmpeg_options = {
    'options': '-vn',
    'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5'
}

ytdl = youtube_dl.YoutubeDL(ytdl_format_options)

class YTDLError(Exception):
    pass

class YTDLSource(discord.PCMVolumeTransformer):
    def __init__(self, source, *, data, volume=0.5):
        super().__init__(source, volume)

        self.data = data

        self.title = data.get('title')
        self.url = data.get('url')

    @classmethod
    async def create_source(cls, search: str, loop: asyncio.BaseEventLoop = None, stream=False):
        loop = loop or asyncio.get_event_loop()

        partial = functools.partial(ytdl.extract_info, search, download=False, process=False)
        data = await loop.run_in_executor(None, partial)

        if data is None:
            raise YTDLError('Couldn\'t find anything that matches `{}`'.format(search))

        if 'entries' not in data:
            process_info = data
        else:
            process_info = None
            for entry in data['entries']:
                if entry:
                    process_info = entry
                    break

            if process_info is None:
                raise YTDLError('Couldn\'t find anything that matches `{}`'.format(search))

        webpage_url = process_info['webpage_url']
        partial = functools.partial(ytdl.extract_info, webpage_url, download=False)
        processed_info = await loop.run_in_executor(None, partial)

        if processed_info is None:
            raise YTDLError('Couldn\'t fetch `{}`'.format(webpage_url))

        if 'entries' not in processed_info:
            info = processed_info
        else:
            info = None
            while info is None:
                try:
                    info = processed_info['entries'].pop(0)
                except IndexError:
                    raise YTDLError('Couldn\'t retrieve any matches for `{}`'.format(webpage_url))

        return cls(discord.FFmpegPCMAudio(info['url'], **ffmpeg_options), data=info)

class WeebGame():
    def __init__(self, guild_id):
        self.guild_id = guild_id

        self.lists = {}
        self.length = 0

        self.scores = {}
        self.players = {}
        self.total = 0
        self.rounds = 0

    def get_length(self):
        total = set()
        for i in self.lists:
            ids = [anime["media"]["idMal"] for anime in self.lists[i]]
            total.update(ids)
        return len(total)

    def add_list(self, name, data):
        self.lists[name] = data
        self.length = self.get_length()
        return self.current_lists()

    def remove_list(self, name):
        if not name in self.lists:
            raise Exception()
        del self.lists[name]
        return self.current_lists()

    def current_lists(self):
        current_lists = list(self.lists.keys())
        if len(current_lists) == 0:
            current_lists = ["empty :("]
        embed = discord.Embed(
            title = "Anime Music Game - Current Lists",
            description = "\n".join(current_lists),
            color = 0xe475ea
        )
        return embed

    def random_anime(self):
        anime_list = random.choice(list(self.lists.values()))
        anime = random.choice(anime_list)["media"]
        idMal = anime["idMal"]
        year = anime["seasonYear"]
        cover = anime["coverImage"]["extraLarge"]
        name = anime["title"]["romaji"]
        english = anime["title"]["english"]
        synonyms = anime["synonyms"]
        synonyms.append(english)

        print(name, year, synonyms)

        return anime, idMal, year, cover, name, synonyms

    def score_string(self):
        combined = [(self.scores[i], self.players[i].display_name) for i in self.scores]
        ordered = list(reversed(sorted(combined)))
        formatted = [f"**{i[1]}** has {i[0]} points" for i in ordered]
        joined = "\n".join(formatted)

        if len(joined) == 0:
            return "none :("
        return joined

    def increment_score(self, user : discord.Member, name, title, thumbnail):
        if not user.id in self.scores:
            self.scores[user.id] = 0
            self.players[user.id] = user

        self.scores[user.id] += 5

        self.total += 1
        self.rounds += 1

        player = self.players[user.id]

        # make an embed
        embed = discord.Embed(
            title = "Anime Music Game",
            description = f'That was __{title}__ from *{name}*',
            color = player.color
        )
        embed.set_thumbnail(url = thumbnail)
        embed.set_author(name = f"{player.display_name} guessed it!", icon_url = player.avatar_url)
        embed.add_field(name = "Scores", value = self.score_string())
        return embed

    def failure(self, name, title, thumbnail):
        self.rounds += 1
        embed = discord.Embed(
            title = "Anime Music Game",
            description = f'That was __{title}__ from *{name}*',
            color = 0xcc0000
        )
        embed.set_thumbnail(url = thumbnail)
        embed.set_author(name = "no one got it this round :(")
        embed.add_field(name = "Scores", value = self.score_string())
        return embed

    def end_embed(self):
        embed = discord.Embed(
            title = "Anime Music Game",
            description = (f'That was {5*self.total} points across {self.rounds} rounds ' +
                            '({:.2f}% accuracy)'.format(100*self.total/self.rounds)),
            color = 0x98d685
        )
        embed.add_field(name = "Scores", value = self.score_string())
        return embed

    def listen_embed(self, name, title, thumbnail):
        embed = discord.Embed(
            title = "Anime Music",
            description = f'This is __{title}__ from *{name}*',
            color = 0xc0c0c0
        )
        embed.set_image(url = thumbnail)
        return embed

class WeebMusic(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.wiki_cache = {}
        self.games = {}
        self.pasts = [deque(), set()]

    async def random_title(self, idMal, year, name):
        # scrape reddit
        if year == None:
            raise Exception()

        if year < 2000:
            year = str(year)[2] + "0s"

        if not year in self.wiki_cache:
            async with self.bot.session.get(wiki + str(year)) as resp:
                soup = BeautifulSoup(await resp.text(), "html.parser")
            self.wiki_cache[year] = soup

        soup = self.wiki_cache[year]

        link = "https://myanimelist.net/anime/{}/".format(idMal)
        matches = soup.select('h3 a[href="{}"]'.format(link))

        if len(matches) == 0:
            print("no matches")
            raise Exception()

        elem = matches[0]
        table = elem.parent.find_next("tbody")

        first_col = [i.find("td").string for i in table.find_all("tr")]
        choices = list(filter(lambda x: x and not x.isspace(), first_col))

        title = random.choice(choices)
        clean_title = title.replace("\"", "")
        full_title = f"{name} {clean_title}"
        return full_title

    async def get_random(self, guild_id):
        # i really need this to return something eventually, but theres a lot of points of failure
        # rather than try to handle all of them, i just retry when something fails
        try:
            # choose from lists
            anime, idMal, year, cover, name, synonyms = self.games[guild_id].random_anime()

            title = await self.random_title(idMal, year, name)

            # avoid repeats
            while len(self.pasts[0]) >= self.games[guild_id].length:
                self.pasts[1].remove(self.pasts[0].pop())
            if title in self.pasts[1]:
                print("repeat")
                raise Exception()
            else:
                self.pasts[0].appendleft(title)
                self.pasts[1].add(title)

            print(title)

            # construct player
            player = await YTDLSource.create_source(title, loop=self.bot.loop, stream=True)

            return (name, cover, title, player, synonyms)
        except Exception as e:
            print(e)
            if guild_id in self.games:
                return await self.get_random(guild_id)

    def longest_common_subsequence(self, A, B):
        x = len(A)
        y = len(B)
        z = 0

        L = [[0 for j in range(y)] for i in range(x)]

        for i in range(x):
            for j in range(y):
                if A[i] == B[j]:
                    if i == 0 or j == 0:
                        L[i][j] = 1
                    else:
                        L[i][j] = L[i - 1][j - 1] + 1
                    if L[i][j] > z:
                        z = L[i][j]
        return z

    def guess_match(self, source, target):
        if source == None or target == None:
            return False

        def clean_string(s):
            return re.sub(r"[\W_]+", " ", s.lower()).split(" ")

        source_list = clean_string(source)
        target_list = clean_string(target)

        if source == target:
            return True

        if source_list[0] in target_list and len(source_list[0]) >= 6:
            return True

        # source_list is a sublist of target_list of at least length 2
        lcs = self.longest_common_subsequence(source_list, target_list)
        if len(source_list) == lcs and lcs >= 2:
            return True

        return False

    async def handle_controls(self, ctx, event, message, game):
        await message.add_reaction('▶')

        def check(reaction, user):
            return (reaction.message.id == message.id
                and str(reaction.emoji) == '▶'
                and user.id in game.players
            )

        def skip_check(reaction, user):
            return (reaction.message.id == message.id
                and str(reaction.emoji) == '⏭'
                and user.id in game.players
            )

        try:
            reaction, user = await self.bot.wait_for('reaction_add', timeout=5.0, check=check)
            await message.add_reaction('⏭')
            skip_task = self.bot.wait_for('reaction_add', check=skip_check)
            # wait for song end or skip react, whichever comes first
            _, pending = await asyncio.wait([event.wait(), skip_task],
                                            return_when=asyncio.FIRST_COMPLETED)
            for task in pending:
                task.cancel()

        except asyncio.TimeoutError:
            pass

    async def game_step(self, ctx, song, game):
        (name, cover, title, player, synonyms) = song

        event = asyncio.Event()

        # stop before play lets previous song play until next song, eliminating awk gap
        ctx.voice_client.stop()
        ctx.voice_client.play(player, after=lambda e: event.set())

        print("playing")

        def check(m):
            return (m.channel.id == ctx.channel.id and
                (self.guess_match(m.content, name) or
                    any([self.guess_match(m.content, i) for i in synonyms]))
            )

        try:
            message = await self.bot.wait_for('message', timeout=30.0, check=check)
            embed = self.games[ctx.guild.id].increment_score(message.author, name, title, cover)
            m = await ctx.send(embed = embed)
            # handle if someone presses continue
            await self.handle_controls(ctx, event, m, game)

        except asyncio.TimeoutError:
            embed = self.games[ctx.guild.id].failure(name, title, cover)
            await ctx.send(embed=embed)

    async def game_loop(self, ctx, game):

        song = await self.get_random(ctx.guild.id)
        while game.guild_id in self.games:
            try:
                await self.game_step(ctx, song, game)
                song = await self.get_random(ctx.guild.id)
            except Exception as e:
                print(e)
                song = await self.get_random(ctx.guild.id)

    @commands.group(aliases=["am"], invoke_without_command=True)
    async def animu(self, ctx):
        embed = discord.Embed(
            title = "Anime Music Game",
            description = " ".join([
                "Test your weeb level against fellow weebs!",
                "Join a voice channel, add at least one anime list using `?am add_list [anilist username]`, "
                "and start the game using `?am play`.",
                "\n\nWhen you recognize what anime you think it's from, simply type out your guess.",
                "You get 5 points for every correct guess, and there's no penalty for guessing.",
                "\n\nOnce you guess correctly, you can use ▶ to continue playing the song",
                "or ⏭ to skip to the next one.",
                "The next song will start automatically in 5 seconds.",
                "\n\nIf you ever want to stop the game, just type out `?am stop`",
                "and the game will tally up your score.",
                "\n\nHave fun!"
            ]),
            color = 0xe475ea
        )

        embed.set_footer(text=f"i am not liable for any time lost playing this game (image credits to @deeeskye)")
        embed.set_image(url="https://i.pinimg.com/originals/34/b2/2e/34b22e8d6c9be0f9d5f09b0295d65747.jpg")
        await ctx.send(embed=embed)

    @animu.command()
    async def play(self, ctx):
        if not ctx.guild.id in self.games:
            await ctx.send("no lists, can't start!")
            return

        if ctx.author.voice == None:
            await ctx.send("hmm, r u sure ur in a voice channel?")
            return

        channel = ctx.author.voice.channel

        try:
            await channel.connect()
        except discord.errors.ClientException as e:
            await ctx.send("woops! can't do that...")
            print(e)
            return

        embed = discord.Embed(
            title = "Anime Music Game",
            description = "Starting!",
            color = 0xe475ea
        )
        await ctx.send(embed=embed)

        await self.game_loop(ctx, self.games[ctx.guild.id])

    @animu.command()
    async def remove_list(self, ctx, name):
        try:
            embed = self.games[ctx.guild.id].remove_list(name)
            await ctx.send(embed=embed)
        except Exception as e:
            print(e)
            await ctx.send("failed")

    @animu.command()
    async def add_list(self, ctx, name):
        async with self.bot.session.post(ANILIST_API, json={
                'query': ANILIST_QUERY,
                'variables': {
                    'name': name
                }
        }) as response:
                if response.status != 200:
                    await ctx.send("failed")
                    print(response)
                else:
                    data = (await response.json())["data"]["MediaListCollection"]["lists"]
                    if not ctx.guild.id in self.games:
                        self.games[ctx.guild.id] = WeebGame(ctx.guild.id)
                    embed = self.games[ctx.guild.id].add_list(name, data[0]["entries"])
                    await ctx.send(embed=embed)

    @animu.command()
    async def stop(self, ctx):
        voice = discord.utils.get(self.bot.voice_clients, guild=ctx.guild)
        await voice.disconnect()
        await ctx.send(embed=self.games[ctx.guild.id].end_embed())
        del self.games[ctx.guild.id]

def setup(bot):
    bot.add_cog(WeebMusic(bot))


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('userprofile', '0003_userconfirmation_user'),
    ]

    operations = [
        migrations.AddField(
            model_name='userprofile',
            name='superuser',
            field=models.BooleanField(default=False),
            preserve_default=True,
        ),
        migrations.AlterField(
            model_name='userprofile',
            name='followed_questions',
            field=models.ManyToManyField(related_name='followed_users', to='question.Question'),
            preserve_default=True,
        ),
    ]


import pickle
list =[]
while True:
    roll = input("Enter student Roll No:")
    sname  = input("Enter student Name :")
    student = {"roll":roll,"name":sname}
    list.append(student)
    choice= input("Want to add more record(y/n) :")
    if(choice=='n'):
        break

file = open("student.dat","wb")
pickle.dump(list,file)
file.close()


import os
import sys
sys.path.insert(0, "../src/")
from Leaf import Leaf
from Token import Token

__author__ = "Davide Muzio"
__version__ = "1.0.0"

def testGetTag():
    print("Test per getTag")
    token = Token()
    listExpectedValue = "S"
    token.setPosTag(listExpectedValue)
    # test
    leaf = Leaf()
    leaf.setToken(token)
    value = leaf.getTag()
    assert value == listExpectedValue, "Errore test"

def testSetToken():
    print("Test per setToken")
    token = Token()
    listExpectedValue = token
    # test
    leaf = Leaf()
    leaf.setToken(listExpectedValue)
    assert leaf.getToken() == listExpectedValue, "Errore test"

def testGetToken():
    print("Test per getToken")
    token = Token()
    listExpectedValue = token
    # test
    leaf = Leaf()
    leaf.setToken(listExpectedValue)
    value = leaf.getToken()
    assert value == listExpectedValue, "Errore test"

def testNumBranch():
    print("Test per numBranch")
    listExpectedValue = 0
    # test
    leaf = Leaf()
    value = leaf.numBranch()
    assert value == listExpectedValue, "Errore test"

def main():
    print("Test per la classe Leaf")
    testGetTag()
    testSetToken()
    testGetToken()
    testNumBranch()

if __name__ == "__main__":
    main()


#Peak hours
#Winter-October - March
#Summer-April-September

import pandas as pd
import csv

userinfo1 = pd.read_csv('/Users/rhearepe/Documents/Financial Analytics/Sem 3/Data Visualization/citibike/2019/userinfo/user_data1.csv')
userinfo2 = pd.read_csv('/Users/rhearepe/Documents/Financial Analytics/Sem 3/Data Visualization/citibike/2019/userinfo/user_data2.csv')
userinfo3 = pd.read_csv('/Users/rhearepe/Documents/Financial Analytics/Sem 3/Data Visualization/citibike/2019/userinfo/user_data3.csv')
userinfo4 = pd.read_csv('/Users/rhearepe/Documents/Financial Analytics/Sem 3/Data Visualization/citibike/2019/userinfo/user_data4.csv')

#Change format to datetime and time to hours:minutes
userinfo1['starttime'] = pd.to_datetime(userinfo1['starttime'])
userinfo1['stoptime'] = pd.to_datetime(userinfo1['stoptime'])

userinfo1['starttime'] = userinfo1['starttime'].dt.strftime('%Y-%m-%d %H:%M')
userinfo1['stoptime'] = userinfo1['stoptime'].dt.strftime('%Y-%m-%d %H:%M')

userinfo2['starttime'] = pd.to_datetime(userinfo2['starttime'])
userinfo2['stoptime'] = pd.to_datetime(userinfo2['stoptime'])

userinfo2['starttime'] = userinfo2['starttime'].dt.strftime('%Y-%m-%d %H:%M')
userinfo2['stoptime'] = userinfo2['stoptime'].dt.strftime('%Y-%m-%d %H:%M')

userinfo3['starttime'] = pd.to_datetime(userinfo3['starttime'])
userinfo3['stoptime'] = pd.to_datetime(userinfo3['stoptime'])

userinfo3['starttime'] = userinfo3['starttime'].dt.strftime('%Y-%m-%d %H:%M')
userinfo3['stoptime'] = userinfo3['stoptime'].dt.strftime('%Y-%m-%d %H:%M')

userinfo4['starttime'] = pd.to_datetime(userinfo4['starttime'])
userinfo4['stoptime'] = pd.to_datetime(userinfo4['stoptime'])

userinfo4['starttime'] = userinfo4['starttime'].dt.strftime('%Y-%m-%d %H:%M')
userinfo4['stoptime'] = userinfo4['stoptime'].dt.strftime('%Y-%m-%d %H:%M')

#Sort data by time counts by start time
peaktimes1 = userinfo1.groupby(['starttime']).size().reset_index(name='counts')
peak_hours1 = peaktimes1.sort_values('counts', ascending=False)

peaktimes2 = userinfo2.groupby(['starttime']).size().reset_index(name='counts')
peak_hours2 = peaktimes2.sort_values('counts', ascending=False)

peaktimes3 = userinfo3.groupby(['starttime']).size().reset_index(name='counts')
peak_hours3 = peaktimes3.sort_values('counts', ascending=False)

peaktimes4 = userinfo4.groupby(['starttime']).size().reset_index(name='counts')
peak_hours4 = peaktimes4.sort_values('counts', ascending=False)

#Save to csv

peak_hours1.to_csv("Peakhours1.csv")
peak_hours2.to_csv("Peakhours2.csv")
peak_hours3.to_csv("Peakhours3.csv")
peak_hours4.to_csv("Peakhours4.csv")

#Sort data by time counts by end time

end_time1 = userinfo1.groupby(['stoptime']).size().reset_index(name='counts')
end_hours1 = end_time1.sort_values('counts', ascending=False)

end_time2 = userinfo2.groupby(['stoptime']).size().reset_index(name='counts')
end_hours2 = end_time2.sort_values('counts', ascending=False)

end_time3 = userinfo3.groupby(['stoptime']).size().reset_index(name='counts')
end_hours3 = end_time3.sort_values('counts', ascending=False)

end_time4 = userinfo4.groupby(['stoptime']).size().reset_index(name='counts')
end_hours4 = end_time4.sort_values('counts', ascending=False)

#Save to csv
end_hours1.to_csv("Endhours1.csv")

end_hours2.to_csv("Endhours2.csv")

end_hours3.to_csv("Endhours3.csv")

end_hours4.to_csv("Endhours4.csv")


"""
Test the code for the mailroom code in mailroom assignment 4.
Test send thank you function.
    Focuses:
        Generating thank you text
        Adding or updating donors
        listing donors
Test Create Report function.
    Focuses:
        Creation of report rows
Test Send Letters report.
    Focuses:
        Generation of thank you text
        File creation
"""

import mailroom4 as mailroom
import os

name1 = 'Jim'
name2 = 'Steve'
names = [name1, name2]

donation1 = 123
donation2 = 123.23
donation3 = 'Fred'
donation4 = (123,'Fred')

dict1 = {name1:[donation1]}
dict2 = {name1:[donation1],name2:[donation2]}
dict3 = {name1:[donation1,donation2],name2:[donation2]}

def test_write_email():
    """Test email text is generated correctly"""
    expected = f"\n\nDear Jim,\n\n\tWe appreciate your generous donations totaling $123.00.\n\nThank you,\nAndrew\n\n"
    assert mailroom.write_email(name1,dict1) == expected

def test_add_donation_new_name():
    """Test that a name and donation are being added correctly to the Donor List"""
    expected = {'Jim': [123.00], 'Steve':[123.23]}
    assert mailroom.add_donation(name2,dict1,str(donation2)) == expected

def test_add_donation_existing_name():
    """Test that a donation is being added to the correct donor"""
    expected = {'Jim': [123.00, 123.23], 'Steve': [123.23]}
    assert mailroom.add_donation(name1,dict1,str(donation2)) == expected

def test_show_list():
    """test list of names is properly displayed"""
    expected = "\n".join(list(dict3))
    assert mailroom.show_list(dict3) == expected

def test_report_sorting():
    """test that the report is generated correctly if second entry donates more than the first"""
    expected = [(name2, donation2, 1, donation2), (name1, donation1, 1, donation1)]
    assert mailroom.build_report(dict2) == expected

def test_email_file_write():
    """Test that text files are created corretly in email function"""
    mailroom.write_email(name1,dict1)
    for root, dir, files in os.walk('./lesson06'):
        assert any(f==f"Thank_You_to_{name1}.txt" for f in files)


import random
from urllib.request import urlopen
import sys

WORD_URL ="http://learncodethehardway.org/words.txt"
WORDS = []

PHRASE = {
    " class %%%(%%%)":
        "Make a class named %%% that is-a %%%.",
    "class %%%(object):\n\tdef __init__(self, ***)":
        "class %%% has-a __init__ that takes self and *** params.",
    "class %%%(object):\n\t def ***(self, @@@)":
        "class %%% has- a function *** that takes self and @@@ params.",
    "*** = %%%()":
        "From *** get the *** function, call it with params self, @@@.",
    "***.*** = '***'":
        "From *** get the *** attribute and set it to '***'."
}

# do they want to drill phrase first
if len(sys.argv) == 2 and sys.argv[1] == 'english':
    PHRASE_FIRST = True
else :
    PHRASE_FIRST = False

# load up the words from the website
for word in urlopen(WORD_URL).readlines():
    WORDS.append(str(word.strip(), encoding = "utf-8"))

snippets = list(PHRASE.keys())
random.shuffle(snippets)

for snippet in snippets:
    phrase = PHRASE[snippet]
    print(phrase)
#print("random keys", )
#print(snippets)
#for keyvalue in snippets:
#    print(keyvalue)


#!/usr/bin/env python

"""
KMTEditor.py

This program allows one to edit a 2D KMT data pixel for pixel.

Author : Deepak Chandan
Date   : June 24th, 2015
"""

import sys, argparse, os, time
from netCDF4 import Dataset
import numpy as np
from PyQt4.QtCore import *
from PyQt4.QtGui import *

import matplotlib as mpl
from matplotlib import pylab as plt
from mpl_toolkits.basemap import Basemap
import matplotlib.patches as mpatches
from matplotlib.collections import PatchCollection
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

#from cesmGUITools.utilities import nccopy
from nccopy import nccopy

mpl.rc('axes',edgecolor='w')

class DataContainer(object):
    """
    DataContainer: A "data container" class for this application which does the job
    of storing the map and other related data as well as a "cursor" upon this data.
    """
    class Cursor(object):
        def __init__(self):
            self.marker = None   # The symbol which is used to denote the marker. Leave it as 'None' to show a square.
            self.x = 0           # X-position of the cursor
            self.y = 0           # Y-position of the cursor

    def __init__(self, nrows, ncols, fname, datavar):
        """
        ARGUMENTS
            nrows - number of rows for the view
            ncols - number of columns for the view
            fname - name of the data file.
            scale - a multiplicative scale factor for the data to be visualized and edited
        """
        self.fname   = fname
        self.datavar = datavar
        self.__read_nc_file()
        self.orig_data = np.copy(self.data)
        self.ny, self.nx = self.data.shape

        self.lon_modulo = 360

        # Datawindow variables
        self.view   = None        # The array (actually a numpy view) that stores the data to be displayed in the main window
        self.view_masked = None   # A masked version of self.view
        self.nrows  = nrows       # Number of rows to display in the main windows (the 'view')
        self.ncols  = ncols       # Number of cols to display in the main windows
        self.si     = None        # 0-based row index of the first element
        self.sj     = None        # 0-based col index of the first element

        # Tracking which elements are changed
        # The columns store: i index, j index, new value
        self.changes = np.zeros((self.ny*self.nx, 3), dtype=np.int32)
        self.changes_row_idx = 0

        # A cursor object on the view
        self.cursor = DataContainer.Cursor()

    def __read_nc_file(self):
        """ This subroutine reads the netCDF4 data file. """
        ncfile        = Dataset(self.fname, "r", format="NETCDF4")
        # We are flipping the arrays so that the latitudes go from 90:-90
        self.data     = np.flipud(ncfile.variables[self.datavar][:,:])
        self.kmt_lons = np.flipud(ncfile.variables["ULON"][:,:])
        self.kmt_lats = np.flipud(ncfile.variables["ULAT"][:,:])
        ncfile.close()

    def getViewStatistics(self): return (self.view.min(), self.view.max(), self.view.mean())

    def getCursor(self): return self.cursor

    def getValueUnderCursor(self):
        # We need to first map the position of the cursor in the view to the position of the
        # on the global map.
        ci, cj = self.viewIndex2GlobalIndex(self.cursor.y, self.cursor.x)
        return self.data[ci, cj]

    def updateCursorPosition(self, event):
        """
        Updates the current view in the data window. This function is
        triggered whenever the user presses the arrow keys.
        ARGUMENTS
            event - Qt key press event
        """
        key = event.key()
        # on_boundary = None   # This will store which boundary if any we've reached
        if key == Qt.Key_Up:
            self.cursor.y = max(0, self.cursor.y - 1)
        elif key == Qt.Key_Down:
            self.cursor.y = min(self.nrows-1, self.cursor.y + 1)
        elif key == Qt.Key_Left:
            self.cursor.x = max(0, self.cursor.x - 1)
        elif key == Qt.Key_Right:
            self.cursor.x = min(self.ncols-1, self.cursor.x + 1)

    def updateView(self, si, sj):
        """
        Updates the data for the view.
        ARGUMENTS
            si, sj - the global 0-based i,j indices of the top left corner of the view
        RETURNS
            Statistics of the newly updated view (a tuple with the min, max, and the mean for the new view)
        """
        self.view = self.data[si:si+self.nrows, sj:sj+self.ncols].view()

        # We need to create the continent mask. We will take this as a masked numpy view
        # on the self.view object.
        self.view_masked = self.view.view(np.ma.MaskedArray)

        # Now that we have updated the view, and created the masked view of the
        # view itself, we need to update the "mask" of the masked view.
        self.updateMask()

        self.si   = si
        self.sj   = sj
        return self.getViewStatistics()

    def updateMask(self): self.view_masked.mask = (self.view == 0)

    def moveView(self, move):
        """
        Moves the view window over the global dataset in response to the L,R,U,D keys.
        ARGUMENTS
            move : A Qt key value
        RETURNS
            Statistics of the newly updated view (a tuple with the min, max, and the mean for the new view)
        """
        col_inc = int(self.ncols*0.25)  # Column increment
        row_inc = int(self.nrows*0.25)  # Row increment

        if (move == Qt.Key_L):  # MOVE THE VIEW RIGHT
            new_sj = min(self.nx-self.ncols, self.sj + col_inc)
            return self.updateView(self.si, new_sj)
        elif (move == Qt.Key_H): # MOVE THE VIEW LEFT
            new_sj = max(0, self.sj - col_inc)
            return self.updateView(self.si, new_sj)
        elif (move == Qt.Key_K): # MOVE THE VIEW UP
            new_si = max(0, self.si - row_inc)
            return self.updateView(new_si, self.sj)
        elif (move == Qt.Key_J): # MOVE THE VIEW DOWN
            new_si = min(self.ny-self.nrows, self.si + row_inc)
            return self.updateView(new_si, self.sj)

    def modifyValue(self, inp):
        """
        Modify the value for a particular pixel. The location of the pixel is that
        determined by the current position of the cursor.
        ARGUMENTS
            inp - a string containing a float
        """
        ci, cj = self.viewIndex2GlobalIndex(self.cursor.y, self.cursor.x)

        _tmp = int(float(inp))
        self.data[ci, cj] = _tmp
        self.changes[self.changes_row_idx, :] = ci, cj, _tmp
        self.changes_row_idx += 1

        # Now that we have changed a value, we have to update the continent mask as
        # well, in case the update entailed creating or destroying land.
        self.updateMask()

    def getAverage(self):
        """
        Returns the average value at the cursor computed from the values of the surrounding cells. This
        is a 4 point average.
        If center==True, then includes the cell at which the cursor is in the calculation of the average,
        in which case it will be a 5 point average.
        """
        ci, cj = self.cursor.y, self.cursor.x
        _sum   = self.view_masked[ci-1:ci+2,cj-1:cj+2].sum()
        # Rounding the floating point to the **nearest** integer
        return np.round(_sum/(self.view_masked[ci-1:ci+2,cj-1:cj+2].count()))

    def viewIndex2GlobalIndex(self, i, j):
        """ Converts an i,j index into the data window into an index for the
        same element into the global data. """
        return (self.si + i, self.sj + j)

class KMTEditor(QMainWindow):

    KMT_MIN_VAL = 0
    KMT_MAX_VAL = 60

    def __init__(self, fname, datavar, dwx=60, dwy=60):
        """
        ARGUMENTS:
            fname    - Name of the netcdf4 file
            datavar  - Name of the data variable in the file for which to plot
            dwx, dwy - size of the DataContainer in number of array elements
            scale    - A float that will be multiplied with the data to scale the data
        """
        super(KMTEditor, self).__init__(None)
        self.setWindowTitle('KMTEditor - {0}'.format(fname))

        #  Creating a variable that contains all the data
        self.dc = DataContainer(dwy, dwx, fname, datavar)

        self.cursor = self.dc.getCursor()  # Defining a cursor on the data
        # This is the Rectangle boundary drawn on the world map that bounds the region
        # under the view. At the start of the program it's value is None
        self.prvrect = None

        # This stores the matplotlib text objects used in the rendering of the colorbar
        # This is used by the function draw_colorbar()
        self.colorbarlabels = []
        # self.colorbar_gradient is used by the function draw_colorbar()
        self.colorbar_gradient = np.vstack((np.linspace(0, 1, 256), np.linspace(0, 1, 256)))

        # The previously updated value
        self.buffer_value = None

        # Stuff for saving data
        self.ofile = None   # Name of output file
        self.asked_about_overwrite_permission = False
        self.unsaved_changes_exist = False

        self.maps = mpl.cm.datad.keys()  # The names of colormaps available
        self.maps.sort() # Sorting them alphabetically for ease of use

        self.create_menu()
        self.create_main_window()

        self.set_stats_info(self.dc.updateView(0, 0))  # Set the initial view for the data container class

        self.draw_preview_worldmap()
        self.render_view()
        self.statusBar().showMessage('KMTEditor 2015')

    def keyPressEvent(self, e):
        if e.key() == Qt.Key_Equal:
            # Pressing = for edit
            self.inputbox.setFocus()
        elif e.key() == Qt.Key_V:
            self.update_value(self.buffer_value)
        elif e.key() == Qt.Key_C:
            self.buffer_value = self.dc.getValueUnderCursor()
            self.statusBar().showMessage('Value copied: {0}'.format(self.buffer_value), 2000)
        elif e.key() == Qt.Key_A:
            # Get the 5-point average and update the value
            self.update_value_with_average(self.dc.getAverage())
        elif e.key() == Qt.Key_M:
            self.colormaps.setFocus()
        elif e.key() == Qt.Key_Escape:
            # Pressing escape to refocus back to the main frame
            self.main_frame.setFocus()
        elif e.key() in [Qt.Key_H, Qt.Key_J, Qt.Key_K, Qt.Key_L]:
            self.set_stats_info(self.dc.moveView(e.key()))
            self.render_view()
            self.render_edited_cells()
        else:
            self.dc.updateCursorPosition(e)
            self.draw_cursor()

    def create_main_window(self):
        """
        This function creates the main window of the program.
        """
        self.main_frame = QWidget()
        self.main_frame.setMinimumSize(QSize(700, 700))

        self.dpi = 100
        self.fig = plt.Figure((6, 6), dpi=self.dpi, facecolor='w', edgecolor='w')
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)

        # Stuff for the preview map >>>>>>>>>>>>>>>>>>>>>>>>>
        self.preview_frame = QWidget()
        self.preview_fig = plt.Figure((3, 1.6), dpi=self.dpi, facecolor='w', edgecolor='w')
        self.preview = FigureCanvas(self.preview_fig)
        self.preview.setParent(self.preview_frame)
        self.preview_axes = self.preview_fig.add_subplot(111)

        self.preview_fig.canvas.mpl_connect('button_press_event', self.onclick)
        self.preview_fig.subplots_adjust(top=1, bottom=0, left=0, right=1)
        # Stuff for the preview map <<<<<<<<<<<<<<<<<<<<<<<<<

        # Stuff for the colorbar >>>>>>>>>>>>>>>>>>>>>>>>>
        self.colorbar_frame = QWidget()
        self.colorbar_fig   = plt.Figure((3,0.4), dpi=self.dpi, facecolor='w', edgecolor='w')
        self.colorbar       = FigureCanvas(self.colorbar_fig)
        self.colorbar.setParent(self.colorbar_frame)
        self.colorbar_axes  = self.colorbar_fig.add_subplot(111)
        self.colorbar_fig.subplots_adjust(top=1.0, bottom=0.35, left=0.02, right=0.97) #Tightening the area around the subplot
        self.colorbar_fig.patch.set_facecolor('none') # Making the figure background transparent

        self.colorbar_axes.get_xaxis().set_visible(False)
        self.colorbar_axes.get_yaxis().set_visible(False)
        # Stuff for the colorbar <<<<<<<<<<<<<<<<<<<<<<<<<

        # Since we have only one plot, we can use add_axes
        # instead of add_subplot, but then the subplot
        # configuration tool in the navigation toolbar wouldn't
        # work.
        #
        self.axes = self.fig.add_subplot(111)
        # Turning off the axes ticks to maximize space. Also the labels were meaningless
        # anyway because they were not representing the actual lat/lons.
        self.axes.get_xaxis().set_visible(False)
        self.axes.get_yaxis().set_visible(False)

        # Other GUI controls
        # Information section
        font = QFont("SansSerif", 14)

        # STATISTICS >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        self.statdisplay = QLabel("Statistics:")
        self.statgrid    = QGridLayout()
        self.statgrid.setSpacing(5)
        w = QLabel("View"); w.setFont(font)
        self.statgrid.addWidget(w,  1, 1, Qt.AlignCenter)
        w = QLabel("Global"); w.setFont(font)
        self.statgrid.addWidget(w, 1, 2, Qt.AlignCenter)

        for i, name in enumerate(["Minimum", "Maximum", "Mean"]):
            w = QLabel(name)
            w.setFont(font)
            self.statgrid.addWidget(w, i+2, 0, Qt.AlignLeft)

        self.statsarray = []
        for i in range(6): self.statsarray.append(QLabel(''))

        self.statsarray[3].setText("{0:3d}".format(int(self.dc.data.min())))
        self.statsarray[4].setText("{0:3d}".format(int(self.dc.data.max())))
        self.statsarray[5].setText("{0:3d}".format(int(self.dc.data.mean())))

        for i in range(3):
            self.statgrid.addWidget(self.statsarray[i], i+2, 1, Qt.AlignCenter)
            self.statgrid.addWidget(self.statsarray[i+3], i+2, 2, Qt.AlignCenter)
            self.statsarray[i].setFont(font)
            self.statsarray[i+3].setFont(font)

        # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

        # PIXEL INFO >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        self.infodisplay = QLabel("Pixel Information:")
        self.infogrid    = QGridLayout()
        self.infogrid.setSpacing(5)

        for i, name in enumerate(["Lat", "Lon", "KMT", "I, J"]):
            w = QLabel(name)
            w.setFont(font)
            # w.setLineWidth(1)
            # w.setFrameShape(QFrame.Box)
            self.infogrid.addWidget(w, i+2, 0, Qt.AlignLeft)

        self.latdisplay  = QLabel("")
        self.londisplay  = QLabel("")
        self.valdisplay  = QLabel("")
        self.idxdisplay  = QLabel("")
        for i,w in enumerate([self.latdisplay, self.londisplay, self.valdisplay, self.idxdisplay]):
            self.infogrid.addWidget(w, i+2, 1, Qt.AlignLeft)
            w.setFont(font)
        # <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

        # Colorscheme selector
        cmap_label = QLabel('Colorscheme:')
        self.colormaps = QComboBox(self)
        self.colormaps.addItems(self.maps)
        self.colormaps.setCurrentIndex(self.maps.index('Set1'))
        self.colormaps.currentIndexChanged.connect(self.render_view)

        # New value editor
        valhbox = QHBoxLayout()
        w = QLabel("Enter new value: ")
        w.setFont(font)
        valhbox.addWidget(w)
        self.inputbox = QLineEdit()
        self.inputbox.returnPressed.connect(self.update_value)
        valhbox.addWidget(self.inputbox)

        for item in [self.statdisplay, self.infodisplay, self.latdisplay, self.londisplay, self.valdisplay, self.idxdisplay, cmap_label]:
            item.setFont(font)

        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)

        vbox2 = QVBoxLayout()
        vbox2.addWidget(self.preview)           # Adding preview window

        # Horizontal line
        fr = QFrame(); fr.setLineWidth(0.5); fr.setFrameShape(QFrame.HLine)
        vbox2.addWidget(fr)
        vbox2.setAlignment(fr, Qt.AlignTop)

        # databox is a horizontal box for the displayed "information"
        databox  = QHBoxLayout()
        statvbox = QVBoxLayout()    # This is the sub-box for the statistics
        statvbox.addWidget(self.statdisplay)
        statvbox.setAlignment(self.statdisplay, Qt.AlignTop)
        statvbox.addLayout(self.statgrid)
        databox.addLayout(statvbox)

        fr = QFrame(); fr.setLineWidth(0.5); fr.setFrameShape(QFrame.VLine)
        databox.addWidget(fr)

        pixelvbox = QVBoxLayout()   # This is another sub-box of databox for the pixel info
        pixelvbox.addWidget(self.infodisplay)
        pixelvbox.setAlignment(self.infodisplay, Qt.AlignTop)
        pixelvbox.addLayout(self.infogrid)
        databox.addLayout(pixelvbox)

        vbox2.addLayout(databox)

        # Horizontal line
        fr = QFrame(); fr.setLineWidth(0.5); fr.setFrameShape(QFrame.HLine)
        vbox2.addWidget(fr)
        vbox2.setAlignment(fr, Qt.AlignTop)

        vbox2.addLayout(valhbox, Qt.AlignTop)

        vbox2.addStretch(1)
        vbox2.addWidget(cmap_label)           # Adding the colormap label
        vbox2.addWidget(self.colormaps)       # Adidng the colormap selector
        vbox2.addWidget(self.colorbar)
        vbox2.setAlignment(self.colorbar, Qt.AlignCenter)
        vbox2.addStretch(1)

        helpbox = QVBoxLayout()

        help_title = QLabel("Help")
        font = QFont("SansSerif", 14)
        font.setBold(True)
        help_title.setFont(font)

        helpbox.addWidget(help_title); helpbox.setAlignment(help_title, Qt.AlignTop)

        helpgrid = QGridLayout()
        helpgrid.setSpacing(5)

        helpgrid.addWidget(QLabel("Key"),                 0, 0, 1, 1,Qt.AlignLeft)
        helpgrid.addWidget(QLabel("Action"),              0, 1, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("up, down,left,right"), 1, 0, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("move cursor"),         1, 1, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("h,j,k,l"),             2, 0, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("move view"),           2, 1, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("a"),                   3, 0, 1, 1, Qt.AlignLeft)
        # helpgrid.addWidget(QLabel("replace cell value with 9 point average"),         3, 1, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("replace cell value with 9\npoint average"),         3, 1, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("="),                   4, 0, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("enter new value for cell"),         4, 1, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("c"),                   5, 0, 1, 1, Qt.AlignLeft)
        # helpgrid.addWidget(QLabel("copy value under cursor into buffer"),         5, 1, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("copy value under cursor\ninto buffer"),         5, 1, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("v"),                   6, 0, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("paste value in buffer"),6, 1, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("m"),                   7, 0, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("move focus to color selector"),         7, 1, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("Escape"), 8, 0, 1, 1, Qt.AlignLeft)
        helpgrid.addWidget(QLabel("move focus to main view"),         8, 1, 1, 1, Qt.AlignLeft)

        helpbox.addLayout(helpgrid); helpbox.setAlignment(helpgrid, Qt.AlignTop)

        vbox2.addLayout(helpbox)
        vbox2.setAlignment(helpbox, Qt.AlignBottom)

        hbox = QHBoxLayout()
        hbox.addLayout(vbox)
        hbox.addLayout(vbox2)

        self.main_frame.setLayout(hbox)
        self.setCentralWidget(self.main_frame)
        self.main_frame.setFocus()

    def draw_preview_worldmap(self):
        """
        This function draws the world map in the preview window on the top right hand corner
        of the application.
        """
        m = Basemap(projection='cyl', lon_0=180, llcrnrlat=-90,urcrnrlat=90,\
            llcrnrlon=0,urcrnrlon=360,resolution='c', ax=self.preview_axes)
        self.preview_axes.set_xlim([0,360])

        m.drawcoastlines(linewidth=0.5)
        m.fillcontinents()
        self.preview_axes.set_ylim([-90,90])

    def draw_colorbar(self):
        """
        This function draws the colorbar and the labels for the colorbar.
        """
        # First clear the colorbar axes
        self.colorbar_axes.cla()
        # Get the current selected colormap
        cmap = mpl.cm.get_cmap(self.maps[self.colormaps.currentIndex()])
        # Plot the colormap
        self.colorbar_axes.imshow(self.colorbar_gradient, aspect='auto', cmap=cmap)
        pos = list(self.colorbar_axes.get_position().bounds)
        dx = (pos[2])/6.  # The spacing between the labels

        if self.colorbarlabels != []:
            # Delete and clear the text labels
            while self.colorbarlabels: self.colorbarlabels.pop().remove()

        for i,l in enumerate([1,10,20,30,40,50,60]):
            self.colorbarlabels.append(self.colorbar_fig.text(pos[0]+(i*dx), 0.01, str(l), va='bottom', ha='center', fontsize=10))
        self.colorbar.draw()

    def draw_cursor(self, noremove=False):
        if self.cursor.marker and (not noremove): self.cursor.marker.remove()
        # The increment by 0.5 below is done so that the center of the marker is shifted
        # so that the top left corner of the square marker conicides with the top right corner
        # of each pixel. The value of 0.5 comes simply because each pixel are offset by 1 in each dimension.
        _cx, _cy = self.cursor.x+0.5, self.cursor.y+0.5
        self.cursor.marker = self.axes.scatter(_cx, _cy, s=55,
                             marker='s', edgecolor="k", facecolor='none', linewidth=2)
        self.set_information(self.cursor.y, self.cursor.x)
        self.canvas.draw()

    def render_edited_cells(self):
        """
        This function draws a box around cells that have been edited, thereby highlighting
        them from the other cells.
        """
        changes_row_idx = self.dc.changes_row_idx

        # We only need to go ahead if a change has been made, i.e. changes_row_idx is larger than 0
        if changes_row_idx > 0:
            # We are creating simple views to make the code for this function simpler
            change_rows = self.dc.changes[:self.dc.changes_row_idx, 0].view()  # A view on rows indices that have been changed
            change_cols = self.dc.changes[:self.dc.changes_row_idx, 1].view()  # A view on column indices that have been changed

            # Retrieving some class variables and storing for speed
            si    = self.dc.si
            sj    = self.dc.sj
            nrows = self.dc.nrows
            ncols = self.dc.ncols

            # We select the indices that lie within the view box
            indices_of_interest = np.logical_and(np.logical_and(change_rows >= si,
                                                                change_rows <= (si+nrows)),
                                                 np.logical_and(change_cols >= sj,
                                                                change_cols <= (sj+ncols)))

            _i = change_rows[indices_of_interest] + 0.5 - si
            _j = change_cols[indices_of_interest] + 0.5 - sj

            self.axes.scatter(_j, _i, s=38, marker='s', edgecolor="k", facecolor='none', linewidth=1)
            self.canvas.draw()

    def render_view(self):
        self.draw_colorbar()
        self.axes.clear()
        # Either select the colormap through the combo box or specify a custom colormap
        cmap = mpl.cm.get_cmap(self.maps[self.colormaps.currentIndex()])
        self.axes.pcolor(self.dc.view_masked, cmap=cmap, edgecolors='w', linewidths=0.5,
                         vmin=KMTEditor.KMT_MIN_VAL, vmax=KMTEditor.KMT_MAX_VAL)

        tmp1 = self.dc.nrows
        tmp2 = self.dc.ncols

        # This is for drawing the black contour line for the continents
        self.axes.contour(self.dc.view, levels=[0], colors='k', linewidth=1.5,
                          interpolation="nearest", origin="lower",
                          extents=[0.5,tmp2+0.5, 0.5, tmp1+0.5])

        # Setting the axes limits. This helps in setting the right orientation of the plot
        # and in clontrolling how much extra space we want around the scatter plot.
        # I am putting 4% space around the scatter plot
        self.axes.set_ylim([int(tmp1*1.02), 0 - int(tmp1*0.02)])
        self.axes.set_xlim([0 - int(tmp2*0.02), int(tmp2*1.02)])
        self.canvas.draw()
        self.fig.tight_layout()
        self.draw_cursor(noremove=True)

    def update_value(self, inp=None):
        if inp == None:
            inp = self.inputbox.text()   # Get the value in the text box

        if self.InputValueIsAcceptable(inp):
            self.dc.modifyValue(inp)     # Modify the data array
            self.unsaved_changes_exist = True
            self.buffer_value = inp
            self.statusBar().showMessage('Value changed: {0}'.format(inp), 2000)
            self.set_stats_info(self.dc.getViewStatistics())
            self.inputbox.clear()        # Now clear the input box
            self.render_view()           # Render the new view (which now contains the updated value)
            self.render_edited_cells()
            self.main_frame.setFocus()   # Bring focus back to the view

    def update_value_with_average(self, val):
        """
        Updates the value at the current cursor position using the input val.
        """
        self.dc.modifyValue(val)     # Modify the data array
        self.unsaved_changes_exist = True
        self.statusBar().showMessage('Value changed: {0}'.format(val), 2000)
        self.set_stats_info(self.dc.getViewStatistics())
        self.render_view()           # Render the new view (which now contains the updated value)
        self.render_edited_cells()

    def InputValueIsAcceptable(self, inp):
        """ This functions checks to see if the user has entered a valid
            vlaue kmt value. Returns true if the input value is acceptable. """
        tt = float(inp)
        if (tt != int(tt)):
            msg = "KMT level must be an integer value\nYou entered {0}".format(inp)
            QMessageBox.critical(self, "Invalid Value", msg.strip())
            return False

        if ((tt < 0) or (tt > 60)):
            msg = "KMT level values must be between 0 and 60.\nYou entered {0}".format(inp)
            QMessageBox.critical(self, "Invalid Value", msg.strip())
            return False
        return True

    def set_information(self, i, j):
        """ Sets the displayed information about the pixel in the right sidebar.
        ARGUMENTS
            i, j : the local (i.e. DataContainer) 0-based indices for the element
        """
        i_global, j_global = self.dc.viewIndex2GlobalIndex(i, j) # Convert local indices to global indices
        self.latdisplay.setText("{0:7.3f}".format(self.dc.kmt_lats[i_global, j_global]))
        self.londisplay.setText("{0:7.3f}".format(self.dc.kmt_lons[i_global, j_global]))
        self.valdisplay.setText("{0:3d}".format(int(self.dc.data[i_global, j_global])))
        self.idxdisplay.setText("{0:3d},{1:3d}".format(int(i_global), int(j_global)))

    def set_stats_info(self, s):
        """
        Updates the statistics display panel with the stats for the view.
        ARGUMENTS
            s - a tuple with the min, max and mean of the view
        """
        self.statsarray[0].setText("{0:3d}".format(int(s[0])))
        self.statsarray[1].setText("{0:3d}".format(int(s[1])))
        self.statsarray[2].setText("{0:3d}".format(int(s[2])))

    def onclick(self, event):
        QMessageBox.information(self, "", "KMTEditor does not presently support mouse selection over the preview plot")

    def on_about(self):
        msg = """ Edit KMT levels for the POP ocean model.  """
        QMessageBox.about(self, "About", msg.strip())

    def save_data(self):
        """
        Saves the data to a netCDF4 file. The program tries to construct a default format of
        output filename, but if it exists, it asks the user whether to overwrite it. If the
        user does not want to overwrite, she is asked to enter a new filename.
        """

        # We construct a standard output name of the form: inputname_fixed.nc
        if self.ofile is None: self.ofile = self.dc.fname.split(".")[0]+"_fixed.nc"

        # Now we check if the file exists. Then we must ask the user if she wants to overwrite the file
        if not self.asked_about_overwrite_permission:
            clobber = False
            if os.path.exists(self.ofile):
                reply = QMessageBox.question(self, 'Saving file...', "The output file {0} exists. Overwrite?".format(self.ofile),
                        QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

                if reply == QMessageBox.Yes: clobber=True

                if not clobber:
                    # The use has responded to not overwrite, we must now ask for a new filename
                    ok = False
                    erromsg = ""
                    # This loop continues until an acceptable filename is entered, or the user presses cancel
                    while not ok:
                        _inp, ok = QInputDialog.getText(self, "Saving file...", "{0}Enter name of a different output file:".format(erromsg),)
                        if ok:
                            try:
                                self.ofile = str(_inp)
                            except:
                                ok = False
                                erromsg = "File name not acceptable. "
                            if os.path.exists(self.ofile):
                                ok = False
                                erromsg = "File exists. "
                        else:
                            self.ofile = None
                            self.statusBar().showMessage('Save cancelled', 2000)
                            return

            # To simplify creation of the output filename, i first duplicate the original file, then overwrite
            # the kmt array.
            nccopy(self.dc.fname, self.ofile, quiet=True, clobber=clobber, zlib=False, shuffle=False, classic=1)

            # now we set this to True, so that next time we save, we are not prompted about existing file
            self.asked_about_overwrite_permission = True

        ncfile = Dataset(self.ofile, "a", format="NETCDF4")
        alldimensions = ncfile.dimensions
        allvariables  = ncfile.variables
        if not "changes" in alldimensions: ncfile.createDimension("changes", None)
        if not "i" in alldimensions: ncfile.createDimension("i", 3)

        if not "original_kmt" in allvariables:
            okmt   = ncfile.createVariable("original_kmt", "f4", ("latitude", "longitude"))
            okmt.description   = "Original KMT data from which this file was created by KMTEditor.py"
            okmt[:,:]          = np.flipud(self.dc.orig_data)

        if not "changes" in allvariables:
            cngvar = ncfile.createVariable("changes", "f8", ("changes", "i"))
            cngvar.description = "changes to original data leading to present data. (i,j,val)"
            cngvar[:,:]        = self.dc.changes[0:self.dc.changes_row_idx,:]
        else:
            cngvar = allvariables["changes"]
            # s = cngvar.shape[0]
            cngvar[:,:]       = self.dc.changes[0:self.dc.changes_row_idx,:]

        kmtvar             = ncfile.variables["kmt"]
        kmtvar[:,:]        = np.flipud(self.dc.data)
        kmtvar.description = "Created by KMTEditor.py"

        ncfile.history     = "Created by KMTEditor.py"
        ncfile.input_file  = self.dc.fname
        ncfile.created     = time.ctime()
        ncfile.close()

        self.unsaved_changes_exist = False
        self.statusBar().showMessage('Saved to file: %s' % self.ofile, 2000)

    def create_action(self, text, slot=None, shortcut=None,
                      icon=None, tip=None, checkable=False,
                      signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action

    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def create_menu(self):
        self.file_menu = self.menuBar().addMenu("&File")

        load_file_action = self.create_action("&Save Data",
            shortcut="Ctrl+S", slot=self.save_data,
            tip="Save the data array")

        self.add_actions(self.file_menu, (load_file_action,))

        self.help_menu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About",
            shortcut='F1', slot=self.on_about,
            tip='About KMTEditor')
        self.add_actions(self.help_menu, (about_action,))

    def closeEvent(self, event):
        if self.unsaved_changes_exist:
            reply = QMessageBox.question(self, 'Message', "There are unsaved changes. Are you sure you want to quit?",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

            if reply == QMessageBox.Yes:
                event.accept()
            else:
                event.ignore()

def main():
    app = QApplication([])   # Create an application
    app.setWindowIcon(QIcon('Resources/kmticon.png'))

    parser = argparse.ArgumentParser(description='KMTEditor', add_help=False)
    parser.add_argument('fname', nargs=1, type=str, help='name of the netcdf4 data file')
    parser.add_argument('-s',    nargs=1, type=int, help='size of the view in number of pixels', default=[60])
    args = parser.parse_args()

    mw = KMTEditor(args.fname[0], "kmt", dwx=args.s[0], dwy=args.s[0])
    mw.show()     # Render the window
    mw.raise_()   # Bring the PyQt4 window to the front
    app.exec_()   # Run the application loop

if __name__ == "__main__":
    main()


import operator
from queue import PriorityQueue

import numpy as np
import torch

from params import JOIN_TOKEN

def greedy_decode(vocab, decoder, with_attention, trg_indexes, hidden, cell, enc_output, eos_token, device,
                  max_len=100):
    """

    Args:
        vocab: vocabulary
        decoder: decoder model
        with_attention: bool value marking if decoder is with attention or not
        trg_indexes: target indexes
        hidden: hidden state
        cell: cell state
        enc_output: encoder output
        eos_token: index of the EOS token
        device: device
        max_len: max length of the generated sequence

    Returns: a generated sequence

    """
    trg = []
    enc_output = enc_output.permute(1, 0, 2)
    decoder_h = (hidden, cell)
    for i in range(max_len):
        trg_tensor = torch.LongTensor([trg_indexes[-1]]).to(device)
        if with_attention:
            predicted, decoder_h, attn_weights = decoder(trg_tensor, decoder_h, enc_output)
        else:
            predicted, hidden, cell = decoder(trg_tensor, hidden, cell)
        pred_token = predicted.argmax(1).item()
        trg.append(pred_token)
        trg_indexes = torch.cat((trg_indexes, torch.LongTensor([pred_token]).to(device)), 0)
        if pred_token == eos_token:
            break
    return JOIN_TOKEN.join([vocab.itos[i] for i in trg])

class BeamSearchNode(object):
    def __init__(self, hidden_state, previous_node, word_ids, log_prob, length):
        '''
        :param hiddenstate: hidden state
        :param previousNode: previous BeamSearchNode
        :param wordId: indexes of the generated words
        :param logProb: log probabilities of the generated words
        :param length: length of the generated sequence
        '''
        self.h = hidden_state
        self.prev_node = previous_node
        self.word_ids = word_ids
        self.logp = log_prob
        self.length = length

    def eval(self, alpha=1.0):
        reward = np.random.uniform(0.1, 10 ** (-20))
        # Add here a function for shaping a reward
        return self.logp / float(self.length - 1 + 1e-6) + alpha * reward

def beam_decode_mixed(vocab, beam_width, max_len, max_sentence_count, models, with_attention, lm_weights,
                      stylized_score_tensors, target_tensor, encoder_hiddens, encoder_outputs, sos_token, eos_token,
                      device):
    """
    Args:
        vocab: vocabulary
        beam_width: width of the beam
        max_len: max length of a generated sequence
        max_sentence_count: max sentence counter
        models: array of the models for sequence generation
        with_attention: a bool value, which indicated if the decoder is with attention or not
        lm_weights: stylized weights for the language models
        stylized_score_tensors: tensors for stylized generation
        target_tensor: target tensor
        encoder_hiddens: last hidden state from the encoder
        encoder_outputs: encoder outputs
        sos_token: index of the SOS token
        eos_token: index of the EOS token
        device: device

    Returns: generated sequences

    """
    # can be 1 or several decoders
    if len(models) != 1:
        assert len(models) == len(lm_weights), "Number of model decoders should be equal to the number of scores"
    else:
        assert len(lm_weights) - 1 == len(
            stylized_score_tensors), "Number of styles should be equal to number of discrete distribution "

    assert sum(lm_weights) == 1, "Sum of scores must be 1"

    decoded_batch = []
    max_len = max(max_len, 2)
    beam_width = max(beam_width, 2)
    sentences = ""
    for idx in range(target_tensor.size(0)):
        if isinstance(encoder_hiddens, tuple):
            decoder_hidden = (encoder_hiddens[0][:, idx, :].unsqueeze(1), encoder_hiddens[1][:, idx, :].unsqueeze(1))
        else:
            decoder_hidden = encoder_hiddens[:, idx, :].unsqueeze(1)
        encoder_output = encoder_outputs[:, idx, :].unsqueeze(1)

        decoder_input = torch.LongTensor([sos_token]).to(device)
        node = BeamSearchNode(decoder_hidden, None, decoder_input, 0, 1)
        nodes_queue = PriorityQueue()
        nodes_queue.put((-node.eval(), node))
        end_nodes = []
        while not nodes_queue.empty():
            score, n = nodes_queue.get()
            if len(end_nodes) >= max_sentence_count:
                break
            if n.length >= max_len or n.word_ids[-1] == eos_token:
                end_nodes.append((score, n))
                continue
            decoder_input = torch.LongTensor([n.word_ids[-1]]).to(device)
            decoder_hidden = n.h
            decoder_hs = []
            for i in range(len(models)):
                if models[i].__class__.__name__ == "Seq2Seq" and with_attention:
                    decoder_output, (decoder_h, cell), _ = models[i].decoder(decoder_input, decoder_hidden,
                                                                             encoder_output)
                else:
                    decoder_output, decoder_h, cell = models[i].decoder(decoder_input, decoder_hidden[0],
                                                                        decoder_hidden[1])
                decoder_hs.append((decoder_h, cell))
                if i == 0:
                    decoder_outputs = decoder_output
                else:
                    decoder_outputs = torch.cat((decoder_outputs, decoder_output), 0)
            if len(models) == 1:
                dec_output = decoder_outputs
                for i in range(len(stylized_score_tensors)):
                    stylized_out = []
                    # stylized_score_tensors is a list of tensors of size [len(vocab)]
                    for coef in range(stylized_score_tensors[i].size(0)):
                        stylized_out.append(torch.exp(stylized_score_tensors[i][coef]) + dec_output[0][coef])
                    stylized_out = torch.FloatTensor(stylized_out).to(device).unsqueeze(0)
                    decoder_outputs = torch.cat((decoder_outputs, stylized_out), 0)
            decoder_outputs = decoder_outputs.transpose(0, 1)

            score = torch.FloatTensor(lm_weights).to(device).unsqueeze(1)
            decoder_out_scored = torch.matmul(decoder_outputs, score).transpose(0, 1)
            for i in range(len(decoder_hs)):
                hidden = decoder_hs[i][0]
                cell = decoder_hs[i][1]
                if i == 0:
                    new_hidden = hidden * lm_weights[i]
                    new_cell = cell * lm_weights[i]
                else:
                    new_hidden = torch.add(new_hidden, hidden * lm_weights[i])
                    new_cell = torch.add(new_cell, cell * lm_weights[i])

            log_prob, indexes = torch.topk(decoder_out_scored, beam_width)
            decoder_hidden = (new_hidden, new_cell)
            for new_k in range(beam_width):
                decoded_t = indexes[0][new_k].unsqueeze(0)
                log_p = log_prob[0][new_k].item()
                decoded_t = torch.cat((n.word_ids, decoded_t), 0)
                node = BeamSearchNode(decoder_hidden, n, decoded_t, n.logp + log_p, n.length + 1)
                score = -node.eval()
                nodes_queue.put((score, node))

        for score, n in sorted(end_nodes, key=operator.itemgetter(0)):
            utterance = n.word_ids
            sentence = [vocab.itos[i] for i in utterance]
            sentences += JOIN_TOKEN.join(sentence) + "<eos>"
            decoded_batch.append(sentence)
    return sentences

def beam_decode(vocab, beam_width, max_len, topk, decoder, with_attention, target_tensor, decoder_hiddens,
                encoder_output, sos_token, eos_token, device):
    '''
    :param target_tensor: target indexes tensor of shape [B, T] where B is the batch size and T is the maximum length of the output sentence
    :param decoder_hidden: input tensor of shape [1, B, H] for start of the decoding
    :param encoder_outputs: if you are using attention mechanism you can pass encoder outputs, [T, B, H] where T is the maximum length of input sentence
    :return: decoded_batch
    '''
    decoded_batch = []
    sentences = ""

    # decoding goes sentence by sentence
    for idx in range(target_tensor.size(0)):
        decoder_hidden = decoder_hiddens

        # Start with the start of the sentence token
        decoder_input = torch.LongTensor([sos_token]).to(device)
        # Number of sentence to generate
        endnodes = []
        number_required = max(topk, 1)

        # starting node -  hidden vector, previous node, word id, logp, length
        node = BeamSearchNode(decoder_hidden, None, decoder_input, 0, 1)
        nodes = PriorityQueue()

        # start the queue
        nodes.put((-node.eval(), node))

        # start beam search
        while True:
            # fetch the best node
            score, n = nodes.get()
            decoder_input = n.word_ids
            decoder_hidden = n.h

            if (n.word_ids.item() == eos_token and n.prev_node != None) or n.length >= max_len:
                endnodes.append((score, n))
                # if we reached maximum of sentences required
                if len(endnodes) >= number_required:
                    break
                else:
                    continue

            if with_attention:
                decoder_output, decoder_hidden, attn_weights = decoder(decoder_input, decoder_hidden, encoder_output)
            else:
                # decode for one step using decoder
                decoder_output, decoder_h, cell = decoder(decoder_input, decoder_hidden[0], decoder_hidden[1])
                decoder_hidden = (decoder_h, cell)
            # PUT HERE REAL BEAM SEARCH OF TOP
            log_prob, indexes = torch.topk(decoder_output, beam_width)
            nextnodes = []

            for new_k in range(beam_width):
                decoded_t = indexes[0][new_k].unsqueeze(0)
                log_p = log_prob[0][new_k].item()
                node = BeamSearchNode(decoder_hidden, n, decoded_t, n.logp + log_p, n.length + 1)
                score = -node.eval()
                nextnodes.append((score, node))

            # put them into queue
            for i in range(len(nextnodes)):
                score, nn = nextnodes[i]
                nodes.put((score, nn))

        # choose nbest paths, back trace them
        if len(endnodes) == 0:
            endnodes = [nodes.get() for _ in range(topk)]

        for score, n in sorted(endnodes, key=operator.itemgetter(0)):
            utterance = [n.word_ids]
            # back trace
            while n.prev_node is not None:
                n = n.prev_node
                utterance.append(n.word_ids)
            utterance = utterance[::-1]
            sentence = [vocab.itos[i] for i in utterance]
            sentences += ' '.join(sentence) + " <eos>\n"
            decoded_batch.append(sentence)

    return sentences


import matplotlib.pyplot as plt
import numpy as np

train = []
dev = []

with open('example_losses.txt', 'r') as f:
    for line in f:
        if line.startswith("Epoch"):
            continue
        line = line[line.find(':'):]
        train.append(float(line[2:8]))
        line = line[line.find("s:")+3:]
        dev.append(float(line[0:6]))

fig, ax = plt.subplots()
ax.plot(np.arange(250), np.array(train), label='train_loss')
ax.plot(np.arange(250), np.array(dev), label='dev_loss')
ax.set_xlabel('# of epochs')
ax.set_ylabel('Loss')
ax.legend()
plt.grid()
plt.show()


#import json file

import json

#open the json file
#store it in dictionary
#append the content need to be added
#print it to check

with open('ex5.json') as json_file:
    ex5 = json.load(json_file)
    ex5[2]['batters']['batter'].append({'id': '1003', 'type': 'Coffee'})
    print(ex5)

#open the file in Write mode
#dumb the updated value to the existing json file

with open('ex5.json','w') as json_file:
    json.dump(ex5,json_file)


# 네이버 영화 평점 크롤러

import requests
from bs4 import BeautifulSoup
import random
import time
from itertools import chain
import pandas as pd
import os
import argparse
from tqdm import tqdm

def naver_movie_comment_crawler(BASE_URL, TABLE_, TITLE_, SCORE_, COMMENT_, PAGE):
    url = BASE_URL.format(PAGE)
    res = requests.get(url)
    if res.status_code == 200:
        soup = BeautifulSoup(res.text, 'lxml')
        tds = soup.select(TABLE_)
        list_ = []
        for td in tds:
            title = td.select_one(TITLE_).text.strip()
            if title == '':
                title = td.select_one(TITLE_).next_sibling.strip()

            score = td.select_one(SCORE_).text.strip()
            if score == '':
                score = td.select_one(SCORE_).next_sibling.strip()

            comment = td.select_one(COMMENT_).text.strip()
            if comment == '':
                comment = td.select_one(COMMENT_).next_sibling.strip()

            if title != '' and score != '' and comment != '':
                list_.append((title, int(score), comment))

        return list_

    else:
        print("Webpage not available.")

def page_crawling(start_page, end_page):

    BASE_URL = 'https://movie.naver.com/movie/point/af/list.naver?&page={}'
    TABLE_ = 'td.title'
    TITLE_ = 'a.movie.color_b'
    SCORE_ = 'em'
    COMMENT_ = 'br'

    comment_list = []
    for page in tqdm(range(start_page, end_page)):
        crw = naver_movie_comment_crawler(BASE_URL, TABLE_, TITLE_, SCORE_, COMMENT_, page)
        comment_list.append(crw)
        interval = round(random.uniform(0.2, 1.2), 2)
        time.sleep(interval)

    df = pd.DataFrame(list(chain(*comment_list)), columns=['title', 'score', 'comment'])
    df = df.dropna()
    return df

def select_data_df_and_toCSV(df, postive_score_cut, negative_score_cut):
    df['label'] = list(map(lambda x: 1 if int(x) >= postive_score_cut else (0 if int(x) <= negative_score_cut else 2), df['score'].values))
    df = df[df['label'] != 2]
    df.to_csv('data/movie_naver.csv', encoding='utf-8-sig', index=False)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('--start_page', '-s',type=int, default=1)
    parser.add_argument('--end_page', '-e',type=int, default=10)
    args = parser.parse_args()

    df = page_crawling(args.start_page, args.end_page)

    if not os.path.isdir('data'):
        os.mkdir('data')
    select_data_df_and_toCSV(df,
                             postive_score_cut=7,
                             negative_score_cut=3)

    print(f"{len(df)} lines are parsed.")
    print("--FINISHED--")

    ### 참조 : https://ysyblog.tistory.com/59
    # BASE_URL = 'https://movie.naver.com/movie/point/af/list.naver?&page={}'
    # comment_list = []
    # for page in tqdm(range(args.start_page, args.end_page)):
    #     url = BASE_URL.format(page)
    #     res = requests.get(url)
    #     if res.status_code == 200:
    #         soup = BeautifulSoup(res.text, 'lxml')
    #         tds = soup.select('table.list_netizen > tbody > tr > td.title')
    #         for td in tds:
    #             movie_title = td.select_one('a.movie').text.strip()
    #             # link = td.select_one('a.movie').get('href')
    #             # link = parse.urljoin(BASE_URL, link)
    #             score = td.select_one('div.list_netizen_score > em').text.strip()
    #             comment = td.select_one('br').next_sibling.strip()
    #             comment_list.append((movie_title, score, comment))
    #         interval = round(random.uniform(0.2, 1.2), 2)
    #         time.sleep(interval)
    #
    # if not os.path.isdir('data'):
    #     os.mkdir('data')
    #
    # df = pd.DataFrame(comment_list, columns=['title', 'score', 'comment'])
    # postive_score_cut = 7
    # negative_score_cut = 3
    # df['label'] = list(map(lambda x: 1 if int(x) >= postive_score_cut else (0 if int(x) <= negative_score_cut else 2), df['score'].values))
    # df = df[df['label'] != 2]
    # df.to_csv('data/movie_naver.csv', encoding='utf-8-sig', index=False)
    # print(f"{len(df)} lines are parsed.")
    # print("--FINISHED--")