import torch
import numpy as np
from torch import nn
import torchvision
import torch.nn.functional as F
from pathlib import Path
from asteroid import torch_utils
from asteroid.engine.optimizers import make_optimizer
from asteroid_filterbanks import transforms

# Reference: https://github.com/bill9800/speech_separation/blob/master/model/lib/utils.py
def generate_cRM(Y, S):
    """Generate CRM.

    Args:
        Y (torch.Tensor): mixed/noisy stft.
        S (torch.Tensor): clean stft.

    Returns:
        M (torch.Tensor): structed cRM.

    """
    M = torch.zeros(Y.shape)
    epsilon = 1e-8
    # real part
    M_real = (Y[..., 0] * S[..., 0]) + (Y[..., 1] * S[..., 1])
    square_real = (Y[..., 0] ** 2) + (Y[..., 1] ** 2)
    M_real = M_real / (square_real + epsilon)
    M[..., 0] = M_real
    # imaginary part
    M_img = (Y[..., 0] * S[..., 1]) - (Y[..., 1] * S[..., 0])
    square_img = (Y[..., 0] ** 2) + (Y[..., 1] ** 2)
    M_img = M_img / (square_img + epsilon)
    M[..., 1] = M_img
    return M

def cRM_tanh_compress(M, K=10, C=0.1):
    """CRM tanh compress.

    Args:
        M (torch.Tensor): crm.
        K (torch.Tensor): parameter to control the compression.
        C (torch.Tensor): parameter to control the compression.

    Returns:
        crm (torch.Tensor): compressed crm.

    """

    numerator = 1 - torch.exp(-C * M)
    numerator[numerator == inf] = 1
    numerator[numerator == -inf] = -1
    denominator = 1 + torch.exp(-C * M)
    denominator[denominator == inf] = 1
    denominator[denominator == -inf] = -1
    crm = K * (numerator / denominator)

    return crm

def cRM_tanh_recover(O, K=10, C=0.1):
    """CRM tanh recover.

    Args:
        O (torch.Tensor): predicted compressed crm.
        K (torch.Tensor): parameter to control the compression.
        C (torch.Tensor): parameter to control the compression.

    Returns:
        M (torch.Tensor): uncompressed crm.

    """

    numerator = K - O
    denominator = K + O
    M = -((1.0 / C) * torch.log((numerator / denominator)))

    return M

def fast_cRM(Fclean, Fmix, K=10, C=0.1):
    """Fast CRM.

    Args:
        Fmix (torch.Tensor): mixed/noisy stft.
        Fclean (torch.Tensor): clean stft.
        K (torch.Tensor): parameter to control the compression.
        C (torch.Tensor): parameter to control the compression.

    Returns:
        crm (torch.Tensor): compressed crm.

    """
    M = generate_cRM(Fmix, Fclean)
    crm = cRM_tanh_compress(M, K, C)
    return crm

def fast_icRM(Y, crm, K=10, C=0.1):
    """fast iCRM.

    Args:
        Y (torch.Tensor): mixed/noised stft.
        crm (torch.Tensor): DNN output of compressed crm.
        K (torch.Tensor): parameter to control the compression.
        C (torch.Tensor): parameter to control the compression.

    Returns:
        S (torch.Tensor): clean stft.

    """
    M = cRM_tanh_recover(crm, K, C)
    S = torch.zeros(M.shape)
    S[:, 0, ...] = (M[:, 0, ...] * Y[:, 0, ...]) - (M[:, 1, ...] * Y[:, 1, ...])
    S[:, 1, ...] = (M[:, 0, ...] * Y[:, 1, ...]) + (M[:, 1, ...] * Y[:, 0, ...])
    return S

class Audio_Model(nn.Module):
    def __init__(self, last_shape=8):
        super(Audio_Model, self).__init__()

        # Audio model layers , name of layers as per table 1 given in paper.

        self.conv1 = nn.Conv2d(
            2,
            96,
            kernel_size=(1, 7),
            padding=self.get_padding((1, 7), (1, 1)),
            dilation=(1, 1),
        )

        self.conv2 = nn.Conv2d(
            96,
            96,
            kernel_size=(7, 1),
            padding=self.get_padding((7, 1), (1, 1)),
            dilation=(1, 1),
        )

        self.conv3 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (1, 1)),
            dilation=(1, 1),
        )

        self.conv4 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (2, 1)),
            dilation=(2, 1),
        )

        self.conv5 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (4, 1)),
            dilation=(4, 1),
        )

        self.conv6 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (8, 1)),
            dilation=(8, 1),
        )

        self.conv7 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (16, 1)),
            dilation=(16, 1),
        )

        self.conv8 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (32, 1)),
            dilation=(32, 1),
        )

        self.conv9 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (1, 1)),
            dilation=(1, 1),
        )

        self.conv10 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (2, 2)),
            dilation=(2, 2),
        )

        self.conv11 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (4, 4)),
            dilation=(4, 4),
        )

        self.conv12 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (8, 8)),
            dilation=(8, 8),
        )

        self.conv13 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (16, 16)),
            dilation=(16, 16),
        )

        self.conv14 = nn.Conv2d(
            96,
            96,
            kernel_size=(5, 5),
            padding=self.get_padding((5, 5), (32, 32)),
            dilation=(32, 32),
        )

        self.conv15 = nn.Conv2d(
            96,
            last_shape,
            kernel_size=(1, 1),
            padding=self.get_padding((1, 1), (1, 1)),
            dilation=(1, 1),
        )

        # Batch normalization layers

        self.batch_norm1 = nn.BatchNorm2d(96)
        self.batch_norm2 = nn.BatchNorm2d(96)
        self.batch_norm3 = nn.BatchNorm2d(96)
        self.batch_norm4 = nn.BatchNorm2d(96)
        self.batch_norm5 = nn.BatchNorm2d(96)
        self.batch_norm6 = nn.BatchNorm2d(96)
        self.batch_norm7 = nn.BatchNorm2d(96)
        self.batch_norm8 = nn.BatchNorm2d(96)
        self.batch_norm9 = nn.BatchNorm2d(96)
        self.batch_norm10 = nn.BatchNorm2d(96)
        self.batch_norm11 = nn.BatchNorm2d(96)
        self.batch_norm11 = nn.BatchNorm2d(96)
        self.batch_norm12 = nn.BatchNorm2d(96)
        self.batch_norm13 = nn.BatchNorm2d(96)
        self.batch_norm14 = nn.BatchNorm2d(96)
        self.batch_norm15 = nn.BatchNorm2d(last_shape)

    def get_padding(self, kernel_size, dilation):
        padding = (
            ((dilation[0]) * (kernel_size[0] - 1)) // 2,
            ((dilation[1]) * (kernel_size[1] - 1)) // 2,
        )
        return padding

    def forward(self, input_audio):
        # input audio will be (2,298,257)

        output_layer = F.relu(self.batch_norm1(self.conv1(input_audio)))
        output_layer = F.relu(self.batch_norm2(self.conv2(output_layer)))
        output_layer = F.relu(self.batch_norm3(self.conv3(output_layer)))
        output_layer = F.relu(self.batch_norm4(self.conv4(output_layer)))
        output_layer = F.relu(self.batch_norm5(self.conv5(output_layer)))
        output_layer = F.relu(self.batch_norm6(self.conv6(output_layer)))
        output_layer = F.relu(self.batch_norm7(self.conv7(output_layer)))
        output_layer = F.relu(self.batch_norm8(self.conv8(output_layer)))
        output_layer = F.relu(self.batch_norm9(self.conv9(output_layer)))
        output_layer = F.relu(self.batch_norm10(self.conv10(output_layer)))
        output_layer = F.relu(self.batch_norm11(self.conv11(output_layer)))
        output_layer = F.relu(self.batch_norm12(self.conv12(output_layer)))
        output_layer = F.relu(self.batch_norm13(self.conv13(output_layer)))
        output_layer = F.relu(self.batch_norm14(self.conv14(output_layer)))
        output_layer = F.relu(self.batch_norm15(self.conv15(output_layer)))

        # output_layer will be (N,8,298,257)
        # we want it to be (N,8*257,298,1)
        batch_size = output_layer.size(0)  # N
        height = output_layer.size(2)  # 298

        output_layer = output_layer.transpose(-1, -2).reshape((batch_size, -1, height, 1))
        return output_layer

class Video_Model(nn.Module):
    def __init__(self, last_shape=256):
        super(Video_Model, self).__init__()

        self.conv1 = nn.Conv2d(
            512,
            256,
            kernel_size=(7, 1),
            padding=self.get_padding((7, 1), (1, 1)),
            dilation=(1, 1),
        )

        self.conv2 = nn.Conv2d(
            256,
            256,
            kernel_size=(5, 1),
            padding=self.get_padding((5, 1), (1, 1)),
            dilation=(1, 1),
        )

        self.conv3 = nn.Conv2d(
            256,
            256,
            kernel_size=(5, 1),
            padding=self.get_padding((5, 1), (2, 1)),
            dilation=(2, 1),
        )

        self.conv4 = nn.Conv2d(
            256,
            256,
            kernel_size=(5, 1),
            padding=self.get_padding((5, 1), (4, 1)),
            dilation=(4, 1),
        )

        self.conv5 = nn.Conv2d(
            256,
            256,
            kernel_size=(5, 1),
            padding=self.get_padding((5, 1), (8, 1)),
            dilation=(8, 1),
        )

        self.conv6 = nn.Conv2d(
            256,
            256,
            kernel_size=(5, 1),
            padding=self.get_padding((5, 1), (16, 1)),
            dilation=(16, 1),
        )

        # Batch normalization layers

        self.batch_norm1 = nn.BatchNorm2d(256)
        self.batch_norm2 = nn.BatchNorm2d(256)
        self.batch_norm3 = nn.BatchNorm2d(256)
        self.batch_norm4 = nn.BatchNorm2d(256)
        self.batch_norm5 = nn.BatchNorm2d(256)
        self.batch_norm6 = nn.BatchNorm2d(last_shape)

    def get_padding(self, kernel_size, dilation):
        padding = (
            ((dilation[0]) * (kernel_size[0] - 1)) // 2,
            ((dilation[1]) * (kernel_size[1] - 1)) // 2,
        )
        return padding

    def forward(self, input_video):
        # input video will be (512,75,1)
        if len(input_video.shape) == 3:
            input_video = input_video.unsqueeze(1)
        # input_video = torch.transpose(input_video,1,3) # (1,75,512)
        # input_video = self.linear_for_512_to_1024(input_video) # (1,75,1024)

        input_video = torch.transpose(input_video, 1, 3)  # (1024,75,1)

        output_layer = F.relu(self.batch_norm1(self.conv1(input_video)))
        output_layer = F.relu(self.batch_norm2(self.conv2(output_layer)))
        output_layer = F.relu(self.batch_norm3(self.conv3(output_layer)))
        output_layer = F.relu(self.batch_norm4(self.conv4(output_layer)))
        output_layer = F.relu(self.batch_norm5(self.conv5(output_layer)))
        output_layer = F.relu(self.batch_norm6(self.conv6(output_layer)))

        # for upsampling , as mentioned in paper
        output_layer = nn.functional.interpolate(output_layer, size=(298, 1), mode="nearest")

        return output_layer

# so now , video_output is (N,256,298,1)
# and audio_output is  (N,8*257,298,1)
# where N = batch_size

class Audio_Visual_Fusion(nn.Module):
    """Audio Visual Speech Separation model as described in [1].
    All default values are the same as paper.

        Args:
            num_person (int): total number of persons (as i/o).
            device (torch.Device): device used to return the final tensor.
            audio_last_shape (int): relevant last shape for tensor in audio network.
            video_last_shape (int): relevant last shape for tensor in video network.
            input_spectrogram_shape (tuple(int)): shape of input spectrogram.

        References:
            [1]: 'Looking to Listen at the Cocktail Party:
            A Speaker-Independent Audio-Visual Model for Speech Separation' Ephrat et. al
            https://arxiv.org/abs/1804.03619
    """

    def __init__(
        self,
        num_person=2,
        device=None,
        audio_last_shape=8,
        video_last_shape=256,
        input_spectrogram_shape=(298, 257, 2),
    ):
        if isinstance(device, str):
            device = torch.device(device)

        self.device = device
        super(Audio_Visual_Fusion, self).__init__()
        self.num_person = num_person
        self.input_dim = (
            audio_last_shape * input_spectrogram_shape[1] + video_last_shape * self.num_person
        )

        self.audio_output = Audio_Model(last_shape=audio_last_shape)
        self.video_output = Video_Model(last_shape=video_last_shape)

        self.lstm = nn.LSTM(
            self.input_dim,
            400,
            num_layers=1,
            bias=True,
            batch_first=True,
            bidirectional=True,
        )

        self.fc1 = nn.Linear(400, 600)
        torch.nn.init.xavier_uniform_(self.fc1.weight)
        self.fc2 = nn.Linear(600, 600)
        torch.nn.init.xavier_uniform_(self.fc2.weight)
        self.fc3 = nn.Linear(600, 600)
        torch.nn.init.xavier_uniform_(self.fc3.weight)

        self.complex_mask_layer = nn.Linear(600, 2 * 257 * self.num_person)
        torch.nn.init.xavier_uniform_(self.complex_mask_layer.weight)

        self.drop1 = nn.Dropout(0.2)
        self.drop2 = nn.Dropout(0.2)
        self.drop3 = nn.Dropout(0.2)

        self.batch_norm1 = nn.BatchNorm1d(298)
        self.batch_norm2 = nn.BatchNorm1d(298)
        self.batch_norm3 = nn.BatchNorm1d(298)

    def forward(self, input_audio, input_video):
        # input_audio will be (N,514,298)
        # input_video will be list of size = num_person , so each item of list will be of (N,512,75,1)

        input_audio = transforms.to_torchaudio(input_audio).transpose(1, 3)
        audio_out = self.audio_output(input_audio)
        # audio_out will be (N,256,298,1)
        AVFusion = [audio_out]
        for i in range(self.num_person):
            video_out = self.video_output(input_video[i])
            AVFusion.append(video_out)

        mixed_av = torch.cat(AVFusion, dim=1)

        mixed_av = mixed_av.squeeze(3)  # (N,input_dim,298)
        mixed_av = torch.transpose(mixed_av, 1, 2)  # (N,298,input_dim)

        self.lstm.flatten_parameters()
        mixed_av, (h, c) = self.lstm(mixed_av)
        mixed_av = mixed_av[..., :400] + mixed_av[..., 400:]

        mixed_av = self.batch_norm1((F.relu(self.fc1(mixed_av))))
        mixed_av = self.drop1(mixed_av)

        mixed_av = self.batch_norm2(F.relu(self.fc2(mixed_av)))
        mixed_av = self.drop2(mixed_av)

        mixed_av = self.batch_norm3(F.relu(self.fc3(mixed_av)))  # (N,298,600)
        mixed_av = self.drop3(mixed_av)

        complex_mask = torch.sigmoid(self.complex_mask_layer(mixed_av))  # (N,298,2*257*num_person)

        batch_size = complex_mask.size(0)  # N
        complex_mask = complex_mask.view(batch_size, 298, 2, 257, self.num_person).transpose(1, 2)

        output_audio = torch.zeros_like(complex_mask, device=self.device)
        for i in range(self.num_person):
            output_audio[..., i] = fast_icRM(input_audio, complex_mask[..., i])

        output_audio = output_audio.permute(0, 4, 1, 3, 2).reshape(
            batch_size, self.num_person, 514, 298
        )
        return output_audio

def make_model_and_optimizer(conf, gpu_ids=[0]):
    """Define model and optimizer.

    Args:
        conf: Configuration for model and optimizer.

    Returns:
        model, optimizer
    """
    device = torch.device(conf["training"]["device"])
    model = Audio_Visual_Fusion(conf["main_args"]["n_src"], device)
    model = model.to(device)
    device_count = torch.cuda.device_count()
    if len(gpu_ids) > 1 and device_count > 1:
        if len(gpu_ids) != device_count:
            print(f"Using {gpu_ids} GPUs")
        else:
            print(f"Using all {device_count} GPUs")
        model = torch.nn.DataParallel(model, device_ids=gpu_ids)

    optimizer = make_optimizer(model.parameters(), **conf["optim"])
    return model, optimizer

def load_best_model(train_conf, exp_dir):
    """Load best model.
    NOTE: This function is not needed during training. Catalyst has
    a `resume` parameter that takes in the logdir location.

    Args:
        train_conf: Configuration used during training.
        exp_dir: Logdir created by Catalyst.

    Returns:
        model
    """
    model, optimizer = make_model_and_optimizer(train_conf)

    # Catalyst stores the best model as: logdir/checkpoints/best_full.pth
    exp_dir = Path(exp_dir) if isinstance(exp_dir, str) else exp_dir
    best_model_path = exp_dir / "checkpoints" / "best_full.pth"
    if not best_model_path.is_file():
        print(f"No best path in logdir: {exp_dir}. Initializing model...")
        return model

    checkpoint = torch.load(best_model_path)
    model = torch_utils.load_state_dict_in(checkpoint["model_state_dict"], model)
    return model


import os
import requests
import subprocess
import re
import sys

# Radarr API key, host and port
RADARR_API_KEY = "RADARR API KEY"
RADARR_HOST = "LOCALHOST"
RADARR_PORT = "7878"

# Directory to scan for video files
SCAN_DIR = r"C:\PATH"

# Track processed, matched, unmonitored, and already unmonitored files
processed_files = 0
matched_files = 0
unmonitored_files = []
already_unmonitored_files = []

def get_video_info(video_file):
    """Get video codec and resolution using ffprobe"""
    try:
        cmd = ["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
            "stream=codec_name,height,width", "-of", "csv=p=0", video_file]
        output = subprocess.check_output(cmd).decode('utf-8').strip().split(',')
        return output[0], (int(output[1]), int(output[2]))
    except Exception as e:
        print(f"Error getting video info for {video_file}: {e}")
        return None, (0, 0)

def set_movie_unmonitored(imdb_id, filename):
    """Flag a movie as unmonitored in Radarr"""
    try:
        response = requests.get(f"http://{RADARR_HOST}:{RADARR_PORT}/api/v3/movie?apikey={RADARR_API_KEY}")
        response.raise_for_status()
    except Exception as e:
        print(f"Error getting movie list from Radarr: {e}")
        return

    movies = response.json()
    movie_found = False

    for movie in movies:
        # Check if 'imdbId' key exists in the movie
        if 'imdbId' in movie and movie['imdbId'] == imdb_id:
            movie_found = True
            movie_id = movie['id']

            if movie['monitored']:
                movie['monitored'] = False
                unmonitored_files.append(filename)

                try:
                    response = requests.put(f"http://{RADARR_HOST}:{RADARR_PORT}/api/v3/movie/{movie_id}?apikey={RADARR_API_KEY}", json=movie)
                    response.raise_for_status()
                except Exception as e:
                    print(f"Error updating movie in Radarr: {e}")
                else:
                    print(f"Flagged {imdb_id} as unmonitored in Radarr.")
            else:
                already_unmonitored_files.append(filename)
                print(f"{imdb_id} is already unmonitored in Radarr. Continuing to the next movie.")

    if not movie_found:
        print(f"Movie with imdb id {imdb_id} not found in Radarr.")

def scan_directory():
    """Walk through directory and process video files"""
    global processed_files, matched_files
    for dirpath, dirnames, filenames in os.walk(SCAN_DIR):
        for filename in filenames:
            processed_files += 1
            if filename.endswith((".mp4", ".mkv", ".avi", ".mov", ".flv")):
                # Normalize the file path
                video_file = os.path.normpath(os.path.join(dirpath, filename))
                print(f"Processing {video_file}...")
                codec, resolution = get_video_info(video_file)
                if codec and codec.lower() == "hevc" and resolution == (3840, 2160):
                    matched_files += 1
                    print(f"{filename} is H265 encoded and in 4K resolution.")
                    match = re.search(r'imdb-(tt\d+)', filename)
                    if match:
                        imdb_id = match.group(1)
                        set_movie_unmonitored(imdb_id, filename)

def main():
    """Main function"""
    if not RADARR_API_KEY:
        print("Please set your Radarr API key.")
        sys.exit(1)
    scan_directory()
    print(f"\nProcessed {processed_files} files")
    print(f"{matched_files} Files matched 4K resolution and HVEC encoding\n")
    print("These files were un-monitored:")
    for file in unmonitored_files:
        print(file)
    print("\nThese files were already un-monitored:")
    for file in already_unmonitored_files:
        print(file)

if __name__ == "__main__":
    main()


import os
import re
import sys
import argparse
import subprocess
from time import sleep
from xml.etree import ElementTree

try:
    import youtube_dl

    ydl = youtube_dl.YoutubeDL(params={
        'noplaylist': True,
        'quiet': True,
    })
    ydl_selector = ydl.build_format_selector('bestaudio/best')
except ImportError:
    youtube_dl = None

NS = '{http://xspf.org/ns/0/}'
EXTS = ['mp3', 'ogg', 'opus', 'mp4', 'm4a', 'wav', 'flac', 'wma']
CHARS = re.compile('[^a-z0-9 ]')

__version__ = '0.0.0'

class DownloadPool(set):
    def log(self, s):
        print(s, file=sys.stderr, end='\r')

    def download(self, url, path):
        self.add(subprocess.Popen(['curl', url, '-s', '-o', path]))

    def poll(self):
        for p in list(self):
            if p.poll() is not None:
                self.remove(p)
        return len(self)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            while self.poll():
                self.log('{} downloads still active'.format(len(self)))
                sleep(5)
        else:
            for p in self:
                p.kill()

def iter_files(folder):
    for dirpath, dirnames, filenames in os.walk(folder):
        for filename in filenames:
            if filename.rsplit('.', 1)[-1] in EXTS:
                yield dirpath, filename

def simplify(s):
    s = s.lower()
    s = s.encode('ascii', errors='replace').decode('ascii')
    return CHARS.sub('', s)

def find_by_title(title, fields, files):
    for dirpath, filename in files:
        path = os.path.join(dirpath, filename)
        if (
            simplify(title) in simplify(filename)
            and all(simplify(o) in simplify(path) for o in fields)
        ):
            return path

def search_youtube(q):
    # result expires in 6h
    try:
        info = ydl.extract_info('ytsearch:' + ' '.join(q), download=False)
    except youtube_dl.utils.DownloadError:
        return None, None
    if not info['entries']:
        return None, None
    info = info['entries'][0]
    try:
        _format = next(ydl_selector({'formats': info['formats']}))
    except StopIteration:
        return None, None
    filename = '{}-{}.{}'.format(
        info['title'].replace('/', '_'),
        info['id'],
        _format['ext'],
    )
    return _format['url'], filename

def iter_tracks(src):
    root = ElementTree.parse(src).getroot()
    for e in root.iter(NS + 'track'):
        track = {}
        for tag in ['location', 'title', 'creator', 'album', 'annotation']:
            field = e.find(NS + tag)
            if field is None:
                track[tag] = None
            else:
                track[tag] = field.text
        yield track

def hard_link(location, outdir):
    os.makedirs(outdir, exist_ok=True)
    filename = os.path.basename(location)
    path = os.path.join(outdir, filename)
    os.link(location, path)
    return path

def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument('src')
    parser.add_argument('folder')
    parser.add_argument('-Y', '--youtube', action='store_true')
    parser.add_argument('-O', '--outdir')
    return parser.parse_args()

def main():
    args = parse_args()
    files = list(iter_files(args.folder))

    if args.outdir:
        os.makedirs(args.outdir)

    with DownloadPool() as pool:
        for track in iter_tracks(args.src):
            location = track['location']

            if location is None:
                context_key = ['creator', 'annotation']
                context = [track[k] for k in context_key if track[k]]
                location = find_by_title(track['title'], context, files)
                if location and args.outdir:
                    location = hard_link(location, args.outdir)

            if location is None and args.youtube and youtube_dl:
                url, filename = search_youtube(
                    [q for q in track.values() if q]
                )
                if url is None:
                    location = None
                elif args.outdir:
                    location = os.path.join(args.outdir, filename)
                    pool.download(url, location)
                else:
                    location = url

            if location is None:
                s = ' - '.join('{}: {}'.format(k, v) for k, v in track.items())
                print('# Warning: ' + s)
            else:
                print(location)

if __name__ == '__main__':
    main()


# external
import random

# internal
import scrape
import pickler

def pick(fresh, used):
    pepo = random.choice(fresh)
    if pepo in used:
        pick(fresh, used)
    else:
        used.append(pepo)
        return pepo
    return pepo

def prep(debug=True):
    # scrape for current peps
    fresh = scrape.peps()

    # get used peps list (from pickle)
    used = pickler.read('used.p')

    # make sure that there are some unused peps, if not reset used list to empty
    if used == fresh:
        used = []

    pep = pick(fresh, used)

    # put away new list of used peps
    pickler.pickleit('used.p', used)

    # add rest of url to pep
    pepo = 'https://www.python.org' + pep

    if debug:
        print('got the pep! {}'.format(pepo))
    return pepo

prep()


# TechCrunch Disrupt
# SMS Project

# import statements
import random
import pygame
import time
import inputbox
from time import sleep
from pygame import *
from Tkinter import *

#start up pygame
pygame.init()

# set font and bg color
font = pygame.font.SysFont("Calibri", 120)
font2 = pygame.font.SysFont("Calibri", 48)
font3 = pygame.font.SysFont("Calibri", 200)
font4 = pygame.font.SysFont("Calibri", 50)
font5 = pygame.font.SysFont("Calibri", 25)
black = (0,0,0)
grey = (96, 96, 96)

# set font colors
blue = (0, 0, 255)
green = (0, 255, 0)
red = (255, 0, 0)
yellow = (255, 255, 0)
purple = (102, 0, 204)
pink = (255, 105, 255)
orange = (255, 128, 0)
brown = (98, 50, 2)
white = (255, 255, 255)

# define screen
width, height = 600, 600
screen = pygame.display.set_mode((width,height))
pygame.display.set_caption("BLUE")
screen.fill(black)

# class defining each word as an object Word
class Word:

    def __init__(self):
        self.name = "name"
        self.color = "color"
        self.num = "num"

    def randomColor(self):
        self.num = random.randint(0, 8)
        self.color = colors[self.num]

    def randomString(self):
        key = random.randint(0, 8)
        self.name = words[key]

    def getColor(self):
        return self.color

    def getString(self):
        return self.name

    def getKey(self):
        return self.num

# dictionary of possibly colors
colors = {
    0: blue,
    1: red,
    2: green,
    3: yellow,
    4: purple,
    5: pink,
    6: orange,
    7: brown,
    8: white,
}

# dictionary of possible words
words = {
    0: "BLUE",
    1: "RED",
    2: "GREEN",
    3: "YELLOW",
    4: "PURPLE",
    5: "PINK",
    6: "ORANGE",
    7: "BROWN",
    8: "WHITE",
}

# creates Word object and displays in iddle of the screen
def gameplay(word):
    word.randomColor()
    word.randomString()
    text = font.render(word.getString(), 1, word.getColor())
    screen.blit(text, (300 - (text.get_width() / 2), 300 - (text.get_height() / 2)))

#creates title screen
def titlescreen():
    screen.fill(white)
    title = font3.render("BLUE", 1, black)
    screen.blit(title, (300 - (title.get_width() / 2), 300 - (title.get_height() / 2) - 50))
    subtitle = font2.render("Press Enter to begin", 1, black)
    screen.blit(subtitle, (300 - (subtitle.get_width() / 2), 300 - (subtitle.get_height() / 2) + 50))
    pygame.display.flip()

def directions():
    screen.fill(white)
    title = font4.render("DIRECTIONS", 1, black)
    screen.blit(title, (300 - (title.get_width() / 2), 100))
    subtitle = font5.render("Type the color of the word that appears on screen in under 2 seconds.", 1, black)
    screen.blit(subtitle, (300 - (subtitle.get_width() / 2), 150))
    subtitle2 = font5.render("If the answer is incorrect or time ends, the screen will turn grey.", 1, black)
    screen.blit(subtitle2, (300 - (subtitle.get_width() / 2), 180))
    subtitle3 = font5.render("There are 20 questions total.", 1, black)
    screen.blit(subtitle3, (300 - (subtitle.get_width() / 2), 210))
    subtitle4 = font5.render("Try to get the highest score possible!", 1, black)
    screen.blit(subtitle4, (300 - (subtitle.get_width() / 2), 240))
    subtitle5 = font2.render("Press Enter to continue", 1, black)
    screen.blit(subtitle5, (300 - (subtitle.get_width() / 2), 290))
    pygame.display.flip()

#runs the game
def main():
    leaving = False
    play = 0
    correct = 0
    titlescreen()
    inkey = inputbox.get_key()
    if inkey != K_RETURN:
        return
    directions()
    inkey = inputbox.get_key()
    if inkey != K_RETURN:
        return
    screen.fill(black)
    pygame.display.flip()
    while play < 21:
        clock = pygame.time.Clock()
        clock.tick()
        word = Word()
        gameplay(word)
        answer = inputbox.ask(screen, "")

        clock.tick()
        time = (2000 - clock.get_time())

        if clock.get_time() >= 2000 or answer.upper() != words[word.getKey()]:
                screen.fill(grey)
                pygame.display.flip()
                play += 1
                continue
        time = str(2000 - clock.get_time())
        text = font.render(time, 1, white)
        screen.blit(text, (50, 50))
        screen.fill(black)
        pygame.display.flip()
        play += 1
        if answer.upper() == words[word.getKey()]:
                correct += 1
    else:
        print(correct)
        correct = str(correct)
        text = font.render('Score: '+ correct, 1, white)
        screen.blit(text, (300 - (text.get_width() / 2), 300 - (text.get_height() / 2)))
        text2 = font2.render("Press Enter to play again", 1, white)
        screen.blit(text2, (300 - (text2.get_width() / 2), 300 - (text2.get_height() / 2) + 100))
        text3 = font2.render("Press Space to exit", 1, white)
        screen.blit(text3, (300 - (text3.get_width() / 2), 300 - (text3.get_height() / 2) + 150))
        pygame.display.flip()
        inkey = inputbox.get_key();
        if inkey == K_RETURN:
            main()
        elif inkey == K_SPACE:
            pass

if __name__ == '__main__': main()


# This line will get the peasant to the first mushroom.
hero.moveXY(hero.xmin, hero.ymin)

# Mushrooms have x-coordinates between xmin and xmax,
# and y-coordinates between ymin and ymax.
# Try using loops to harvest all of the mushrooms
# without typing very many lines of code.
# It can be done in less than 5 lines!
for y in range(hero.ymin, hero.ymax + 1, 10):
    for x in range(hero.xmin, hero.xmax + 1, 10):
        hero.moveXY(x, y)
# Try to have the hero.moveXY() function show up
# as few times as possible in your code.


#! /usr/bin/env python3

import asyncio
from aiogremlin import GremlinClient
from kafka import KafkaConsumer

QUERY="g.V().count()"
bad_ls_expected_result=70960
# Q1="g.V().has('type','file').count()"
# Q2="g.V().has('type','netflow').count()"
# Q3="g.V().has('type','memory').count()"
# Q4="g.V().has('type','resource').count()"
# Q5="g.V().has('type','subject').count()"
# Q6="g.V().has('type','host').count()"
# Q7="g.V().has('type','agent').count()"
# QUERIES = [Q1,Q2,Q3,Q4,Q5,Q6,Q7]
QUERIES = []

if __name__ == '__main__':
    chan = KafkaConsumer('pe')
    msg  = next(chan)
    print ("Received a signal: ", msg)

    loop = asyncio.get_event_loop()
    gc = GremlinClient(loop=loop)

    for q in QUERIES:
        e = gc.execute(q)
        r = loop.run_until_complete(e)
        print(q, "\n\t", r[0].data[0])

    execute = gc.execute(QUERY)
    result = loop.run_until_complete(execute)
    print("total nodes: ", result[0].data[0])
    print("success rate: ", result[0].data[0] / bad_ls_expected_result)

    loop.run_until_complete(gc.close())


import os
import pyaudio
import wave

FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
CHUNK = 1024
chunk = 1024
DURATION = 5

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
filename = os.path.join(BASE_DIR, '201114165.wav')
audio = pyaudio.PyAudio()
stream = audio.open(format=FORMAT, channels=CHANNELS,
                    rate=RATE, input=True,
                    frames_per_buffer=CHUNK)
print('Grabando....')
frames = list()
for i in range(0, int(RATE/CHUNK * DURATION)):
    data = stream.read(CHUNK)
    frames.append(data)
print(f'Grabacion finalizada. Archivo: {filename}')
stream.stop_stream()
stream.close()
audio.terminate()
#preparando muestras para almacenar
data_bin = b''.join(frames)  # de lista a texto binario
#guardar archivo
with wave.open(filename, 'wb') as wav:
    wav.setnchannels(CHANNELS)
    wav.setsampwidth(audio.get_sample_size(FORMAT))
    wav.setframerate(RATE)
    wav.writeframes(data_bin)
#leyendo archivo
f = wave.open(r"201114165.wav","rb")
#iniciando pyaudio
p = pyaudio.PyAudio()
#abriendo stream
stream = p.open(format = p.get_format_from_width(f.getsampwidth()),
                   channels = f.getnchannels(),
                   rate = f.getframerate(),
                   output = True)
#leyendo muestras
data = f.readframes(chunk)
#reproduciendo stream
while data:
       stream.write(data)
       data = f.readframes(chunk)
#parando stream
stream.stop_stream()
stream.close()
#cerrando pyaudio
p.terminate()


#!/bin/env/python

import pyproj
import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import cartopy.feature as cfeature
import matplotlib
import io
import matplotlib.pyplot as plt
from PIL import Image
import matplotlib.image as image
from matplotlib.gridspec import GridSpec
from matplotlib import colors
import numpy as np
import time,os,sys,multiprocessing
import multiprocessing.pool

import ncepy
from scipy import ndimage
#from netCDF4 import Dataset
import cartopy
from datetime import datetime

import netCDF4 as nc
import numpy as np
import argparse
import glob
import os
import pandas as pd
import yaml
import ncepy

def plot_world_map(lon, lat, data, vartype, cychr,thisdir):

# NA domain
    llcrnrlon = -160.0
    llcrnrlat = 15.0
    urcrnrlon = -55.0
    urcrnrlat = 65.0
    cen_lat = 35.4
    cen_lon = -105.0
    xextent = -3700000
    yextent = -2500000
    offset = 1

# set up the map background with cartopy
    extent = [-176.,0.,0.5,45.] #lonw, lone, lats, latn
    myproj=ccrs.Orthographic(central_longitude=-114, central_latitude=54.0, globe=None)

# plot generic world ma p
    fig = plt.figure(figsize=(12,10))
    gs = GridSpec(12,10,wspace=0.0,hspace=0.0)
    ax = fig.add_subplot(gs[0:12,0:8], projection=myproj)
    ax.set_extent(extent)
#    ax.stock_img()
    axes = [ax]

    fline_wd = 0.5  # line width
    fline_wd_lakes = 0.35  # line width
    falpha = 0.5    # transparency

  # natural_earth
    back_res='50m'
    back_img='off'

#  land=cfeature.NaturalEarthFeature('physical','land',back_res,
#                    edgecolor='face',facecolor=cfeature.COLORS['land'],
#                    alpha=falpha)
#   lakes=cfeature.NaturalEarthFeature('physical','lakes',back_res,
#                   edgecolor='black',facecolor='none',
#                   linewidth=fline_wd_lakes,alpha=falpha)
    coastlines=cfeature.NaturalEarthFeature('physical','coastline',
                    back_res,edgecolor='black',facecolor='none',
                    linewidth=fline_wd,alpha=falpha)
    states=cfeature.NaturalEarthFeature('cultural','admin_1_states_provinces',
                    back_res,edgecolor='black',facecolor='none',
                    linewidth=fline_wd,alpha=falpha)
    borders=cfeature.NaturalEarthFeature('cultural','admin_0_countries',
                    back_res,edgecolor='black',facecolor='none',
                    linewidth=fline_wd,alpha=falpha)

# All lat lons are earth relative, so setup the associated projection correct for that data
    transform = ccrs.RotatedPole(pole_longitude=67.0, pole_latitude=35.0)

#   ax.add_feature(lakes)
    ax.add_feature(states)
    ax.add_feature(coastlines)

    data=data
    vmin=np.min(data)
    vmax=np.max(data)
    print(vmin, vmax)
    x, y,_ = myproj.transform_points(ccrs.Geodetic(), lon, lat).T
    tmp2m_1=data

    cmap = colors.ListedColormap(['white','lightgray','gray','skyblue','dodgerblue','mediumblue',\
               'lime','limegreen','green','yellow','gold','darkorange','red','firebrick',\
               'darkred','fuchsia','darkorchid','black'])

    bounds=[0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80]

#   maxmark=72
#   intv=int(maxmark)/18
#   print(intv)
#   maxmark=76
#   bounds=range(0,int(maxmark),int(intv))
#   print(bounds)

    norm = colors.BoundaryNorm(bounds, cmap.N)

#   cs = ax.scatter(x, y, tmp2m_1,s=10, marker='o',cmap=cmap,norm=norm)
    cs = ax.scatter(x, y, s=1, marker='.')
#   cs = ax.pcolormesh(x, y, tmp2m_1,cmap=cmap,norm=norm)
#   cb = m.colorbar(cs, location='bottom',pad=0.05,extend='both')

    plttitle="diag_"+vartype+"_"+cychr
    plt.title(plttitle)
    plotname=thisdir+"/"+plttitle+".png"
    figpath=thisdir+plotname
    plt.savefig(plotname,bbox_inches='tight',dpi=100)
    plt.close('all')

def readobs(diagfile):
    tmpdata = nc.Dataset(diagfile,'r')
    lat = tmpdata.variables['Latitude'][:]
    lon = tmpdata.variables['Longitude'][:]
    return lat, lon

if __name__ == "__main__":

    stream = open("config_rrfs_obs.yaml", 'r')
    config = yaml.safe_load(stream)

    fldir=config['paths']['inputdir']
    filename=config['filename']
    vartype=config['VARTYPE']
    outfile=config['out_nc_file']
    cyctime=config['cyctime']

    obsdir=config['rrfsobs']['inputdir']
    obsconus=config['rrfsobs']['obs_file_name']
    diagconus=obsdir+obsconus

    obsdir=config['rrfsobs']['inputna']
    obsna=config['rrfsobs']['obs_file_na']
    diagna=obsdir+obsna

    cmd="mkdir "+str(cyctime)
    thisdir="./"+str(cyctime)
    os.system(cmd)
    cmd="pwd"
    os.system(cmd)

    cychr="conus"
    latconus, lonconus = readobs(diagconus)
    dataconus=lonconus
    plot_world_map(lonconus, latconus, dataconus, vartype, cychr, thisdir)
    cychr="na"
    latna, lonna = readobs(diagna)
    datana=lonna
    plot_world_map(lonna, latna, datana, vartype, cychr, thisdir)


################################################################################
# oops/surface/ringplane.py: RingPlane subclass of class Surface
################################################################################

import numpy as np
from polymath     import Scalar, Vector3
from oops.frame   import Frame
from oops.path    import Path
from oops.surface import Surface
from oops.gravity.oblategravity import OblateGravity

class RingPlane(Surface):
    """A subclass of Surface describing a flat surface in the (x,y) plane, in
    which the optional velocity field is defined by circular Keplerian motion
    about the center point. Coordinates are cylindrical (radius, longitude,
    elevation), with an optional offset in elevation from the equatorial (z=0)
    plane.

    Optional modes can be used to apply sinusoidal offset patterns in the radial
    coordinate.
    """

    COORDINATE_TYPE = 'polar'
    IS_VIRTUAL = False

    #===========================================================================
    def __init__(self, origin, frame, radii=None, gravity=None,
                       elevation=0., modes=[], epoch=0.):
        """Constructor for a RingPlane surface.

        Input:
            origin      a Path object or ID defining the motion of the center
                        of the ring plane.

            frame       a Frame object or ID in which the ring plane is the
                        (x,y) plane (where z = 0).

            radii       the nominal inner and outer radii of the ring, in km.
                        None for a ring with no radial limits.

            gravity     an optional Gravity object, used to define the orbital
                        velocities within the plane.

            elevation   an optional offset of the ring plane in the direction of
                        positive rotation, in km.

            modes       an optional list of zero or more radial modes in the
                        ring. Each mode is described by a tuple of four
                        parameters (cycles, amp, peri0, speed):
                            cycles  the number of radial cycles around the ring.
                            amp     radial amplitude in km.
                            peri0   longitude of one radial minimum at epoch, in
                                    radians.
                            speed   the pattern speed in radians per second.

            epoch       the epoch at which the radial mode parameters apply.
                        Not used unless radial modes are present.
         """

        self.origin    = Path.as_waypoint(origin)
        self.frame     = Frame.as_wayframe(frame)
        self.gravity   = gravity
        self.elevation = float(elevation)
        self.modes     = modes
        self.epoch     = float(epoch)

        if radii is None:
            self.radii = None
        else:
            self.radii    = np.asfarray(radii)
            self.radii_sq = self.radii**2

        # Save the unmasked version of this surface
        if radii is None:
            self.unmasked = self
        else:
            self.unmasked = RingPlane(self.origin, self.frame,
                                      radii = None,
                                      gravity = self.gravity,
                                      elevation = self.elevation,
                                      modes = self.modes,
                                      epoch = self.epoch)

        # Identify the maximum orbital rate by any means necessary; without this
        # limit, speeds near the origin get ridiculous.
        if self.radii is not None:
            r = self.radii[0]
            self.max_rate = self.gravity.n(r)
        elif hasattr(self.gravity, 'rp'):
            r = self.gravity.rp
            self.max_rate = self.gravity.n(r)
        else:
            # If we can't figure out the planet, clamp the rate at that for an
            # orbit skimming the surface of Neptune. (Note that this rate is
            # faster than that for Jupiter, Saturn, or Uranus.)
            neptune = OblateGravity.NEPTUNE
            self.max_rate = neptune.n(neptune.rp)

        # Unique key for intercept calculations
        # ('ring', origin, frame, elevation, i, node, dnode_dt, epoch)
        # Extra elements are so OrbitPlane and RingPlane can share the same
        # key in situations where the orbit is not inclined.
        self.intercept_key = ('ring', self.origin.waypoint,
                                      self.frame.wayframe,
                                      self.elevation, 0., 0., 0., 0.)

    def __getstate__(self):
        return (Path.as_primary_path(self.origin),
                Frame.as_primary_frame(self.frame),
                None if self.radii is None else tuple(self.radii),
                self.gravity, self.elevation, self.modes, self.epoch)

    def __setstate__(self, state):
        self.__init__(*state)

    #===========================================================================
    def coords_from_vector3(self, pos, obs=None, time=None, axes=2,
                                       derivs=False, hints=None):
        """Surface coordinates associated with a position vector.

        Input:
            pos         a Vector3 of positions at or near the surface, relative
                        to this surface's origin and frame.
            obs         a Vector3 of observer position relative to this
                        surface's origin and frame; ignored for this Surface
                        subclass.
            time        a Scalar time at which to evaluate the surface; ignored
                        unless this RingPlane contains radial modes.
            axes        2 or 3, indicating whether to return the first two
                        coordinates (rad, theta) or all three (rad, theta, z) as
                        Scalars.
            derivs      True to propagate any derivatives inside pos and obs
                        into the returned coordinates.
            hints       ignored. Provided for compatibility with other Surface
                        subclasses.

        Return:         coordinate values packaged as a tuple containing two or
                        three Scalars, one for each coordinate.
            rad         mean orbital radius in the ring plane, in km.
            theta       longitude in radians of the intercept point.
            z           vertical distance in km above the ring plane; included
                        if axes == 3.
        """

        # Validate inputs
        self._coords_from_vector3_check(axes)
        pos = Vector3.as_vector3(pos, derivs)

        # Generate cylindrical coordinates
        (r, theta, z) = pos.to_cylindrical()

        if self.modes:
            a = r - self._mode_offset(theta, time, derivs=derivs)
        else:
            a = r

        # Apply mask as needed
        if self.radii is not None:
            mask = a.tvl_lt(self.radii[0]) | a.tvl_gt(self.radii[1])
            if mask.any():
                a = a.remask_or(mask.vals)
                theta = theta.remask(a.mask)
                if axes > 2:
                    z = z.remask(r.mask)

        if axes == 2:
            return (a, theta)
        elif self.elevation == 0:
            return (a, theta, z)
        else:
            return (a, theta, z - self.elevation)

    #===========================================================================
    def vector3_from_coords(self, coords, obs=None, time=0., derivs=False):
        """The position where a point with the given coordinates falls relative
        to this surface's origin and frame.

        Input:
            coords      a tuple of two or three Scalars defining coordinates at
                        or near this surface. These can have different shapes,
                        but must be broadcastable to a common shape.
                rad     mean orbital radius in the ring plane, in km.
                theta   longitude in radians of the intercept point.
                z       vertical distance in km above the ring plane.
            obs         a Vector3 of observer position relative to this
                        surface's origin and frame; ignored for this Surface
                        subclass.
            time        a Scalar time at which to evaluate the surface; ignored
                        unless this RingPlane contains radial modes.
            derivs      True to propagate any derivatives inside the coordinates
                        and obs into the returned position vectors.

        Return:         a Vector3 of points defined by the coordinates, relative
                        to this surface's origin and frame.
        """

        # Validate inputs
        self._vector3_from_coords_check(coords)

        a = Scalar.as_scalar(coords[0], derivs)
        theta = Scalar.as_scalar(coords[1], derivs)

        if self.modes:
            r = a + self._mode_offset(theta, time, derivs=derivs)
        else:
            r = a

        if len(coords) > 2:
            z = Scalar.as_scalar(coords[2] + self.elevation, derivs)
        else:
            z = Scalar.as_scalar(self.elevation, derivs)

        x = r * theta.cos()
        y = r * theta.sin()

        return Vector3.from_scalars(x, y, z)

    #===========================================================================
    def intercept(self, obs, los, time=None, direction='dep', derivs=False,
                                  guess=None, hints=None):
        """The position where a specified line of sight intercepts the surface.

        Input:
            obs         observer position as a Vector3 relative to this
                        surface's origin and frame.
            los         line of sight as a Vector3 in this surface's frame.
            time        a Scalar time at the surface; ignored here.
            direction   'arr' for a photon arriving at the surface; 'dep' for a
                        photon departing from the surface; ignored here.
            derivs      True to propagate any derivatives inside obs and los
                        into the returned intercept point.
            guess       unused.
            hints       if not None (the default), this value is appended to the
                        returned tuple. Needed for compatibility with other
                        Surface subclasses.

        Return:         a tuple (pos, t) or (pos, t, hints), where
            pos         a Vector3 of intercept points on the surface relative
                        to this surface's origin and frame, in km.
            t           a Scalar such that:
                            intercept = obs + t * los
            hints       the input value of hints, included if hints is not None.
        """

        # Solve for obs + factor * los for scalar t, such that the z-component
        # equals zero.
        obs = Vector3.as_vector3(obs, derivs)
        los = Vector3.as_vector3(los, derivs)

        obs_z = obs.to_scalar(2)
        los_z = los.to_scalar(2)

        t = (self.elevation - obs_z)/los_z
        pos = obs + t * los

        # Mask based on radial limits if necessary
        if self.radii is not None:
            r_sq = pos.norm_sq(False)
            mask = (r_sq < self.radii_sq[0]) | (r_sq > self.radii_sq[1])
            if np.any(mask):
                pos = pos.remask_or(mask)
            t = t.remask(pos.mask)

        if hints is not None:
            return (pos, t, hints)

        return (pos, t)

    #===========================================================================
    def normal(self, pos, time=0., derivs=False):
        """The normal vector at a position at or near a surface.

        Input:
            pos         a Vector3 of positions at or near the surface relative
                        to this surface's origin and frame.
            time        a Scalar time at which to evaluate the surface; ignored
                        here.
            derivs      True to propagate any derivatives of pos into the
                        returned normal vectors.

        Return:         a Vector3 containing directions normal to the surface
                        that pass through the position. Lengths are arbitrary.
        """

        pos = Vector3.as_vector3(pos, derivs)

        # Always the Z-axis
        perp = pos.all_constant((0.,0.,1.))

        # The normal is undefined outside the ring's radial limits
        if self.radii is not None:
            r_sq = pos.norm_sq(False)
            mask = (r_sq < self.radii_sq[0]) | (r_sq > self.radii_sq[1])
            if np.any(mask):
                perp = perp.remask_or(mask)

        return perp

    #===========================================================================
    def velocity(self, pos, time=0.):
        """The local velocity vector at a point within the surface.

        This can be used to describe the orbital motion of ring particles or
        local wind speeds on a planet.

        Input:
            pos         a Vector3 of positions at or near the surface relative
                        to this surface's origin and frame.
            time        a Scalar time at which to evaluate the surface; ignored
                        unless this RingPlane contains radial modes.

        Return:         a Vector3 of velocities, in units of km/s.
        """

        pos = Vector3.as_vector3(pos, False)

        # Handle special case that's easy
        if self.gravity is None and not self.modes:
            return Vector3.zeros(pos.shape, mask=pos.mask)

        # Generate info about intercept points
        (x,y,z) = pos.to_scalars(recursive=False)
        radius = (x**2 + y**2).sqrt()
        r_vector = Vector3.from_scalars(x,y,0.)

        # Handle radial modes
        if self.modes:
            lon = y.arctan2(x)
            (offset, dr_dt, dlon_dt) = self._mode_offset(lon, time, rates=True)
            a = radius - offset

            if self.gravity:
                dlon_dt += Scalar.minimum(self.gravity.n(a.vals), self.max_rate)

            v_radial = (dr_dt / radius) * r_vector
            v_angular = dlon_dt * Vector3.ZAXIS.cross(r_vector)
            vflat = v_radial + v_angular

        # Handle simple gravity
        else:
            a = radius
            n = Scalar.minimum(self.gravity.n(a.vals), self.max_rate)
            vflat = n * Vector3.ZAXIS.cross(r_vector)

        # The velocity is undefined outside the ring's radial limits
        if self.radii is not None:
            mask = (a < self.radii[0]) | (a > self.radii[1])
            if np.any(mask):
                vflat = vflat.remask_or(mask)

        return vflat

    ############################################################################
    # Radius conversions
    ############################################################################

    def _mode_offset(self, lon, time, derivs=False, rates=False):
        """Sum of the modes as a local radial offset from the mean epicyclic
        radius to the actual radius.

        If input rates==True, return a tuple (radial offset, epicyclic dr/dt,
        epicyclic dlon/dt.
        """

        offset = 0.
        dr_dt = 0.
        dlon_dt = 0.
        for mode in self.modes:
            (cycles, amp, peri0, speed) = mode
            arg = cycles * (lon - peri0) + speed * (time - self.epoch)
            amp_cos_arg = amp * arg.cos(recursive=derivs)
            offset = offset - amp_cos_arg
            if rates:
                dr_dt   = dr_dt   + (speed * amp) * arg.sin()
                dlon_dt = dlon_dt + (2. * speed) * amp_cos_arg

        if rates:
            return (offset, dr_dt, dlon_dt)

        return offset

################################################################################
# UNIT TESTS
################################################################################

import unittest
from oops.constants import TWOPI

class Test_RingPlane(unittest.TestCase):

    def runTest(self):

        from oops.gravity import Gravity
        from oops.event import Event

        np.random.seed(8829)

        plane = RingPlane(Path.SSB, Frame.J2000)

        # Coordinate/vector conversions
        obs = np.random.rand(2,4,3,3)

        (r,theta,z) = plane.coords_from_vector3(obs,axes=3)
        self.assertTrue((theta >= 0.).all())
        self.assertTrue((theta < TWOPI).all())
        self.assertTrue((r >= 0.).all())

        test = plane.vector3_from_coords((r,theta,z))
        self.assertTrue(np.all(np.abs(test.vals - obs) < 1.e-15))

        # Ring intercepts
        los = np.random.rand(2,4,3,3)
        obs[...,2] =  np.abs(obs[...,2])
        los[...,2] = -np.abs(los[...,2])

        (pts, factors) = plane.intercept(obs, los)
        self.assertTrue(abs(pts.to_scalar(2)).max() < 1.e-15)

        angles = pts - obs
        self.assertTrue((angles.sep(los) > -1.e-12).all())
        self.assertTrue((angles.sep(los) <  1.e-12).all())

        # Intercepts that point away from the ring plane
        self.assertTrue(np.all(factors.vals > 0.))

        ########################################################################
        # Test of radial modes
        ########################################################################

        # Coordinate/vector conversions
        refplane = RingPlane(Path.SSB, Frame.J2000)

        plane = RingPlane(Path.SSB, Frame.J2000,
                          modes=[(10, 1000., 0., 0.)], epoch=0.)

        obs = 10.e3 * np.random.rand(2,4,3,3)

        (a,theta,z) = plane.coords_from_vector3(obs, time=0., axes=3)
        test = plane.vector3_from_coords((a,theta,z), time=0.)
        self.assertTrue(np.all(np.abs(test.vals - obs) < 1.e-11))

        test = plane.vector3_from_coords((a,theta,z), time=1.e8)
        self.assertTrue(np.all(np.abs(test.vals - obs) < 1.e-11))

        plane = RingPlane(Path.SSB, Frame.J2000,
                          modes=[(10, 1000., 0., 2*np.pi/100.)], epoch=0.)

        obs = 10.e3 * np.random.rand(2,4,3,3)

        (a,theta,z) = plane.coords_from_vector3(obs, time=0., axes=3)
        test = plane.vector3_from_coords((a,theta,z), time=0.)
        self.assertTrue(np.all(np.abs(test.vals - obs) < 1.e-11))

        test = plane.vector3_from_coords((a,theta,z), time=100.)
        self.assertTrue(np.all(np.abs(test.vals - obs) < 1.e-11))

        # longitudes are the same in both maps
        (a0,theta0,z0) = refplane.coords_from_vector3(obs, time=0., axes=3)
        self.assertEqual(theta0, theta)

        # radial offsets are out of phase when time=50.
        diff1 = a - a0
        (a,theta,z) = plane.coords_from_vector3(obs, time=50., axes=3)
        diff2 = a - a0
        self.assertTrue(abs(diff1 + diff2).max() < 1.e-11)

        ########################################################################
        # Test of velocities
        ########################################################################

        pos = 10.e3 * np.random.rand(200,3)
        pos[...,2] = 0.     # set Z-coordinate to zero
        pos = Vector3(pos)

        # No gravity, no modes
        refplane = RingPlane(Path.SSB, Frame.J2000)

        vels = refplane.velocity(obs)
        self.assertEqual(vels, (0.,0.,0.))

        # No gravity, motionless mode
        plane = RingPlane(Path.SSB, Frame.J2000,
                          modes=[(10, 1000., 0., 0.)], epoch=0.)

        vels = plane.velocity(obs)
        self.assertEqual(vels, (0.,0.,0.))

        # No gravity, modes (10 cycles, 100 km amplitude, period = 10,000 s)
        plane = RingPlane(Path.SSB, Frame.J2000,
                          modes=[(10, 100., 0., 2.*np.pi/1.e4)], epoch=0.)

        TIME = 0.
        (a0,theta0) = plane.coords_from_vector3(pos, time=TIME - 0.5)
        (a ,theta ) = plane.coords_from_vector3(pos, time=TIME)
        (a1,theta1) = plane.coords_from_vector3(pos, time=TIME + 0.5)
        self.assertEqual(theta, theta0)
        self.assertEqual(theta, theta1)

        vels = plane.velocity(pos, time=TIME)
        v_angular = vels.perp(pos)
        v_radial = vels - v_angular

        sign = v_radial.dot(pos).sign()
        speed2 = sign * v_radial.norm()
        speed1 = a0 - a1
        self.assertTrue(abs(speed1 - speed2).max() < 2.e-9)

        # Gravity, no modes
        plane = RingPlane(Path.SSB, Frame.J2000, gravity=Gravity.SATURN)

        (a, theta) = plane.coords_from_vector3(pos)

        vels = plane.velocity(pos)
        sep = vels.sep(pos)
        self.assertTrue(abs(sep - np.pi/2.).max() < 1.e-14)

        speed1 = vels.norm()
        rate = np.minimum(Gravity.SATURN.n(a.vals), plane.max_rate)
        diff = (a * rate - speed1) / speed1
        self.assertTrue(abs(diff).max() < 1.e-15)

        ########################################################################
        # coords_of_event, event_from_coords
        ########################################################################

        plane = RingPlane(Path.SSB, Frame.J2000)

        pos = Vector3(np.random.rand(2,4,3,3))
        vel = Vector3(np.random.rand(2,4,3,3))
        pos.insert_deriv('t', vel)

        event = Event(0., pos, Path.SSB, Frame.J2000)
        coords = plane.coords_of_event(event)
        test = plane.event_at_coords(0., coords)

        self.assertTrue(np.all(np.abs(test.pos.vals - pos.vals) < 1.e-15))
        self.assertTrue(np.all(np.abs(test.vel.vals - vel.vals) < 1.e-15))

        ########################################################################
        # Note: Additional unit testing is performed in orbitplane.py
        ########################################################################

        Path.reset_registry()
        Frame.reset_registry()

########################################
if __name__ == '__main__':
    unittest.main(verbosity=2)
################################################################################


"""
The GripNet proposed in the `"GripNet: Graph Information Propagation on Supergraph for Heterogeneous Graphs"
    <https://doi.org/10.1016/j.patcog.2022.108973>`_ (PatternRecognit 2022) paper, which is an efficient
    framework to learn node representations on heterogeneous graphs for the downstream link prediction,
    node classification, and visualization. The code is based on the https://github.com/NYXFLOWER/GripNet.
"""

import logging
from typing import Dict

import torch
import torch.nn.functional as F
from torch.nn import Module

from kale.embed.gcn import GCNEncoderLayer, RGCNEncoderLayer
from kale.prepdata.supergraph_construct import SuperGraph, SuperVertex, SuperVertexParaSetting

class GripNetInternalModule(Module):
    r"""
    The internal module of a supervertex, which is composed of an internal feature layer and multiple internal
    aggregation layers.

    Args:
        in_channels (int): the dimension of node features on this supervertex.
        num_edge_type (int): the number of edge types on this supervertex.
        start_supervertex (bool): whether this supervertex is a start supervertex on the supergraph.
        setting (SuperVertexParaSetting): supervertex parameter settings.
    """

    def __init__(
        self, in_channels: int, num_edge_type: int, start_supervertex: bool, setting: SuperVertexParaSetting
    ) -> None:
        super(GripNetInternalModule, self).__init__()
        # in and out dimension
        self.in_channels = in_channels
        self.out_channels = setting.inter_agg_channels_list[-1]

        self.num_edge_type = num_edge_type
        self.multirelational = 1 if num_edge_type > 1 else 0
        self.start_supervertex = start_supervertex
        self.setting = setting

        self.__init_inter_feat_layer__()
        self.__init_inter_agg_layer__()

    def __init_inter_feat_layer__(self):
        """internal feature layer"""

        self.embedding = torch.nn.Parameter(torch.Tensor(self.in_channels, self.setting.inter_feat_channels))
        self.embedding.requires_grad = True

        # reset parameters to be normally distributed
        self.embedding.data.normal_()

    def __init_inter_agg_layer__(self):
        """internal aggregation layers"""

        # compute the dim of input of the first internal aggregation layer
        self.in_agg_channels = self.setting.inter_feat_channels
        if not self.start_supervertex:
            if self.setting.mode == "cat":
                if not self.setting.exter_agg_channels_dict:
                    error_msg = "`exter_agg_channels_dict` is not set."
                    logging.error(error_msg)
                    raise ValueError(error_msg)
                self.in_agg_channels += sum(self.setting.exter_agg_channels_dict.values())
            elif self.setting.mode == "add":
                tmp = set([self.in_agg_channels] + list(self.setting.exter_agg_channels_dict.values()))
                if len(tmp) != 1:
                    error_msg = "`in_agg_channels` should be the same as any element in `exter_agg_channels_dict`."
                    logging.error(error_msg)
                    raise ValueError(error_msg)
            else:
                error_msg = "`mode` value is invalid. Use 'cat' or 'add'."
                logging.error(error_msg)
                raise ValueError(error_msg)

        # create and initialize the internal aggregation layers
        self.num_inter_agg_layer = len(self.setting.inter_agg_channels_list)
        tmp_dim = [self.in_agg_channels] + self.setting.inter_agg_channels_list

        if self.setting.concat_output:
            self.out_channels = sum(tmp_dim)

        if self.multirelational:
            # using RGCN if there are multiple edge types
            after_relu = [False if i == 0 else True for i in range(self.num_inter_agg_layer)]
            self.inter_agg_layers = torch.nn.ModuleList(
                [
                    RGCNEncoderLayer(
                        tmp_dim[i], tmp_dim[i + 1], self.num_edge_type, self.setting.num_bases, after_relu[i]
                    )
                    for i in range(self.num_inter_agg_layer)
                ]
            )
        else:
            # using GCN if there is only one edge type
            self.inter_agg_layers = torch.nn.ModuleList(
                [GCNEncoderLayer(tmp_dim[i], tmp_dim[i + 1], cached=True) for i in range(self.num_inter_agg_layer)]
            )

    def forward(
        self,
        x: torch.Tensor,
        edge_index: torch.Tensor,
        edge_type: torch.Tensor = None,
        range_list: torch.Tensor = None,
        edge_weight: torch.Tensor = None,
    ) -> torch.Tensor:
        r"""
        Args:
            x (torch.Tensor): the input node feature embedding.
            edge_index (torch.Tensor): edge index in COO format with shape [2, #edges].
            edge_type (torch.Tensor, optional): one-dimensional relation type for each edge, indexed from 0.
                Defaults to None.
            range_list (torch.Tensor, optional): The index range list of each edge type with shape [num_types, 2].
                Defaults to None.
            edge_weight (torch.Tensor, optional): one-dimensional weight for each edge. Defaults to None.

        Note: The internal feature layer is computed in the `forward` function of GripNet class. If the supervertex
        is not a start supervertex, `x` should be the sum or concat of the outputs of the internal feature
        layer and all external aggregation layers.
        """

        if self.setting.concat_output:
            tmp = []
            tmp.append(x)

        if self.multirelational:
            if edge_type is None or range_list is None:
                error_msg = "`edge_type` and `range_list` are not set."
                logging.error(error_msg)
                raise ValueError(error_msg)

        # internal feature aggregation layers
        for net in self.inter_agg_layers[:-1]:
            x = net(x, edge_index, edge_type, range_list) if self.multirelational else net(x, edge_index, edge_weight)
            x = F.relu(x, inplace=True)
            if self.setting.concat_output:
                tmp.append(x)

        x = (
            self.inter_agg_layers[-1](x, edge_index, edge_type, range_list)
            if self.multirelational
            else self.inter_agg_layers[-1](x, edge_index, edge_weight)
        )

        x = F.relu(x, inplace=True)
        if self.setting.concat_output:
            tmp.append(x)
            x = torch.cat(tmp, dim=1)

        return x

    def __repr__(self):
        tmp = [f"\n    ({i}): {l}" for i, l in enumerate(self.inter_agg_layers)]

        return (
            "{}: ModuleList(\n  (0): InternalFeatureLayer: Embedding({}, {})\n  "
            "(1): InternalFeatureAggregationModule: ModuleList({}\n  )\n)"
        ).format(self.__class__.__name__, self.in_channels, self.setting.inter_feat_channels, "".join(tmp))

class GripNetExternalModule(Module):
    """The internal module of a supervertex, which is an external feature layer.

    Args:
        in_channels (int): Size of each input sample. In GripNet, it should be the dimension of the output embedding of
        the corresponding parent supervertex.
        out_channels (int): Size of each output sample. In GripNet, it is the dimension of the output embedding of
            the supervertex.
        num_out_node (int): the number of output nodes.
    """

    def __init__(self, in_channels: int, out_channels: int, num_out_node: int) -> None:
        super(GripNetExternalModule, self).__init__()

        self.in_channels = in_channels
        self.out_channels = out_channels
        self.num_out_node = num_out_node

        self.exter_agg_layer = GCNEncoderLayer(in_channels, out_channels, cached=True)

    def forward(self, x: torch.Tensor, edge_index: torch.Tensor, edge_weight: torch.Tensor = None, use_relu=True):
        """
        Args:
            x (torch.Tensor): the input node feature embedding.
            edge_index (torch.Tensor): edge index in COO format with shape [2, #edges].
            edge_weight (torch.Tensor, optional): one-dimensional weight for each edge. Defaults to None.
            use_relu (bool, optional): whether to use ReLU before returning node feature embeddings. Defaults to True.
        """

        n_source, n_feat = x.shape
        bigraph_edge_index = edge_index + 0
        bigraph_edge_index[1, :] += n_source

        x = torch.cat([x, torch.zeros((self.num_out_node, n_feat)).to(x.device)], dim=0)
        x = self.exter_agg_layer(x, bigraph_edge_index, edge_weight)[n_source:, :]

        if use_relu:
            x = F.relu(x, inplace=True)

        return x

    def __repr__(self):
        return "{}: {}".format(self.__class__.__name__, self.exter_agg_layer.__repr__())

class GripNet(Module):
    r"""The GripNet model.

    Args:
        supergraph (SuperGraph): the supergraph.

    Reference:
        Xu, H., Sang, S., Bai, P., Li, R., Yang, L. and Lu, H., 2022. GripNet: Graph Information
        Propagation on Supergraph for Heterogeneous Graphs. Pattern Recognition, p.108973.
    """

    def __init__(self, supergraph: SuperGraph) -> None:
        super(GripNet, self).__init__()

        self.supergraph = supergraph
        self.task_supervertex_name = supergraph.topological_order[-1]

        self.out_embed_dict: Dict[str, torch.Tensor] = {}

        self.__check_supergraph__()
        self.__init_supervertex_module_dict__()

        self.out_channels = self.__get_out_channels__()

    def __check_supergraph__(self) -> None:
        """check whether the input supergraph has parameter settings"""

        if self.supergraph.supervertex_setting_dict is None:
            error_msg = "`supervertex_setting_dict` is not set."
            logging.error(error_msg)
            raise ValueError(error_msg)

    def __init_supervertex_module_dict__(self):
        self.supervertex_module_dict: Dict[str, torch.nn.ModuleList] = {}
        for supervertex_name in self.supergraph.topological_order:
            supervertex = self.supergraph.supervertex_dict[supervertex_name]
            setting = self.supergraph.supervertex_setting_dict[supervertex_name]
            self.__init_module_supervertex__(supervertex, setting)

    def __init_module_supervertex__(self, supervertex: SuperVertex, setting: SuperVertexParaSetting):
        module_list = torch.nn.ModuleList()

        if not supervertex.start_supervertex:
            # add the external modules from all parent supervertices
            for in_name in supervertex.in_supervertex_list:
                in_channels = self.supervertex_module_dict[in_name][-1].out_channels

                if setting.exter_agg_channels_dict is None:
                    error_msg = "`exter_agg_channels_dict` is not set."
                    logging.error(error_msg)
                    raise ValueError(error_msg)

                out_channels = setting.exter_agg_channels_dict[in_name]
                module_list.append(GripNetExternalModule(in_channels, out_channels, supervertex.num_node))

        # add the internal module
        module_list.append(
            GripNetInternalModule(
                supervertex.num_node_feat, supervertex.num_edge_type, supervertex.start_supervertex, setting
            )
        )

        self.supervertex_module_dict[supervertex.name] = module_list

    def __get_out_channels__(self):
        task_supervertex = self.supergraph.topological_order[-1]
        return self.supervertex_module_dict[task_supervertex][-1].out_channels

    def forward(self):
        if self.supergraph.supervertex_setting_dict is None:
            error_msg = "`supervertex_setting_dict` is not set."
            logging.error(error_msg)
            raise ValueError(error_msg)

        for supervertex_name in self.supergraph.topological_order:
            mode = self.supergraph.supervertex_setting_dict[supervertex_name].mode
            self.__forward_supervertex__(supervertex_name, mode)

        return self.out_embed_dict[self.task_supervertex_name]

    def __forward_supervertex__(self, supervertex_name: str, mode: str):
        supervertex = self.supergraph.supervertex_dict[supervertex_name]
        model = self.supervertex_module_dict[supervertex_name]

        # internal feature layer
        x = torch.matmul(supervertex.node_feat, model[-1].embedding)

        # external feature aggregation layers
        if mode == "add":
            for idx in range(len(supervertex.in_supervertex_list)):
                parent_name = supervertex.in_supervertex_list[idx]
                parent_x = self.out_embed_dict[parent_name]
                superedge = self.supergraph.superedge_dict[(parent_name, supervertex_name)]

                x += model[idx](parent_x, superedge.edge_index, superedge.edge_weight)
        else:
            tmp = [x]
            for idx in range(len(supervertex.in_supervertex_list)):
                parent_name = supervertex.in_supervertex_list[idx]
                parent_x = self.out_embed_dict[parent_name]
                superedge = self.supergraph.superedge_dict[(parent_name, supervertex_name)]

                tmp.append(model[idx](parent_x, superedge.edge_index, superedge.edge_weight))
            x = torch.cat(tmp, dim=1)

        # internal feature aggregation layers
        if supervertex.num_edge_type > 1:
            x = model[-1](
                x, supervertex.edge_index, supervertex.edge_type, supervertex.range_list, supervertex.edge_weight
            )
        else:
            x = model[-1](x, supervertex.edge_index, supervertex.edge_weight)

        self.out_embed_dict[supervertex_name] = x

    def __repr__(self):
        return "{}: ModuleDict(\n{})".format(self.__class__.__name__, self.supervertex_module_dict)


from copy import deepcopy
from itertools import product
from collections import defaultdict

dic=defaultdict(int)
dic['L']=(0,-1)
dic['R']=(0,1)
dic['U']=(-1,0)
dic['D']=(1,0)
ONE=[('L'),('R'),('U'),('D')]
TWO=[('L','R'),('U','D')]
THREE=[('U','R'),('R','D'),('D','L'),('L','U')]
FOUR=[('U','R','L'),('U','R','D'),('R','D','L'),('U','L','D')]
FIVE=[('U','R','D','L')]

def visit(board,orient_lst,c_x,c_y): #(L,R) board와 방향,현재위치 주면 #으로 만들어준다.
    for ori in orient_lst:  #ori==L OR ori==R
        dx = dic[ori][0]
        dy = dic[ori][1]
        nx=c_x+dx
        ny=c_y+dy
        while True:
            if nx<0 or R_N<=nx or ny<0 or C_N<=ny or board[nx][ny]==6:
                break
            else:
                if board[nx][ny]==0:
                    board[nx][ny]='#'
            nx+=dx
            ny+=dy
    return
def solution(board,dot_lst,comb_lst):
    answer=0
    for cur_location,ori_lst in zip(dot_lst,comb_lst):
        visit(board, ori_lst, cur_location[0],cur_location[1])
    for i in range(R_N):
        for j in range(C_N):
            if board[i][j]==0:
                answer+=1
    return answer

if __name__=="__main__":
    answer=float('inf')
    board=[]
    R_N,C_N=map(int,input().split())
    for _ in range(R_N):
        board.append(list(map(int,input().split())))
    comb_lst=[]
    dot_lst=[]
    for i in range(R_N):
        for j in range(C_N):
            if board[i][j]==1:
                comb_lst.append(ONE)
                dot_lst.append((i,j))
            elif board[i][j]==2:
                comb_lst.append(TWO)
                dot_lst.append((i,j))
            elif board[i][j] == 3:
                comb_lst.append(THREE)
                dot_lst.append((i,j))
            elif board[i][j] == 4:
                comb_lst.append(FOUR)
                dot_lst.append((i,j))
            elif board[i][j] == 5:
                comb_lst.append(FIVE)
                dot_lst.append((i,j))
            else:
                continue
    comb_lst=list(product(*comb_lst))   #신의한수..
    for c in comb_lst:
        sub_board=deepcopy(board)
        answer=min(solution(sub_board,dot_lst,c),answer)
    print(answer)


from google.appengine.ext import db
from model import IngredientCategory
import jinja2
import os
from base_handler import BaseHandler
from user_management import isUserCook
from cache_ingredient import modifyIngredient
from cache_ingredient_category import addIngredientCategory,\
	getIngredientCategoryWithIngredients, getIngredientCategories,\
	deleteIngredientCategory

jinja_environment = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))

class CategoryIngredientDeletePage(BaseHandler):
	URL = '/deleteIngredientFromCategory'
	def post(self):
		if not isUserCook(self):
			self.redirect("/")
			return
		category = db.get(self.request.get('ingredientCategoryKey'))
		ingredient = db.get(self.request.get('ingredientKey'))
		ingredient.category=None
		ingredient.put()
		modifyIngredient(ingredient)
		self.redirect('/ingredientCategory?ingredientCategoryKey=%s' % category.key())

class IngredientCategoryPage(BaseHandler):
	URL = '/ingredientCategory'
	def post(self):
		if not isUserCook(self):
			self.redirect("/")
			return
		ingredientCategory = IngredientCategory()
		ingredientCategory.name = self.request.get('ingredient_category_name')
		ingredientCategory.put()
		addIngredientCategory(ingredientCategory)
		self.redirect('/ingredientCategory')
	def get(self):
		if not isUserCook(self):
			self.redirect("/")
			return
		ingredientCategoryKey = self.request.get('ingredientCategoryKey')
		if ingredientCategoryKey!= None and ingredientCategoryKey != "":
		# List every ingredient in the category
			ingredientCategory = getIngredientCategoryWithIngredients(ingredientCategoryKey)
			template_values = {
				'ingredientCategory': ingredientCategory,
				'add_url':"/addIngredientToCategory",
				'delete_url':"/deleteIngredientFromCategory"
			}
			template = jinja_environment.get_template('templates/ingredient_category.html')
			self.printPage(ingredientCategory['name'], template.render(template_values), False, False)
		else:
		# All categories
			ingredientCategories = getIngredientCategories()
			template_values = {
				'ingredientCategories': ingredientCategories,
				'delete_url':"/deleteIngredientCategory"
			}
			template = jinja_environment.get_template('templates/ingredient_category_list.html')
			self.printPage("Alapanyag kategoriak", template.render(template_values), False, False)

class IngredientCategoryDeletePage(BaseHandler):
	URL = '/deleteIngredientCategory'
	def post(self):
		if not isUserCook(self):
			self.redirect("/")
			return
		ingredientCategoryKey = self.request.get('ingredientCategoryKey')
		ingredientCategory = db.get(ingredientCategoryKey)
		ingredientCategory.delete()
		deleteIngredientCategory(ingredientCategoryKey)
		self.redirect('/ingredientCategory')


import tensorflow as tf
import numpy as np
import pygame

#Checkpoint System
checkpoint_path="pong/pong.ckpt"
cp_callback=tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,save_weights_only=True,verbose=1)

#AI
    #model
model = tf.keras.Sequential([
    tf.keras.layers.Input(shape=(5)),
    tf.keras.layers.Dense(5,activation='relu'),
    tf.keras.layers.Dense(2)
])

model.compile(optimizer='adam',
    #loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    loss='categorical_crossentropy',
    metrics=['accuracy'])
#load Checkpoint
model.load_weights(checkpoint_path)

inputs=[]
outputs=[]

def resArrays():
    inputs=[]
    outputs=[]
counter = 0

bs = 5
#Screen and drawning
size = width,height = 400,400
    #init
pygame.init()
screen = pygame.display.set_mode((int(width),int(height)))

    #DrawningColor
c_open= (   255,255,255)
c_off = (   0,  0,  0)

def drawRect(x,y,width,height):
    pygame.draw.rect(screen,c_open,pygame.Rect(int(x),int(y),int(width),int(height)))

#Object
class Object:
    def __init__(self,startX=45,startY=45,startSX=10,startSY=10,startSpeed = 1):
        self.pos,self.size = [startX,startY],[startSX,startSY]
        self.speed = startSpeed

    def getCol(self, cpX,cpY):
        return (self.pos[0]<cpX) and (self.pos[0]+self.size[0]>cpX) and (self.pos[1]<cpY) and (self.pos[1]+self.size[1]>cpY)

    def getColBlock(self,pos,size):
        return self.getCol(pos[0],pos[1]) or self.getCol(pos[0]+size[0],pos[1]) or self.getCol(pos[0],pos[1]+size[1]) or self.getCol(pos[0]+size[0],pos[1]+size[1])

    def print(self):
        drawRect(self.pos[0],self.pos[1],self.size[0],self.size[1])

    def move(self,mX,mY):
        self.pos[0]+=int(mX*self.speed)
        self.pos[1]+=int(mY*self.speed)

#Control
control1=[0.0,0.0]
control2=[0.0,0.0]
score=[0,0]

player1 = Object(0,40,10,100,6)
player2 = Object(390,40,10,100,6)
ball    = Object(200,200,10,10,2)
ballV   = [1.0,0.0]

def setVector(l):
    ballV[1]+=0.03*l

#System
clock = pygame.time.Clock()
isOpen = True
while isOpen:
    #Controls
    for event in pygame.event.get():
        if event.type == pygame.QUIT: isOpen=False

    keys=pygame.key.get_pressed()
    if(keys[pygame.K_w]):control1[1]=1.0
    else:control1[1]=0.0
    if(keys[pygame.K_s]):control1[0]=1.0
    else:control1[0]=0.0

    if(keys[pygame.K_o]):control2[1]=1.0
    else:control2[1]=0.0
    if(keys[pygame.K_l]):control2[0]=1.0
    else:control2[0]=0.0
    #control2 = [0.0,0.0]
    inputToAI=[ball.pos[0]/400,ball.pos[1]/400,ballV[0]/5,ballV[1]/5,player2.pos[1]/400]
    AIControls=model.predict([inputToAI])
    control2=AIControls[0]
    print("AI:",AIControls)

    #Train Values
    control=np.array(control1)
    values=np.array ([((400-ball.pos[0])/400),ball.pos[1]/400,((5-ballV[0])/5),ballV[1]/5,player1.pos[1]/400])
    inputs.append(values)
    outputs.append(control)

    #inputs=np.insert(inputs,values,axis=2)
    #outputs=np.instert(outputs,control,axis=2)

    #Move
    moveLimit = 0.3
    if(control1[0]>moveLimit):player1.move(0,1)
    if(control1[1]>moveLimit):player1.move(0,-1)

    if(control2[0]>moveLimit):player2.move(0,1)
    if(control2[1]>moveLimit):player2.move(0,-1)

    ball.move(ballV[0],ballV[1])

    #Collision
    if(ball.pos[1]<0) : ballV[1]*=-1
    elif(ball.pos[1]+ball.size[1]>400):ballV[1]*=-1

    if(player1.getColBlock(ball.pos, ball.size)) :
        ballV[0]*=-1
        setVector((ball.pos[1]+(ball.size[1]/2))-(player1.pos[1]+(player1.size[1]/2)))
    elif(player2.getColBlock(ball.pos, ball.size)) :
        ballV[0]*=-1
        setVector((ball.pos[1]+(ball.size[1]/2))-(player2.pos[1]+(player2.size[1]/2)))
        resArrays()

    if(player1.pos[1]<0):player1.pos[1]=0
    elif(player1.pos[1]+player1.size[1]>400):player1.pos[1]=300
    if(player2.pos[1]<0):player2.pos[1]=0
    elif(player2.pos[1]+player2.size[1]>400):player2.pos[1]=300

        #Win
    if(ball.pos[0]+ball.size[0]>400):
        ball.pos=[200,200]
        score[0]+=1
        ballV=[-1.0,0.0]
        print("P1:",score[0]," P2:",score[1])
        #Train Model
            #wu
        inputsT=np.vstack(inputs)
        outputsT=np.vstack(outputs)
        print("I:",inputsT)
        print("O:",outputsT)
        model.fit(inputsT,outputsT,callbacks=[cp_callback])
        #Reset Inputs and Outputs
        resArrays()
        player1.pos=[0,150]
        player2.pos=[390,150]
    elif(ball.pos[0]<0):
        ball.pos=[200,200]
        score[1]+=1
        ballV=[1.0,0.0]
        print("P1:",score[0]," P2:",score[1])
        #Reset Inputs and Outputs
        resArrays()
        player1.pos=[0,150]
        player2.pos=[390,150]

    #Gae System
    #print(ballV[1])

    #Drawning
    screen.fill(c_off)
    player1.print()
    player2.print()
    ball.print()
    pygame.display.flip()
    clock.tick(60)


import streamlit as st
import pandas as pd

st.set_page_config(layout="wide")

col1, col2, col3 = st.columns([1, 2, 0.25])

df = pd.read_csv("data.csv", sep=";")

with col1:
    st.image("images/photo.png", width=300)

with col2:
    st.title("Başak Dilara Çevik")
    content1 = """After graduating from the department of economics,
      I started to pursue my master's degree in economics and had the opportunity to develop
       myself in the research area.
        Currently, I am conducting a thesis study to accelerate the adoption of electric vehicles
         in Turkey within the scope of sustainability. In this process,
          I significantly improved my knowledge of game development with Unity, project management,
          and game art with the help of Oyun ve Uygulama Akademisi.
          Besides all these, I have been actively developing myself in the fields of data science and machine learning
          for the last three years, participating in various events and communities. :)"""
    st.info(content1)

content2 = """This is my portfolio. You can navigate between the bars to see my projects."""
st.subheader(content2)

tab1, tab2, tab3, tab4, tab5, tab6,\
tab7, tab8, tab9, tab10, \
tab11, tab12, \
tab13, tab14, tab15 = st.tabs(["To-Do App", "Portfolio", "PDF Generation", "Excel Invoices to PDF",
                                  "Email News", "Weather API", "Book Sentiment Analysis",
                                  "Email Webcam Object Detection", "Web Scraping Musical Events",
                                  "Hotel Booking", "Super Mario Game Code Inspection",
                                  "Student Management System", "Chatbot", "Astronomy Image of the Day", "Weather Forecast"])

#if you prefer columnwise rather than tabwise
# for index, row in df.iterrows():
#     st.header(row["title"])
#     st.write(row["description"])
#     st.image("images/" + row["image"])
#     st.write("[Source Code](https://badice.com.tr)")

with tab1:
   st.header("To-Do App")
   st.write(df["description"][0])
   st.image("images/1.png", width=500)
   st.write(f"[Source Code]({df['url'][0]})")

with tab2:
   st.header("Portfolio")
   st.write(df["description"][1])
   st.image("images/2.png", width=500)
   st.write(f"[Source Code]({df['url'][1]})")

with tab3:
   st.header("Excel Invoices to PDF")
   st.write(df["description"][2])
   st.image("images/3.png", width=500)
   st.write(f"[Source Code]({df['url'][2]})")

with tab4:
    st.header("")
    st.write(df["description"][3])
    st.image("images/4.png", width=500)
    st.write(f"[Source Code]({df['url'][3]})")

with tab5:
    st.header("")
    st.write(df["description"][4])
    st.image("images/5.png", width=500)
    st.write(f"[Source Code]({df['url'][4]})")

with tab6:
    st.header("")
    st.write(df["description"][5])
    st.image("images/6.png", width=500)
    st.write(f"[Source Code]({df['url'][5]})")

with tab7:
    st.header("")
    st.write(df["description"][6])
    st.image("images/7.png", width=500)
    st.write(f"[Source Code]({df['url'][6]})")

with tab8:
    st.header("")
    st.write(df["description"][7])
    st.image("images/8.png", width=500)
    st.write(f"[Source Code]({df['url'][7]})")

with tab9:
    st.header("")
    st.write(df["description"][8])
    st.image("images/9.png", width=500)
    st.write(f"[Source Code]({df['url'][8]})")

with tab10:
    st.header("")
    st.write(df["description"][9])
    st.image("images/10.png", width=500)
    st.write(f"[Source Code]({df['url'][9]})")

with tab11:
    st.header("")
    st.write(df["description"][10])
    st.image("images/11.png", width=500)
    st.write(f"[Source Code]({df['url'][10]})")

with tab12:
    st.header("")
    st.write(df["description"][11])
    st.image("images/12.png", width=500)
    st.write(f"[Source Code]({df['url'][11]})")

with tab13:
    st.header("")
    st.write(df["description"][12])
    st.image("images/13.png", width=500)
    st.write(f"[Source Code]({df['url'][12]})")

with tab14:
    st.header("")
    st.write(df["description"][13])
    st.image("images/14.png", width=500)
    st.write(f"[Streamlit Website]({df['url'][13]})")

with tab15:
    st.header("")
    st.write(df["description"][16])
    st.image("images/16.png", width=500)
    st.write(f"[Streamlit Website]({df['url'][16]})")


import time

class Student:
    def __init__(self, last, first, ssn, email, age):
        self.last = last
        self.first = first
        self.ssn = ssn
        self.email = email
        self.age = int(age)

    def __str__(self):
        return '{} {} {}'.format(self.ssn, self.first, self.last)

    def __eq__(self, other):
        return self.ssn == other.ssn

    def __int__(self):
        return self.age

    def __float__(self):
        return float(self.__int__())

def read_names(students):
    print('READING NAMES')
    f = open('InsertNames.txt', 'r')
    t = 0
    start = time.time()
    for line in f:
        last, first, ssn, email, age = line.split()
        s = Student(last, first, ssn, email, age)
        skip = False
        for student in students:
            if student == s:
                print('Could not add:', s, '-> Duplicate:', student, 'already exists')
                skip = True
                break
        if skip:
            continue
        students.append(s)
        t += 1
    end = time.time()

    print(t, 'records created.')
    print('Time: {:04f}'.format(end - start))
    f.close()
    print()

def traverse_names(students):
    print('TRAVERSING NAMES')
    total = 0.0
    count = 0
    start = time.time()
    for student in students:
        total += int(student)
        count += 1
    avg_age = total / count
    end = time.time()
    print(count, 'records read')
    print('Average Age: {:04f}'.format(avg_age))
    print('Time: {:04f}'.format(end - start))
    print()

def delete_names(students):
    print('DELETING NAMES')
    f = open('DeleteNames.txt', 'r')
    t = 0
    start = time.time()
    for line in f:
        ssn = line.strip()
        deleted = False
        for i in range(len(students)):
            student = students[i]
            if student.ssn == ssn:
                del students[i]
                t += 1
                deleted = True
                break
        if deleted:
            continue
        print(ssn, 'not found')
    end = time.time()
    print(t, 'records deleted')
    print('Time: {:04f}'.format(end - start))
    f.close()
    print()

def retrieve_names(students):
    print('RETRIEVING NAMES')
    f = open('RetrieveNames.txt', 'r')
    total = 0.0
    count = 0
    start = time.time()
    for line in f:
        ssn = line.strip()
        found = False
        for student in students:
            if student.ssn == ssn:
                found = True
                total += int(student)
                count += 1
                break
        if found:
            continue
        print(ssn, 'not found')
    avg_age = total / count
    end = time.time()
    print(count, 'records retrieved')
    print('Average Age: {:04f}'.format(avg_age))
    print('Time: {:04f}'.format(end - start))
    f.close()
    print()

def main():
    start = time.time()
    names = []
    read_names(names)
    traverse_names(names)
    delete_names(names)
    retrieve_names(names)
    end = time.time()
    print('Total Time: {:04f}'.format(end - start))

if __name__ == '__main__':
    main()


from flask import Flask, render_template, url_for, request, redirect
import csv
app = Flask(__name__)
# print(__name__)

# @app.route('/<username>/<int:post_id>')
# def hello_world(username=None, post_id=None):
#     return render_template('./index1.html', name=username, post_id=post_id)

# @app.route('/')
# def hello_world():
#     return render_template('./index1.html')

@app.route('/blog')
def blog():
    return 'Hello, blog!'

@app.route('/')
def hello_home():
    return render_template('./index.html')

@app.route('/<string:page_name>')
def html_page(page_name):
    return render_template(f'./{page_name}.html')

def write_to_file(data):
    with open('database.txt', mode='a') as database:
        email = data["email"]
        subject = data["subject"]
        message = data["message"]
        file = database.write(f'\n {email},{subject},{message}')

def write_to_csv(data):
    with open('database.csv', mode='a') as database2:
        email = data["email"]
        subject = data["subject"]
        message = data["message"]
        csv_writer = csv.writer(database2, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
        csv_writer.writerow([email, subject, message])

@app.route('/submit_form', methods=['POST', 'GET'])
def submit_form():
    if request.method == 'POST':
        try:
            data = request.form.to_dict()
            # print(data)
            # write_to_csv(data)
            # write_to_file(data)
            return redirect('/thank_you')
        except:
            return 'Something went wrong'

    else:
        return 'problem'
    # error = None
    # if request.method == 'POST':
    #     if valid_login(request.form['username'],
    #                    request.form['password']):
    #         return log_the_user_in(request.form['username'])
    #     else:
    #         error = 'Invalid username/password'
    # # the code below is executed if the request method
    # was GET or the credentials were invalid
    # return render_template('login.html', error=error)
#
# @app.route('/works')
# def hello_work():
#     return render_template('./works.html')
#
#
# @app.route('/about')
# def hello_about():
#     return render_template('./about.html')
#
#
# @app.route('/contact')
# def hello_contact():
#     return render_template('./contact.html')
#
#
# @app.route('/components')
# def hello_components():
#     return render_template('./components.html')