# Dataset utils and dataloaders

import glob, hashlib, logging, math, os, random, shutil, time
from itertools import repeat
from multiprocessing.pool import ThreadPool
from pathlib import Path
from threading import Thread
import cv2, numpy as np, torch, torch.nn.functional as F
from PIL import Image, ExifTags
from torch.utils.data import Dataset
from tqdm import tqdm
from utils.general import check_requirements, xyxy2xywh, xywh2xyxy, xywhn2xyxy, xyn2xy, segment2box, segments2boxes, resample_segments, clean_str
from utils.torch_utils import torch_distributed_zero_first
help_url = 'https://github.com/ultralytics/yolov5/wiki/Train-Custom-Data'
img_formats = ['bmp', 'jpg', 'jpeg', 'png', 'tif', 'tiff', 'dng', 'webp', 'mpo']
vid_formats = ['mov', 'avi', 'mp4', 'mpg', 'mpeg', 'm4v', 'wmv', 'mkv']
logger = logging.getLogger(__name__)
for orientation in ExifTags.TAGS.keys():
    if ExifTags.TAGS[orientation] == 'Orientation':
        break

def get_hash(paths):
    size = sum(os.path.getsize(p) for p in paths if os.path.exists(p))
    h = hashlib.md5(str(size).encode())
    h.update(''.join(paths).encode())
    return h.hexdigest()

def exif_size(img):
    s = img.size
    try:
        rotation = dict(img._getexif().items())[orientation]
        if rotation == 6:
            s = (
             s[1], s[0])
        else:
            if rotation == 8:
                s = (
                 s[1], s[0])
    except:
        pass

    return s

def create_dataloader(path, imgsz, batch_size, stride, opt, hyp=None, augment=False, cache=False, pad=0.0, rect=False, rank=-1, world_size=1, workers=8, image_weights=False, quad=False, prefix=''):
    with torch_distributed_zero_first(rank):
        dataset = LoadImagesAndLabels(path, imgsz, batch_size, augment=augment,
          hyp=hyp,
          rect=rect,
          cache_images=cache,
          single_cls=(opt.single_cls),
          stride=(int(stride)),
          pad=pad,
          image_weights=image_weights,
          prefix=prefix)
    batch_size = min(batch_size, len(dataset))
    nw = min([os.cpu_count() // world_size, batch_size if batch_size > 1 else 0, workers])
    sampler = torch.utils.data.distributed.DistributedSampler(dataset) if rank != -1 else None
    loader = torch.utils.data.DataLoader if image_weights else InfiniteDataLoader
    dataloader = loader(dataset, batch_size=batch_size,
      num_workers=nw,
      sampler=sampler,
      pin_memory=True,
      collate_fn=(LoadImagesAndLabels.collate_fn4 if quad else LoadImagesAndLabels.collate_fn))
    return (dataloader, dataset)

class InfiniteDataLoader(torch.utils.data.dataloader.DataLoader):
    __doc__ = ' Dataloader that reuses workers\n    Uses same syntax as vanilla DataLoader\n    '

    def __init__(self, *args, **kwargs):
        (super().__init__)(*args, **kwargs)
        object.__setattr__(self, 'batch_sampler', _RepeatSampler(self.batch_sampler))
        self.iterator = super().__iter__()

    def __len__(self):
        return len(self.batch_sampler.sampler)

    def __iter__(self):
        for i in range(len(self)):
            yield next(self.iterator)

class _RepeatSampler(object):
    __doc__ = ' Sampler that repeats forever\n    Args:\n        sampler (Sampler)\n    '

    def __init__(self, sampler):
        self.sampler = sampler

    def __iter__(self):
        while True:
            yield from iter(self.sampler)

        if False:
            yield None

class LoadImages:

    def __init__(self, path, img_size=640, stride=32):
        p = str(Path(path).absolute())
        if '*' in p:
            files = sorted(glob.glob(p, recursive=True))
        else:
            if os.path.isdir(p):
                files = sorted(glob.glob(os.path.join(p, '*.*')))
            else:
                if os.path.isfile(p):
                    files = [
                     p]
                else:
                    raise Exception(f"ERROR: {p} does not exist")
                images = [x for x in files if x.split('.')[(-1)].lower() in img_formats]
                videos = [x for x in files if x.split('.')[(-1)].lower() in vid_formats]
                ni, nv = len(images), len(videos)
                self.img_size = img_size
                self.stride = stride
                self.files = images + videos
                self.nf = ni + nv
                self.video_flag = [False] * ni + [True] * nv
                self.mode = 'image'
                if any(videos):
                    self.new_video(videos[0])
                else:
                    self.cap = None
            assert self.nf > 0, f"No images or videos found in {p}. Supported formats are:\nimages: {img_formats}\nvideos: {vid_formats}"

    def __iter__(self):
        self.count = 0
        return self

    def __next__(self):
        if self.count == self.nf:
            raise StopIteration
        else:
            path = self.files[self.count]
            if self.video_flag[self.count]:
                self.mode = 'video'
                ret_val, img0 = self.cap.read()
                if not ret_val:
                    self.count += 1
                    self.cap.release()
                    if self.count == self.nf:
                        raise StopIteration
                    else:
                        path = self.files[self.count]
                        self.new_video(path)
                        ret_val, img0 = self.cap.read()
                self.frame += 1
                print(f"video {self.count + 1}/{self.nf} ({self.frame}/{self.frames}) {path}: ", end='')
            else:
                self.count += 1
                img0 = cv2.imread(path)
                assert img0 is not None, 'Image Not Found ' + path
                print(f"image {self.count}/{self.nf} {path}: ", end='')
        img = letterbox(img0, (self.img_size), stride=(self.stride))[0]
        img = img[:, :, ::-1].transpose(2, 0, 1)
        img = np.ascontiguousarray(img)
        return (
         path, img, img0, self.cap)

    def new_video(self, path):
        self.frame = 0
        self.cap = cv2.VideoCapture(path)
        self.frames = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))

    def __len__(self):
        return self.nf

class LoadWebcam:

    def __init__(self, pipe='0', img_size=640, stride=32):
        self.img_size = img_size
        self.stride = stride
        if pipe.isnumeric():
            pipe = eval(pipe)
        self.pipe = pipe
        self.cap = cv2.VideoCapture(pipe)
        self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 3)

    def __iter__(self):
        self.count = -1
        return self

    def __next__(self):
        self.count += 1
        if cv2.waitKey(1) == ord('q'):
            self.cap.release()
            cv2.destroyAllWindows()
            raise StopIteration
        else:
            if self.pipe == 0:
                ret_val, img0 = self.cap.read()
                img0 = cv2.flip(img0, 1)
            else:
                n = 0
                while 1:
                    n += 1
                    self.cap.grab()
                    if n % 30 == 0:
                        ret_val, img0 = self.cap.retrieve()
                        if ret_val:
                            break

            assert ret_val, f"Camera Error {self.pipe}"
        img_path = 'webcam.jpg'
        print(f"webcam {self.count}: ", end='')
        img = letterbox(img0, (self.img_size), stride=(self.stride))[0]
        img = img[:, :, ::-1].transpose(2, 0, 1)
        img = np.ascontiguousarray(img)
        return (
         img_path, img, img0, None)

    def __len__(self):
        return 0

class LoadStreams:

    def __init__(self, sources='streams.txt', img_size=640, stride=32):
        self.mode = 'stream'
        self.img_size = img_size
        self.stride = stride
        if os.path.isfile(sources):
            with open(sources, 'r') as (f):
                sources = [x.strip() for x in f.read().strip().splitlines() if len(x.strip())]
        else:
            sources = [
             sources]
        n = len(sources)
        self.imgs, self.fps, self.frames, self.threads = ([None] * n, [0] * n, [0] * n, [None] * n)
        self.sources = [clean_str(x) for x in sources]
        for i, s in enumerate(sources):
            print(f"{i + 1}/{n}: {s}... ", end='')
            if 'youtube.com/' in s or 'youtu.be/' in s:
                check_requirements(('pafy', 'youtube_dl'))
                import pafy
                s = pafy.new(s).getbest(preftype='mp4').url
            s = eval(s) if s.isnumeric() else s
            cap = cv2.VideoCapture(s)
            assert cap.isOpened(), f"Failed to open {s}"
            w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            self.fps[i] = max(cap.get(cv2.CAP_PROP_FPS) % 100, 0) or 30.0
            self.frames[i] = max(int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), 0) or float('inf')
            _, self.imgs[i] = cap.read()
            self.threads[i] = Thread(target=(self.update), args=[i, cap], daemon=True)
            print(f" success ({self.frames[i]} frames {w}x{h} at {self.fps[i]:.2f} FPS)")
            self.threads[i].start()

        print('')
        s = np.stack([letterbox(x, (self.img_size), stride=(self.stride))[0].shape for x in self.imgs], 0)
        self.rect = np.unique(s, axis=0).shape[0] == 1
        if not self.rect:
            print('WARNING: Different stream shapes detected. For optimal performance supply similarly-shaped streams.')

    def update(self, i, cap):
        n, f = 0, self.frames[i]
        while cap.isOpened() and n < f:
            n += 1
            cap.grab()
            if n % 4:
                success, im = cap.retrieve()
                self.imgs[i] = im if success else self.imgs[i] * 0
            time.sleep(1 / self.fps[i])

    def __iter__(self):
        self.count = -1
        return self

    def __next__(self):
        self.count += 1
        if not all(x.is_alive() for x in self.threads) or cv2.waitKey(1) == ord('q'):
            cv2.destroyAllWindows()
            raise StopIteration
        img0 = self.imgs.copy()
        img = [letterbox(x, (self.img_size), auto=(self.rect), stride=(self.stride))[0] for x in img0]
        img = np.stack(img, 0)
        img = img[:, :, :, ::-1].transpose(0, 3, 1, 2)
        img = np.ascontiguousarray(img)
        return (
         self.sources, img, img0, None)

    def __len__(self):
        return 0

def img2label_paths(img_paths):
    sa, sb = os.sep + 'images' + os.sep, os.sep + 'labels' + os.sep
    return ['txt'.join(x.replace(sa, sb, 1).rsplit(x.split('.')[(-1)], 1)) for x in img_paths]

class LoadImagesAndLabels(Dataset):

    def __init__(self, path, img_size=640, batch_size=16, augment=False, hyp=None, rect=False, image_weights=False, cache_images=False, single_cls=False, stride=32, pad=0.0, prefix=''):
        self.img_size = img_size
        self.augment = augment
        self.hyp = hyp
        self.image_weights = image_weights
        self.rect = False if image_weights else rect
        self.mosaic = self.augment and not self.rect
        self.mosaic_border = [-img_size // 2, -img_size // 2]
        self.stride = stride
        self.path = path
        try:
            f = []
            for p in path if isinstance(path, list) else [path]:
                p = Path(p)
                if p.is_dir():
                    f += glob.glob((str(p / '**' / '*.*')), recursive=True)
                elif p.is_file():
                    with open(p, 'r') as (t):
                        t = t.read().strip().splitlines()
                        parent = str(p.parent) + os.sep
                        f += [x.replace('./', parent) if x.startswith('./') else x for x in t]
                else:
                    raise Exception(f"{prefix}{p} does not exist")

            self.img_files = sorted([x.replace('/', os.sep) for x in f if x.split('.')[(-1)].lower() in img_formats])
            assert self.img_files, f"{prefix}No images found"
        except Exception as e:
            raise Exception(f"{prefix}Error loading data from {path}: {e}\nSee {help_url}")

        self.label_files = img2label_paths(self.img_files)
        cache_path = (p if p.is_file() else Path(self.label_files[0]).parent).with_suffix('.cache')
        if cache_path.is_file():
            cache, exists = torch.load(cache_path), True
            if cache['hash'] != get_hash(self.label_files + self.img_files):
                cache, exists = self.cache_labels(cache_path, prefix), False
        else:
            cache, exists = self.cache_labels(cache_path, prefix), False
        nf, nm, ne, nc, n = cache.pop('results')
        if exists:
            d = f"Scanning '{cache_path}' images and labels... {nf} found, {nm} missing, {ne} empty, {nc} corrupted"
            tqdm(None, desc=(prefix + d), total=n, initial=n)
        if not nf > 0:
            if not not augment:
                raise AssertionError(f"{prefix}No labels in {cache_path}. Can not train without labels. See {help_url}")
        cache.pop('hash')
        cache.pop('version')
        labels, shapes, self.segments = zip(*cache.values())
        self.labels = list(labels)
        self.shapes = np.array(shapes, dtype=(np.float64))
        self.img_files = list(cache.keys())
        self.label_files = img2label_paths(cache.keys())
        if single_cls:
            for x in self.labels:
                x[:, 0] = 0

        n = len(shapes)
        bi = np.floor(np.arange(n) / batch_size).astype(np.int)
        nb = bi[(-1)] + 1
        self.batch = bi
        self.n = n
        self.indices = range(n)
        if self.rect:
            s = self.shapes
            ar = s[:, 1] / s[:, 0]
            irect = ar.argsort()
            self.img_files = [self.img_files[i] for i in irect]
            self.label_files = [self.label_files[i] for i in irect]
            self.labels = [self.labels[i] for i in irect]
            self.shapes = s[irect]
            ar = ar[irect]
            shapes = [
             [
              1, 1]] * nb
            for i in range(nb):
                ari = ar[(bi == i)]
                mini, maxi = ari.min(), ari.max()
                if maxi < 1:
                    shapes[i] = [
                     maxi, 1]
                elif mini > 1:
                    shapes[i] = [
                     1, 1 / mini]

            self.batch_shapes = np.ceil(np.array(shapes) * img_size / stride + pad).astype(np.int) * stride
        self.imgs = [
         None] * n
        if cache_images:
            gb = 0
            self.img_hw0, self.img_hw = [None] * n, [None] * n
            results = ThreadPool(8).imap(lambda x: load_image(*x), zip(repeat(self), range(n)))
            pbar = tqdm((enumerate(results)), total=n)
            for i, x in pbar:
                self.imgs[i], self.img_hw0[i], self.img_hw[i] = x
                gb += self.imgs[i].nbytes
                pbar.desc = f"{prefix}Caching images ({gb / 1000000000.0:.1f}GB)"

            pbar.close()

    def cache_labels(self, path=Path('./labels.cache'), prefix=''):
        x = {}
        nm, nf, ne, nc = (0, 0, 0, 0)
        pbar = tqdm((zip(self.img_files, self.label_files)), desc='Scanning images', total=(len(self.img_files)))
        for i, (im_file, lb_file) in enumerate(pbar):
            try:
                im = Image.open(im_file)
                im.verify()
                shape = exif_size(im)
                segments = []
                assert (shape[0] > 9) & (shape[1] > 9), f"image size {shape} <10 pixels"
                assert im.format.lower() in img_formats, f"invalid image format {im.format}"
                if os.path.isfile(lb_file):
                    nf += 1
                    with open(lb_file, 'r') as (f):
                        l = [x.split() for x in f.read().strip().splitlines() if len(x)]
                        if any([len(x) > 8 for x in l]):
                            classes = np.array([x[0] for x in l], dtype=(np.float32))
                            segments = [np.array((x[1:]), dtype=(np.float32)).reshape(-1, 2) for x in l]
                            l = np.concatenate((classes.reshape(-1, 1), segments2boxes(segments)), 1)
                        l = np.array(l, dtype=(np.float32))
                    if len(l):
                        if not l.shape[1] == 5:
                            raise AssertionError('labels require 5 columns each')
                        else:
                            assert (l >= 0).all(), 'negative labels'
                            assert (l[:, 1:] <= 1).all(), 'non-normalized or out of bounds coordinate labels'
                        assert np.unique(l, axis=0).shape[0] == l.shape[0], 'duplicate labels'
                    else:
                        ne += 1
                        l = np.zeros((0, 5), dtype=(np.float32))
                else:
                    nm += 1
                    l = np.zeros((0, 5), dtype=(np.float32))
                x[im_file] = [
                 l, shape, segments]
            except Exception as e:
                nc += 1
                logging.info(f"{prefix}WARNING: Ignoring corrupted image and/or label {im_file}: {e}")

            pbar.desc = f"{prefix}Scanning '{path.parent / path.stem}' images and labels... {nf} found, {nm} missing, {ne} empty, {nc} corrupted"

        pbar.close()
        if nf == 0:
            logging.info(f"{prefix}WARNING: No labels found in {path}. See {help_url}")
        x['hash'] = get_hash(self.label_files + self.img_files)
        x['results'] = (nf, nm, ne, nc, i + 1)
        x['version'] = 0.2
        try:
            torch.save(x, path)
            logging.info(f"{prefix}New cache created: {path}")
        except Exception as e:
            logging.info(f"{prefix}WARNING: Cache directory {path.parent} is not writeable: {e}")

        return x

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

    def __getitem__(self, index):
        index = self.indices[index]
        hyp = self.hyp
        mosaic = self.mosaic and random.random() < hyp['mosaic']
        if mosaic:
            img, labels = load_mosaic(self, index)
            shapes = None
            if random.random() < hyp['mixup']:
                img2, labels2 = load_mosaic(self, random.randint(0, self.n - 1))
                r = np.random.beta(8.0, 8.0)
                img = (img * r + img2 * (1 - r)).astype(np.uint8)
                labels = np.concatenate((labels, labels2), 0)
        else:
            img, (h0, w0), (h, w) = load_image(self, index)
            shape = self.batch_shapes[self.batch[index]] if self.rect else self.img_size
            img, ratio, pad = letterbox(img, shape, auto=False, scaleup=(self.augment))
            shapes = ((h0, w0), ((h / h0, w / w0), pad))
            labels = self.labels[index].copy()
            if labels.size:
                labels[:, 1:] = xywhn2xyxy((labels[:, 1:]), (ratio[0] * w), (ratio[1] * h), padw=(pad[0]), padh=(pad[1]))
            if self.augment:
                if not mosaic:
                    img, labels = random_perspective(img, labels, degrees=(hyp['degrees']),
                      translate=(hyp['translate']),
                      scale=(hyp['scale']),
                      shear=(hyp['shear']),
                      perspective=(hyp['perspective']))
                augment_hsv(img, hgain=(hyp['hsv_h']), sgain=(hyp['hsv_s']), vgain=(hyp['hsv_v']))
            nL = len(labels)
            if nL:
                labels[:, 1:5] = xyxy2xywh(labels[:, 1:5])
                labels[:, [2, 4]] /= img.shape[0]
                labels[:, [1, 3]] /= img.shape[1]
            if self.augment:
                if random.random() < hyp['flipud']:
                    img = np.flipud(img)
                    if nL:
                        labels[:, 2] = 1 - labels[:, 2]
                if random.random() < hyp['fliplr']:
                    img = np.fliplr(img)
                    if nL:
                        labels[:, 1] = 1 - labels[:, 1]
            labels_out = torch.zeros((nL, 6))
            if nL:
                labels_out[:, 1:] = torch.from_numpy(labels)
            img = img[:, :, ::-1].transpose(2, 0, 1)
            img = np.ascontiguousarray(img)
            return (
             torch.from_numpy(img), labels_out, self.img_files[index], shapes)

    @staticmethod
    def collate_fn(batch):
        img, label, path, shapes = zip(*batch)
        for i, l in enumerate(label):
            l[:, 0] = i

        return (
         torch.stack(img, 0), torch.cat(label, 0), path, shapes)

    @staticmethod
    def collate_fn4(batch):
        img, label, path, shapes = zip(*batch)
        n = len(shapes) // 4
        img4, label4, path4, shapes4 = ([], [], path[:n], shapes[:n])
        ho = torch.tensor([[0.0, 0, 0, 1, 0, 0]])
        wo = torch.tensor([[0.0, 0, 1, 0, 0, 0]])
        s = torch.tensor([[1, 1, 0.5, 0.5, 0.5, 0.5]])
        for i in range(n):
            i *= 4
            if random.random() < 0.5:
                im = F.interpolate((img[i].unsqueeze(0).float()), scale_factor=2.0, mode='bilinear', align_corners=False)[0].type(img[i].type())
                l = label[i]
            else:
                im = torch.cat((torch.cat((img[i], img[(i + 1)]), 1), torch.cat((img[(i + 2)], img[(i + 3)]), 1)), 2)
                l = torch.cat((label[i], label[(i + 1)] + ho, label[(i + 2)] + wo, label[(i + 3)] + ho + wo), 0) * s
            img4.append(im)
            label4.append(l)

        for i, l in enumerate(label4):
            l[:, 0] = i

        return (torch.stack(img4, 0), torch.cat(label4, 0), path4, shapes4)

def load_image(self, index):
    img = self.imgs[index]
    if img is None:
        path = self.img_files[index]
        img = cv2.imread(path)
        assert img is not None, 'Image Not Found ' + path
        h0, w0 = img.shape[:2]
        r = self.img_size / max(h0, w0)
        if r != 1:
            img = cv2.resize(img, (int(w0 * r), int(h0 * r)), interpolation=cv2.INTER_AREA if (r < 1 and not self.augment) else (cv2.INTER_LINEAR))
        return (img, (h0, w0), img.shape[:2])
    else:
        return (
         self.imgs[index], self.img_hw0[index], self.img_hw[index])

def augment_hsv(img, hgain=0.5, sgain=0.5, vgain=0.5):
    r = np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain] + 1
    hue, sat, val = cv2.split(cv2.cvtColor(img, cv2.COLOR_BGR2HSV))
    dtype = img.dtype
    x = np.arange(0, 256, dtype=(np.int16))
    lut_hue = (x * r[0] % 180).astype(dtype)
    lut_sat = np.clip(x * r[1], 0, 255).astype(dtype)
    lut_val = np.clip(x * r[2], 0, 255).astype(dtype)
    img_hsv = cv2.merge((cv2.LUT(hue, lut_hue), cv2.LUT(sat, lut_sat), cv2.LUT(val, lut_val))).astype(dtype)
    cv2.cvtColor(img_hsv, (cv2.COLOR_HSV2BGR), dst=img)

def hist_equalize(img, clahe=True, bgr=False):
    yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV if bgr else cv2.COLOR_RGB2YUV)
    if clahe:
        c = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
        yuv[:, :, 0] = c.apply(yuv[:, :, 0])
    else:
        yuv[:, :, 0] = cv2.equalizeHist(yuv[:, :, 0])
    return cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR if bgr else cv2.COLOR_YUV2RGB)

def load_mosaic(self, index):
    labels4, segments4 = [], []
    s = self.img_size
    yc, xc = [int(random.uniform(-x, 2 * s + x)) for x in self.mosaic_border]
    indices = [index] + random.choices((self.indices), k=3)
    for i, index in enumerate(indices):
        img, _, (h, w) = load_image(self, index)
        if i == 0:
            img4 = np.full((s * 2, s * 2, img.shape[2]), 114, dtype=(np.uint8))
            x1a, y1a, x2a, y2a = (max(xc - w, 0), max(yc - h, 0), xc, yc)
            x1b, y1b, x2b, y2b = (w - (x2a - x1a), h - (y2a - y1a), w, h)
        else:
            if i == 1:
                x1a, y1a, x2a, y2a = (
                 xc, max(yc - h, 0), min(xc + w, s * 2), yc)
                x1b, y1b, x2b, y2b = (0, h - (y2a - y1a), min(w, x2a - x1a), h)
            else:
                if i == 2:
                    x1a, y1a, x2a, y2a = (
                     max(xc - w, 0), yc, xc, min(s * 2, yc + h))
                    x1b, y1b, x2b, y2b = (w - (x2a - x1a), 0, w, min(y2a - y1a, h))
                else:
                    if i == 3:
                        x1a, y1a, x2a, y2a = (
                         xc, yc, min(xc + w, s * 2), min(s * 2, yc + h))
                        x1b, y1b, x2b, y2b = (0, 0, min(w, x2a - x1a), min(y2a - y1a, h))
        img4[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b]
        padw = x1a - x1b
        padh = y1a - y1b
        labels, segments = self.labels[index].copy(), self.segments[index].copy()
        if labels.size:
            labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padw, padh)
            segments = [xyn2xy(x, w, h, padw, padh) for x in segments]
        labels4.append(labels)
        segments4.extend(segments)

    labels4 = np.concatenate(labels4, 0)
    for x in (labels4[:, 1:], *segments4):
        np.clip(x, 0, (2 * s), out=x)

    img4, labels4 = random_perspective(img4, labels4, segments4, degrees=(self.hyp['degrees']),
      translate=(self.hyp['translate']),
      scale=(self.hyp['scale']),
      shear=(self.hyp['shear']),
      perspective=(self.hyp['perspective']),
      border=(self.mosaic_border))
    return (
     img4, labels4)

def load_mosaic9(self, index):
    labels9, segments9 = [], []
    s = self.img_size
    indices = [index] + random.choices((self.indices), k=8)
    for i, index in enumerate(indices):
        img, _, (h, w) = load_image(self, index)
        if i == 0:
            img9 = np.full((s * 3, s * 3, img.shape[2]), 114, dtype=(np.uint8))
            h0, w0 = h, w
            c = (s, s, s + w, s + h)
        else:
            if i == 1:
                c = (
                 s, s - h, s + w, s)
            else:
                if i == 2:
                    c = (
                     s + wp, s - h, s + wp + w, s)
                else:
                    if i == 3:
                        c = (
                         s + w0, s, s + w0 + w, s + h)
                    else:
                        if i == 4:
                            c = (
                             s + w0, s + hp, s + w0 + w, s + hp + h)
                        else:
                            if i == 5:
                                c = (
                                 s + w0 - w, s + h0, s + w0, s + h0 + h)
                            else:
                                if i == 6:
                                    c = (
                                     s + w0 - wp - w, s + h0, s + w0 - wp, s + h0 + h)
                                else:
                                    if i == 7:
                                        c = (
                                         s - w, s + h0 - h, s, s + h0)
                                    else:
                                        if i == 8:
                                            c = (
                                             s - w, s + h0 - hp - h, s, s + h0 - hp)
        padx, pady = c[:2]
        x1, y1, x2, y2 = [max(x, 0) for x in c]
        labels, segments = self.labels[index].copy(), self.segments[index].copy()
        if labels.size:
            labels[:, 1:] = xywhn2xyxy(labels[:, 1:], w, h, padx, pady)
            segments = [xyn2xy(x, w, h, padx, pady) for x in segments]
        labels9.append(labels)
        segments9.extend(segments)
        img9[y1:y2, x1:x2] = img[y1 - pady:, x1 - padx:]
        hp, wp = h, w

    yc, xc = [int(random.uniform(0, s)) for _ in self.mosaic_border]
    img9 = img9[yc:yc + 2 * s, xc:xc + 2 * s]
    labels9 = np.concatenate(labels9, 0)
    labels9[:, [1, 3]] -= xc
    labels9[:, [2, 4]] -= yc
    c = np.array([xc, yc])
    segments9 = [x - c for x in segments9]
    for x in (labels9[:, 1:], *segments9):
        np.clip(x, 0, (2 * s), out=x)

    img9, labels9 = random_perspective(img9, labels9, segments9, degrees=(self.hyp['degrees']),
      translate=(self.hyp['translate']),
      scale=(self.hyp['scale']),
      shear=(self.hyp['shear']),
      perspective=(self.hyp['perspective']),
      border=(self.mosaic_border))
    return (
     img9, labels9)

def replicate(img, labels):
    h, w = img.shape[:2]
    boxes = labels[:, 1:].astype(int)
    x1, y1, x2, y2 = boxes.T
    s = (x2 - x1 + (y2 - y1)) / 2
    for i in s.argsort()[:round(s.size * 0.5)]:
        x1b, y1b, x2b, y2b = boxes[i]
        bh, bw = y2b - y1b, x2b - x1b
        yc, xc = int(random.uniform(0, h - bh)), int(random.uniform(0, w - bw))
        x1a, y1a, x2a, y2a = [xc, yc, xc + bw, yc + bh]
        img[y1a:y2a, x1a:x2a] = img[y1b:y2b, x1b:x2b]
        labels = np.append(labels, [[labels[(i, 0)], x1a, y1a, x2a, y2a]], axis=0)

    return (img, labels)

def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32):
    shape = img.shape[:2]
    if isinstance(new_shape, int):
        new_shape = (
         new_shape, new_shape)
    r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
    if not scaleup:
        r = min(r, 1.0)
    ratio = (
     r, r)
    new_unpad = (int(round(shape[1] * r)), int(round(shape[0] * r)))
    dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]
    if auto:
        dw, dh = np.mod(dw, stride), np.mod(dh, stride)
    else:
        if scaleFill:
            dw, dh = (0.0, 0.0)
            new_unpad = (new_shape[1], new_shape[0])
            ratio = (new_shape[1] / shape[1], new_shape[0] / shape[0])
    dw /= 2
    dh /= 2
    if shape[::-1] != new_unpad:
        img = cv2.resize(img, new_unpad, interpolation=(cv2.INTER_LINEAR))
    top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
    left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
    img = cv2.copyMakeBorder(img, top, bottom, left, right, (cv2.BORDER_CONSTANT), value=color)
    return (img, ratio, (dw, dh))

def random_perspective(img, targets=(), segments=(), degrees=10, translate=0.1, scale=0.1, shear=10, perspective=0.0, border=(0, 0)):
    height = img.shape[0] + border[0] * 2
    width = img.shape[1] + border[1] * 2
    C = np.eye(3)
    C[(0, 2)] = -img.shape[1] / 2
    C[(1, 2)] = -img.shape[0] / 2
    P = np.eye(3)
    P[(2, 0)] = random.uniform(-perspective, perspective)
    P[(2, 1)] = random.uniform(-perspective, perspective)
    R = np.eye(3)
    a = random.uniform(-degrees, degrees)
    s = random.uniform(1 - scale, 1 + scale)
    R[:2] = cv2.getRotationMatrix2D(angle=a, center=(0, 0), scale=s)
    S = np.eye(3)
    S[(0, 1)] = math.tan(random.uniform(-shear, shear) * math.pi / 180)
    S[(1, 0)] = math.tan(random.uniform(-shear, shear) * math.pi / 180)
    T = np.eye(3)
    T[(0, 2)] = random.uniform(0.5 - translate, 0.5 + translate) * width
    T[(1, 2)] = random.uniform(0.5 - translate, 0.5 + translate) * height
    M = T @ S @ R @ P @ C
    if border[0] != 0 or border[1] != 0 or (M != np.eye(3)).any():
        if perspective:
            img = cv2.warpPerspective(img, M, dsize=(width, height), borderValue=(114,
                                                                                114,
                                                                                114))
        else:
            img = cv2.warpAffine(img, (M[:2]), dsize=(width, height), borderValue=(114,
                                                                                114,
                                                                                114))
    n = len(targets)
    if n:
        use_segments = any(x.any() for x in segments)
        new = np.zeros((n, 4))
        if use_segments:
            segments = resample_segments(segments)
            for i, segment in enumerate(segments):
                xy = np.ones((len(segment), 3))
                xy[:, :2] = segment
                xy = xy @ M.T
                xy = xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]
                new[i] = segment2box(xy, width, height)

        else:
            xy = np.ones((n * 4, 3))
            xy[:, :2] = targets[:, [1, 2, 3, 4, 1, 4, 3, 2]].reshape(n * 4, 2)
            xy = xy @ M.T
            xy = (xy[:, :2] / xy[:, 2:3] if perspective else xy[:, :2]).reshape(n, 8)
            x = xy[:, [0, 2, 4, 6]]
            y = xy[:, [1, 3, 5, 7]]
            new = np.concatenate((x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T
            new[:, [0, 2]] = new[:, [0, 2]].clip(0, width)
            new[:, [1, 3]] = new[:, [1, 3]].clip(0, height)
        i = box_candidates(box1=(targets[:, 1:5].T * s), box2=(new.T), area_thr=(0.01 if use_segments else 0.1))
        targets = targets[i]
        targets[:, 1:5] = new[i]
    return (img, targets)

def box_candidates(box1, box2, wh_thr=2, ar_thr=20, area_thr=0.1, eps=1e-16):
    w1, h1 = box1[2] - box1[0], box1[3] - box1[1]
    w2, h2 = box2[2] - box2[0], box2[3] - box2[1]
    ar = np.maximum(w2 / (h2 + eps), h2 / (w2 + eps))
    return (w2 > wh_thr) & (h2 > wh_thr) & (w2 * h2 / (w1 * h1 + eps) > area_thr) & (ar < ar_thr)

def cutout(image, labels):
    h, w = image.shape[:2]

    def bbox_ioa(box1, box2):
        box2 = box2.transpose()
        b1_x1, b1_y1, b1_x2, b1_y2 = (
         box1[0], box1[1], box1[2], box1[3])
        b2_x1, b2_y1, b2_x2, b2_y2 = (box2[0], box2[1], box2[2], box2[3])
        inter_area = (np.minimum(b1_x2, b2_x2) - np.maximum(b1_x1, b2_x1)).clip(0) * (np.minimum(b1_y2, b2_y2) - np.maximum(b1_y1, b2_y1)).clip(0)
        box2_area = (b2_x2 - b2_x1) * (b2_y2 - b2_y1) + 1e-16
        return inter_area / box2_area

    scales = [
     0.5] * 1 + [0.25] * 2 + [0.125] * 4 + [0.0625] * 8 + [0.03125] * 16
    for s in scales:
        mask_h = random.randint(1, int(h * s))
        mask_w = random.randint(1, int(w * s))
        xmin = max(0, random.randint(0, w) - mask_w // 2)
        ymin = max(0, random.randint(0, h) - mask_h // 2)
        xmax = min(w, xmin + mask_w)
        ymax = min(h, ymin + mask_h)
        image[ymin:ymax, xmin:xmax] = [random.randint(64, 191) for _ in range(3)]
        if len(labels) and s > 0.03:
            box = np.array([xmin, ymin, xmax, ymax], dtype=(np.float32))
            ioa = bbox_ioa(box, labels[:, 1:5])
            labels = labels[(ioa < 0.6)]

    return labels

def create_folder(path='./new'):
    if os.path.exists(path):
        shutil.rmtree(path)
    os.makedirs(path)

def flatten_recursive(path='../coco128'):
    new_path = Path(path + '_flat')
    create_folder(new_path)
    for file in tqdm(glob.glob((str(Path(path)) + '/**/*.*'), recursive=True)):
        shutil.copyfile(file, new_path / Path(file).name)

def extract_boxes(path='../coco128/'):
    path = Path(path)
    shutil.rmtree(path / 'classifier') if (path / 'classifier').is_dir() else None
    files = list(path.rglob('*.*'))
    n = len(files)
    for im_file in tqdm(files, total=n):
        if im_file.suffix[1:] in img_formats:
            im = cv2.imread(str(im_file))[..., ::-1]
            h, w = im.shape[:2]
            lb_file = Path(img2label_paths([str(im_file)])[0])
            if Path(lb_file).exists():
                with open(lb_file, 'r') as (f):
                    lb = np.array([x.split() for x in f.read().strip().splitlines()], dtype=(np.float32))
                for j, x in enumerate(lb):
                    c = int(x[0])
                    f = path / 'classifier' / (f"{c}") / f"{path.stem}_{im_file.stem}_{j}.jpg"
                    if not f.parent.is_dir():
                        f.parent.mkdir(parents=True)
                    b = x[1:] * [w, h, w, h]
                    b[2:] = b[2:] * 1.2 + 3
                    b = xywh2xyxy(b.reshape(-1, 4)).ravel().astype(np.int)
                    b[[0, 2]] = np.clip(b[[0, 2]], 0, w)
                    b[[1, 3]] = np.clip(b[[1, 3]], 0, h)
                    assert cv2.imwrite(str(f), im[b[1]:b[3], b[0]:b[2]]), f"box failure in {f}"

def autosplit(path='../coco128', weights=(0.9, 0.1, 0.0), annotated_only=False):
    """ Autosplit a dataset into train/val/test splits and save path/autosplit_*.txt files
    Usage: from utils.datasets import *; autosplit('../coco128')
    Arguments
        path:           Path to images directory
        weights:        Train, val, test weights (list)
        annotated_only: Only use images with an annotated txt file
    """
    path = Path(path)
    files = sum([list(path.rglob(f"*.{img_ext}")) for img_ext in img_formats], [])
    n = len(files)
    indices = random.choices([0, 1, 2], weights=weights, k=n)
    txt = [
     'autosplit_train.txt', 'autosplit_val.txt', 'autosplit_test.txt']
    [(path / x).unlink() for x in txt if (path / x).exists()]
    print(f"Autosplitting images from {path}" + ', using *.txt labeled images only' * annotated_only)
    for i, img in tqdm((zip(indices, files)), total=n):
        if not annotated_only or Path(img2label_paths([str(img)])[0]).exists():
            with open(path / txt[i], 'a') as (f):
                f.write(str(img) + '\n')


# -------------------------------------------------------------------------------------------------------------
## Import Statements
# -------------------------------------------------------------------------------------------------------------
from __future__ import print_function

import json
import os
import re
import sys

GGD_INFO = "share/ggd_info"
METADATA = "channeldata.json"

# -------------------------------------------------------------------------------------------------------------
## Argument Parser
# -------------------------------------------------------------------------------------------------------------
def add_list_installed_packages(p):

    import argparse

    c = p.add_parser(
        "list",
        help="List the ggd data package(s) that are currently installed in a specific conda environment",
        description="Get a list of ggd data packages installed in the current or specified conda prefix/environment.",
    )
    c.add_argument(
        "-p",
        "--pattern",
        help="(Optional) pattern to match the name of the ggd data package.",
    )
    c.add_argument(
        "--prefix",
        default=None,
        help="(Optional) The name or the full directory path to a conda environment where a ggd recipe is stored. (Only needed if listing data files not in the current environment)",
    )
    c.add_argument("--reset", action="store_true", help=argparse.SUPPRESS)
    c.set_defaults(func=list_installed_packages)

# -------------------------------------------------------------------------------------------------------------
## Functions/Methods
# -------------------------------------------------------------------------------------------------------------

def load_json(jfile):
    """Method to load a json file into a dictionary

    load_json
    =========
    Method to load a json file

    Parameters:
    ---------
    1) jfile: (str) The path to the json file

    Returns:
    1) (dict) A dictionary of a json object
    """

    with open(jfile) as jsonFile:
        return json.load(jsonFile)

def get_environment_variables(prefix):
    """Method to get ggd data package environment variables in a user specified conda environment/prefix

    get_environment_variables
    =========================
    Method to get the environment variables for each installed data package in a specific conda environment

    Parameters:
    -----------
    1) prefix: (str) The conda environment/prefix to get environment variables for

    Returns:
    ++++++++
    1) (dict) A dictionary with each key == env_var, and values == the path the environment variable is for
    """

    env_var_path = os.path.join(prefix, "etc", "conda", "activate.d", "env_vars.sh")
    env_vars = {}
    try:
        with open(env_var_path, "r") as env_file:
            for var in env_file:
                var_array = var.strip().split()
                if len(var_array) >= 2:
                    var_item_array = var_array[1].split("=")
                if len(var_item_array) >= 1:
                    env_vars[var_item_array[0]] = var_item_array[1]
    except (IOError, ValueError):
        return None

    ## Key = env_var, value = path
    return env_vars

def list_pkg_info(pkg_names, pkgs_dict, env_vars, conda_list, prefix, prefix_set=False):
    """Method to identify and display available data packages in a specific conda environment

    list_pkg_info
    =============
    Method to display the ggd data packages installed in a specific conda environment. If the
     prefix is not set, the packages in the current environment will be displayed. If the --pattern
     flag is set, the package names will be filtered prior to this method.

    Parameters:
    -----------
    1) pkg_names:  (list) A list of package names to show. (List comes from ggd_info metadata file)
    2) pkgs_dict:  (dict) The ggd_info metadata file as a dictionary (To get version and channel info)
    3) env_vars:   (dict) A dictionary of environment variables. (Key = env_var name, value = path to file/dir)
    4) conda_list: (dict) A dictionary representing conda list output (from utils.get_conda_package_list())
    5) prefix:     (str)  The prefix/conda environment to display information for.
    6) prefix_set: (bool) True or False, whether the user set a prefix or not.
    """

    ## Create a 2d list for string formatting
    formatted_list = [
        ["    Name", "Pkg-Version", "Pkg-Build", "Channel", "Environment-Variables"]
    ]

    missing_in_conda = False
    missing_message = " [WARNING: Present in GGD but missing from Conda]"
    ## Iterate over each package in pkg_names
    for pkg in pkg_names:

        version = pkgs_dict[pkg]["version"]

        ## If package is present in both ggd metadata and conda metadata
        if pkg in conda_list:
            assert version == conda_list[pkg]["version"]
            build = conda_list[pkg]["build"]
            channel = "ggd-" + pkgs_dict[pkg]["tags"]["ggd-channel"]
            assert channel == conda_list[pkg]["channel"]

        ## If package is missing from conda metadata
        else:
            missing_in_conda = True
            build = missing_message
            channel = ""

        ## Get env_vars
        env_variables = []
        if (
            "ggd_" + pkg.replace("-", "_").replace(".", "_") + "_dir"
        ) in env_vars.keys():
            env_variables.append(
                " $ggd_" + pkg.replace("-", "_").replace(".", "_") + "_dir"
            )
        if (
            "ggd_" + pkg.replace("-", "_").replace(".", "_") + "_file"
        ) in env_vars.keys():
            env_variables.append(
                " $ggd_" + pkg.replace("-", "_").replace(".", "_") + "_file"
            )

        formatted_list.append([pkg, version, build, channel, ",".join(env_variables)])

    ## Print data pkg list
    print("\n\n# Packages in environment: {p}\n#".format(p=prefix))

    dash = "-" * 120
    for i in range(len(formatted_list)):
        if i == 0:
            print(dash)
            print(
                "{:<40s}{:>5s}{:>10s}{:>10s}{:>30s}".format(
                    formatted_list[i][0],
                    formatted_list[i][1],
                    formatted_list[i][2],
                    formatted_list[i][3],
                    formatted_list[i][4],
                )
            )
            print(dash)
        else:
            print(
                "-> {:<40s}{:>5s}{:>10s}{:>15s}{:^60s}\n".format(
                    formatted_list[i][0],
                    formatted_list[i][1],
                    formatted_list[i][2],
                    formatted_list[i][3],
                    formatted_list[i][4],
                )
            )

    ## Print environment variables info
    if prefix_set:
        print(
            "# The environment variables are only available when you are using the '{p}' conda environment.".format(
                p=prefix
            )
        )
    else:
        print("# To use the environment variables run `source activate base`")
        print(
            "# You can see the available ggd data package environment variables by running `ggd show-env`\n"
        )

    ## Print message if a package is missing from conda metadata
    if missing_in_conda:
        print(
            (
                "#\n# NOTE: Packages with the '{}' messages represent packages where the ggd"
                " package(s) are installed, but the package metadata has been removed from conda storage. This"
                " happens when one of the following happen: \n 1) The package represents an ID specific meta-"
                "recipe installed by GGD. \n 2) When the recipe is built locally using 'ggd check-recipe' and"
                " has not been uninstalled. (Commonly for private data packages).\n  Or \n 3) The package is"
                " uninstalled using conda rather then ggd. The package is still available for use and is in"
                " the same state as before the 'conda uninstall'. To fix the problem on conda's side, uninstall"
                " the package with 'ggd uninstall' and re-install with 'ggd install'.\n"
            ).format(missing_message.strip())
        )

def get_metadata(C_ROOT, GGD_INFO_DIR, METADATA_FILE):
    """
    get_metadata
    =============
    Method to load local ggd specific metadata from json into dict

    Parameters:
    -----------
    1) C_ROOT:        (str) The conda prefix/root
    2) GGD_INFO_DIR:  (str) The directory path where ggd metadata info is stored
    3) METADATA_FILE: (str) The file name of the metadata

    Returns:
    ++++++++
    1) (dict) Metadata json file loaded as a dictionary
    """

    try:
        metadata_dict = load_json(os.path.join(C_ROOT, GGD_INFO_DIR, METADATA_FILE))
    except IOError as e:
        print(str(e))
        sys.exit("\n:ggd:list: !!ERROR!! Unable to load the local metadata")

    return metadata_dict

def list_installed_packages(parser, args):
    """Main method of `ggd list` used to list installed ggd data package in user specified conda environment/prefix

    list_installed_packages
    =======================
    Main method of ggd list. This method will check and set the conda environment/prefix, check the ggd info metdata file
     get environment variables for ggd data packages in the user specified conda prefix, get the installed data packages
     from conda info, filter results based on user specified pattern, and provide the information to the display function.
    """

    from .utils import (
        conda_root,
        get_conda_package_list,
        get_conda_prefix_path,
        prefix_in_conda,
        update_installed_pkg_metadata,
    )

    ## Check prefix
    CONDA_ROOT = (
        get_conda_prefix_path(args.prefix)
        if args.prefix != None and prefix_in_conda(args.prefix)
        else conda_root()
    )

    ## If reset list
    if args.reset:
        print(
            "\n:ggd:list: The --reset flag was set. RESETTING ggd installed list metadata."
        )
        update_installed_pkg_metadata(args.prefix)
        print(
            "\n:ggd:list: Run 'ggd list' without --reset to see a list of installed ggd data packages"
        )
        print("\nDONE\n")
        sys.exit(0)

    ggd_info_path = os.path.join(CONDA_ROOT, GGD_INFO)

    ## Check that the ggd info dir exists. If not, create it
    if not os.path.isdir(ggd_info_path):
        update_installed_pkg_metadata(prefix=CONDA_ROOT)

    ## Load json metadata data as dictionary
    # metadata = load_json(os.path.join(CONDA_ROOT, GGD_INFO, METADATA))
    metadata = get_metadata(CONDA_ROOT, GGD_INFO, METADATA)

    ## Get the environment variables
    env_vars = get_environment_variables(CONDA_ROOT)

    ## Get conda package list
    ggd_packages = get_conda_package_list(CONDA_ROOT)

    ## Get final package list
    final_package_list = metadata["packages"].keys()

    ## Check if there is a user defined pattern
    pat = args.pattern if args.pattern != None else None
    if pat != None:
        matches = list(
            map(
                str,
                [
                    re.search(".*" + pat.lower() + ".*", x).group()
                    for x in metadata["packages"].keys()
                    if re.search(pat.lower(), x) != None
                ],
            )
        )
        if len(matches) < 1:
            # print("\n-> '{p}' did not match any installed data packages".format(p=args.pattern))
            sys.exit(
                "\n:ggd:list: '{p}' did not match any installed data packages".format(
                    p=args.pattern
                )
            )
            # sys.exit(0)
        else:
            final_package_list = matches

    ## Provide the results to stdout
    list_pkg_info(
        final_package_list,
        metadata["packages"],
        env_vars,
        ggd_packages,
        CONDA_ROOT,
        prefix_set=False if args.prefix == None else True,
    )


# By submitting this assignment, I agree to the following:
# “Aggies do not lie, cheat, or steal, or tolerate those who do”
# “I have not given or received any unauthorized aid on this assignment”
#
# Name: Katherine Stevens
# Section: 462
# Assignment: Lab9b_Act3.py
# Date: 27 October 2020
from math import *
# open the csv file for reading
file = open("WeatherData.csv", "r")

list2 = []
# read the csv file and compute
mylist = file.readlines()
for i in range(len(mylist)):
    mylist[i] = mylist[i].strip()
    l = mylist[i].split(",")
    list2.append(l)
#print(mylist)
#print(list2)
#convert to int and float
for i in range(1,len(list2)):
    for j in range(1,14):
        list2[i][j] = float(list2[i][j])
#print(list2)

#loop for max
#   a. maximum temp seen over the 3 yr period

max = list2[1][1]
for i in range(1,len(list2)):
    if list2[i][1] > max:
        max = list2[i][1]
#print(max)

#   b. minimum temp seen over the 3 yr period

min = list2[1][3]
for i in range(1,len(list2)):
    if list2[i][3] < min:
        min = list2[i][3]
#print(min)

#   c. avg daily precipitation over the 3 yr period (2 dec places)
sum = 0
for i in range(1,len(list2)):
    sum += list2[i][13]
avg_prec = sum / (len(list2)-1)
#print(avg_prec)
#output results in console

print("3-year maximum temperature:", int(max), "F")
print("3-year minimum temperature:", int(min), "F")
print("3-year average precipitation: %.2f" %avg_prec, "inches\n")

#   take input month and year
month = input("Enter a month: ")
year = input("Enter a year: \n")
print("For ", month," ", year, ":", sep="")
dict = {'January': '1', 'February': '2', 'March': '3', 'April': '4', 'May': '5', 'June': '6', 'July': '7', 'August': '8', 'September': '9', 'October': '10', 'November': '11', 'December': '12'}
if month in dict:
    month_number = dict[month]

# for that month
#       a. calc avg of low temps  (1 dec)
total = 0
low = 0
for i in range(1, len(list2)):
    date = list2[i][0].split("/")
    #print(date)
    if date[2] == year and date[0] == month_number:
        low += list2[i][3]
        total += 1
avg_low = low / total
print("Average low temperature: %.1f" %avg_low, "F")

#       b. calc % of days when avg humidity below 75% (1 dec)
humidity_number = 0
total_humidity = 0
for i in range(1, len(list2)):
    date = list2[i][0].split("/")
    if date[2] == year and date[0] == month_number:
        total_humidity += 1
        if list2[i][8] < 75:
            humidity_number += 1
humidity_percent = (humidity_number / total_humidity) * 100

per_string = "%.1f" % humidity_percent + "%"
print("Percentage of days with average humidity below 75%:", per_string)

precipitation_count = 0
num_days = 0
var = 0
#       c. calc mean and standard dev of daily precipitation levels (4 dec)
for i in range(1, len(list2)):
    date = list2[i][0].split("/")
    if date[2] == year and date[0] == month_number:
        precipitation_count += list2[i][13]
        num_days += 1
mean = precipitation_count / num_days

for i in range(1, len(list2)):
    date = list2[i][0].split("/")
    if date[2] == year and date[0] == month_number:
        var += ((list2[i][13] - mean) ** 2)

stan_dev = sqrt(var / (num_days))

print("Mean daily precipitation: %.4f" %mean, "inches")
print("Standard deviation of daily precipitation: %.4f" %stan_dev, "inches")

file.close()


import streamlit as st
import pandas as pd
import numpy as np
import time

@st.cache
def dataframe(rows):
    df = pd.DataFrame(
        np.random.randn(rows, 5), columns=("col %d" % i for i in range(5))
    )

runtime = pd.DataFrame(
    data={
        "Number of rows": [10, 100, 1000, 10000, 100000, 1000000, 10000000],
        "First runtime (s)": None,
        "Second runtime (s)": None,
        "Runtime saved (%)": None,
    }
)

st.write(runtime)
st.write(len(runtime))

for i in range(0, len(runtime)):
    start = time.time()
    dataframe(runtime.loc[i]["Number of rows"])
    stop = time.time()
    runtime.loc[i, "First runtime (s)"] = stop - start

    start = time.time()
    dataframe(runtime.loc[i]["Number of rows"])
    stop = time.time()
    runtime.loc[i, "Second runtime (s)"] = stop - start

    runtime.loc[i, "Runtime saved (%)"] = 100 - int(
        100
        * (runtime.loc[i, "Second runtime (s)"] / runtime.loc[i, "First runtime (s)"])
    )

st.write(runtime)


# pylint: disable=missing-function-docstring,invalid-name
# pylint: disable=missing-class-docstring,missing-module-docstring
import os
import sys
import random
import uuid
import yaml
from prompt_toolkit import prompt
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.shortcuts import radiolist_dialog

class GameDB(dict):
    def __init__(self):
        dict.__init__(self)
        self.load()

    @staticmethod
    def data_filepath(filename):
        return os.path.join(os.path.dirname(__file__), filename)

    def load(self):
        with open(self.data_filepath('gamedata.yaml'), 'r') as fin:
            self.update(yaml.load(fin, Loader=yaml.SafeLoader))

    def save(self):
        with open(self.data_filepath('gamedata.yaml'), 'w') as fout:
            yaml.dump(dict(self), fout)

def get_free_family_name(db):
    family_names = db['family-names']
    random.shuffle(family_names)
    for name in family_names:
        match = False
        for player in db.get('players', []):
            if name == player['name']:
                match = True
                break
        if match:
            continue
        return name
    # return last-match (it is a duplicate)
    return family_names[-1]

def show_welcome(name, is_new):
    back = ''
    if not is_new:
        back = ' back'

    print(f"Welcome{back}, {name}!")

def select_advantage(db):
    attributes = db['attributes']
    advantage = radiolist_dialog(
        title=f'Family advantage',
        text='Select a family advantage',
        values=list(zip(attributes, attributes))
    ).run()
    if advantage is None:
        sys.exit(1)  # cancel
    return advantage

def select_province(db, player):
    all_provinces = db['provinces']
    province_name = radiolist_dialog(
        title=f"{player['name']} decides his fate",
        text='Select a province',
        values=list(zip(all_provinces.keys(), all_provinces.keys()))
    ).run()
    if province_name is None:
        sys.exit(1)  # cancel
    province = all_provinces[province_name]
    province['name'] = province_name
    return province

def create_player(db, name):
    player = {
        'name': name,
        'id': str(uuid.uuid4()),
        'ai': False,
        'age': random.randrange(18, 34),
        'level': 1,
        'location': 'home',
    }
    province = select_province(db, player)
    player['province'] = province['name']
    player = set_new_player_attributes(db, player, province)
    advantage = select_advantage(db)
    player[advantage] += 1
    return player

def set_new_player_attributes(db, player, province):
    # set province attribute values to player by random order
    some_attributes = db['attributes']
    random.shuffle(some_attributes)
    for idx, attr in enumerate(some_attributes):
        player[attr] = max(0.0, province.get(attr, 0.0) - idx)
    return player

def create_hatamoto(db, province):
    hatamoto = {
        'name': get_free_family_name(db),
        'id': str(uuid.uuid4()),
        'ai': True,
        'age': random.randrange(34, 68),
        'level': 2,
        'location': 'home',
    }
    hatamoto['province'] = province['name']
    hatamoto = set_new_player_attributes(db, hatamoto, province)
    hatamoto[random.choice(db['attributes'])] += 1
    return hatamoto

def create_ai_player(db, province):
    ai_player = {
        'name': get_free_family_name(db),
        'id': str(uuid.uuid4()),
        'ai': True,
        'age': random.randrange(18, 34),
        'level': 1,
        'location': 'home',
    }
    ai_player['province'] = province['name']
    ai_player = set_new_player_attributes(db, ai_player, province)
    ai_player[random.choice(db['attributes'])] += 1
    return ai_player

def join_province(db, player):
    # conditionally add player to province
    province = db['provinces'][player['province']]
    if player['id'] not in province.get('members', []):
        province['members'] = province.get('members', []) + [player['id']]
    return province

def ready_province(db, province):
    # Generate new Hatamoto
    if 'hatamoto' not in province:
        hatamoto = create_hatamoto(db, province)
        db['provinces'][province['name']]['hatamoto'] = hatamoto['id']

    # Create AI opponents
    while len(db['provinces'][province['name']]['members']) < 4:
        ai_player = create_ai_player(db, province)
        db['provinces'][province['name']]['members'].append(ai_player['id'])
        db['players'].append(ai_player)

def select_player(db):
    existing_players = db.get('players', [])
    all_names = [player['name'] for player in existing_players]
    name = ''
    while not name:
        name = prompt(
            "Your name?  ",
            completer=WordCompleter(all_names)
        ).strip()

    player = None
    for tgt_player in existing_players:
        if tgt_player['name'].lower() == name.lower():
            player = tgt_player
            name = player['name']

    show_welcome(name, is_new=player is None)

    if player is None:
        player = create_player(db, name)
        db['players'].append(player)

    return player

def main():
    db = GameDB()
    player = select_player(db)
    province = join_province(db, player)
    ready_province(db, province)
    db.save()

if __name__ == '__main__':
    main()


from turtle import *
from math import sin, pi

shape('turtle')
speed(100)
for i in range(3,13):
    left(90+180/i)
    forward(2*(20*(i-2))*sin(pi/i))
    for j in range(i-1):
        left(360/i)
        forward(2*(20*(i-2))*sin(pi/i))
    penup()
    goto(20*(i-2),0)
    pendown()
    right(90-180/i)
mainloop()


from PPlay.window import *
from PPlay.gameimage import *
from PPlay.sprite import *
from PPlay.keyboard import *
from PPlay.animation import *
from pygame import mixer
import menu
import funcoes

def jogo():
    janela_altura = 1080
    janela_largura = 1920
    lista_tiro = []
    delay = 0
    v = []
    crash = False
    contamove = 0
    janela_j = Window(1920,1080)
    conta2 = 0
    mixer.init()
    linha = 4
    coluna = 10

    #sprites
    nave = Sprite("assets/xwing.png")
    background = Sprite("assets/walljogo.png")
    nave.set_position(janela_j.width/2 - nave.width/2 ,950)

    #Usuario
    teclado = Window.get_keyboard()
    click = Window.get_mouse()
    listatiro = []
    #variaveis
    total = linha * coluna
    totalpontos = linha * coluna
    velmonstro = 0.5
    velx = 300
    vely = 300
    veli = 0.5
    pontos = 0
    mixer.music.load('assets/game.mp3')
    mixer.music.set_volume(0.2)
    mixer.music.play()
    cooldown2 = 0
    cooldown = 0
    lifes = 1
    invincible = False
    countinvincible = 120
    while True:
        background.draw()
        nave.draw()

        #Mover nave
        if teclado.key_pressed("LEFT") and nave.x >= 0:
            nave.x -= velx * janela_j.delta_time()
        elif teclado.key_pressed("RIGHT") and nave.x <= janela_j.width - nave.width:
            nave.x += velx * janela_j.delta_time()
        # Atirar
        delay = funcoes.piupiu(nave, background, janela_j, teclado, velx , vely, lista_tiro, delay)

        # Criar matriz
        if conta2 == 0:
            funcoes.criaMatriz(coluna, linha, v)
            conta2 += 1

        # Mover matriz
        if contamove >= 3 :
            velmonstro = funcoes.movematriz(coluna, linha, v, janela_j, velmonstro, nave)
            contamove = 0
        contamove += 1

        # Printar matriz e checar derrota
        crash, pontos  = funcoes.printaMatriz(coluna, linha, v, nave, crash, lista_tiro, pontos)
        if pontos >= totalpontos:
            conta2 = 0
            v = []
            totalpontos += total

        # Finalizar jogo, se derrotado
        if crash or (lifes == 0):
                background = Sprite("assets/fail.png")
                mixer.music.load('assets/loss.mp3')
                mixer.music.set_volume(0.2)
                mixer.music.play()
                funcoes.colocar_ranking(pontos)
                listapontos = funcoes.translate("ranking.txt")
                while True:

                    background.draw()
                    funcoes.printaranking(listapontos,janela_altura, janela_largura, janela_j)
                    janela_j.update()

                    if teclado.key_pressed("ESC"):
                        janela_j.close()

        cooldown, lifes,invincible, countinvincible = funcoes.monstroatira(v, nave, vely, janela_j, cooldown, listatiro, lifes, invincible, countinvincible)
        if teclado.key_pressed("ESC"):
            janela_j.close()
        janela_j.update()


# -*- coding: utf-8 -*-
"""
Created on Sat Oct 29 08:32:13 2016

@author: dell
"""

trans = {'0':'ling', '1':'yi', '2':'er', '3':'san', '4': 'si',
          '5':'wu', '6':'liu', '7':'qi', '8':'ba', '9':'jiu', '10': 'shi'}

def convert_to_mandarin(us_num):
    '''
    us_num, a string representing a US number 0 to 99
    returns the string mandarin representation of us_num
    '''
    answer = ""
    if int(us_num) <= 10:
        return trans[us_num]
    elif int(us_num) > 10 and int(us_num) < 20:
        tens = (int(us_num)// 10) * 10
        digits = int(us_num) % 10
        answer += trans[str(tens)]
        answer += " "
        answer += trans[str(digits)]
        return answer
    elif int(us_num) >= 20 and int(us_num) < 100:
        tens = (int(us_num)// 10)
        digits = int(us_num) % 10
        if int(us_num) % 10 == 0:
            answer += trans[str(tens)]
            answer += " "
            answer += trans["10"]
        else:
            answer += trans[str(tens)]
            answer += " "
            answer += trans['10']
            answer += " "
            answer += trans[str(digits)]
        return answer

print(convert_to_mandarin("30"))


# 백준 2667 단지번호붙이기

import sys
sys.stdin = open('input.txt', 'r')

N = int(input())
danji = [list(input()) for _ in range(N)]
visited = [[0]*N for _ in range(N)]
Q = []
result = []
for i in range(N):
    for j in range(N):
        if visited[i][j] == '1':
            continue
        if danji[i][j] == '1':
            cnt = 0
            Q.append((i, j))
            while Q:
                r, c = Q.pop(0)
                if visited[r][c] == 1:
                    continue
                cnt += 1
                visited[r][c] = 1
                dr = [-1, 1, 0, 0]
                dc = [0, 0, -1, 1]
                for k in range(4):
                    nr = r + dr[k]
                    nc = c + dc[k]
                    if 0 <= nr < N and 0 <= nc < N:
                        if danji[nr][nc] == '1':
                            Q.append((nr, nc))
            if cnt != 0:
                result.append(cnt)
result.sort()
print(len(result))
for i in result:
    print(i)

백준_단지번호붙이기.py


surface = None
rect = None

import pygame
pygame.init()
pygame.display.set_caption('Rect Draw Application')
surface = pygame.display.set_mode ((400,200), (pygame.RESIZABLE))
rect = pygame.Rect(((10,10)),(((100,100))[0]-((10,10))[0],((100,100))[1]-((10,10))[1]))
pygame.draw.rect(surface,0Xcc0000,rect)
pygame.display.update()
_quitEvent = False
while not _quitEvent:
   for event in (pygame.event.get()):
      if (event.type) == (pygame.KEYDOWN):
         _quitEvent = True
         break


import os
from PIL import Image

input_folder = '../Data/images/cropped'

desired_width = 50  # Adjust to your preferred width
desired_height = 50  # Adjust to your preferred height

output_folder = '../Data/images/cropped_' + desired_width

# Create the output folder if it doesn't exist
if not os.path.exists(output_folder):
    os.makedirs(output_folder)

# Loop through all files in the input folder
for filename in os.listdir(input_folder):
    if filename.endswith(('.jpg', '.jpeg', '.png', '.gif', '.bmp')):  # Adjust file extensions as needed
        input_image_path = os.path.join(input_folder, filename)
        output_image_path = os.path.join(output_folder, filename)
        try:
            with Image.open(input_image_path) as img:
                # # Calculate new dimensions while maintaining the aspect ratio
                # img.thumbnail((desired_width, desired_height))
                # # Create a blank background image with the desired dimensions and black color
                # new_img = Image.new("RGB", (desired_width, desired_height), (0, 0, 0))
                # # Calculate the position to paste the resized image in the center
                # position = ((desired_width - img.width) // 2, (desired_height - img.height) // 2)
                # # Paste the resized image onto the center of the blank background
                # new_img.paste(img, position)
                # # Save the modified image to the output folder
                new_img = img.resize((desired_width, desired_height))
                new_img.save(output_image_path)
        except Exception as e:
            print(f"Error processing {filename}: {str(e)}")


# -*- coding: utf-8 -*-
"""
Created on Tue Jul 12 12:29:25 2022

This file uses a file path to lists of drug names to search for, to pull
medication features from MIMIC-III. It examines the first 24 hours of data.

Runtime: ~30 min.

@author: Kirby
"""

import pandas as pd
import ValidationTwoTwentyFourHrDrugFunction as df
import os.path
import glob
from time import time
from pathlib import Path

start = time()
file_path = Path(__file__)
dataset_path = file_path.parent.parent.parent.joinpath('Dataset')

comp = pd.read_csv(dataset_path.joinpath('MIMICIV_complete_dataset.csv'))

#define all the paths.
drugPathList = glob.glob('DrugNameLists\*')

#error checking

for path in drugPathList:
    if os.path.isfile(path) == False:
        raise NameError(path+" is not a valid file path")

#Loop through each medication class, attach results into one dataframe.
for i in range(1,len(drugPathList)):
    print(drugPathList[i])
    comp = pd.concat(objs=[comp,df.TwentyFourHourDrugFeature(drugPathList[i])],axis = 1)

#Save off results.
comp.drop(columns = ['hadm_id', 'subject_id', 'intime', 'outtime', 'del_onset',
                     'del_onset_time', 'delirium_pos'], inplace = True)
comp.to_csv('MIMICIV_24hrs_all_drug_features.csv',index=False)

calc = time() - start

First 24 Hour/Ext Validation 2/Medications/ValidationTwo24hrAllDrugFeatures.py


from fastapi import FastAPI
from . import(config,db,models,schema,crud)
from cassandra.cqlengine.management import sync_table

settings = config.get_settings()
product = models.Products
unique_product = models.UniqueProduct
session = None

app = FastAPI()

@app.on_event("startup")
def on_startup():
    global session
    session = db.get_session()
    sync_table(product)
    sync_table(unique_product)

@app.get('/')
def read_index():
    return "Hello Fast Api"

@app.get('/products')
def get_all_product():
    return list(product.objects().all())

@app.get('/unique_product')
def get_all_unique_product():
    # data = dict(unique_product.objects().first())
    allunique = list(unique_product.objects().all())
    filteredData = [schema.UniqueProductschema(**x)for x in allunique]
    # data['events'] = filteredData
    return filteredData

@app.get('/unique_product/{name}')
def get_all_unique_product(name:str):
    # data = dict(unique_product.objects().first())
    allunique = list(unique_product.objects().filter(name=name))
    # filteredData = [schema.UniqueProductschema(**x)for x in allunique]
    # # data['events'] = filteredData
    return allunique

@app.post('/insert_unique_product')
def add_unique_product(data: schema.UniqueProductschemaList):
    uproduct = crud.create_unique_entry(data.dict())
    return uproduct


class EarlyStopping:
    """
    Early Stopping for Overfit :)
    """

    def __init__(self, tolerance: int = 5, min_delta: float = 0.5) -> None:
        """
        :param tolerance: number of epochs for wait :)
        :param min_delta: allowed difference between train loss & valid loss
        """
        self.tolerance = tolerance
        self.min_delta = min_delta
        self.counter = 0
        self.early_stop = False

    def __call__(self, train_loss, validation_loss):
        """
        check overfit :)
        :param train_loss: training loss
        :param validation_loss: validation loss
        :return:
        """
        if (validation_loss - train_loss) > self.min_delta:
            self.counter += 1
            if self.counter >= self.tolerance:
                self.early_stop = True


"""
Dado el sueldo actual de un empleado
si este es menor a $8000.00 se incrementa un 12%
en caso contratio es el 8%. Al final mostrar el aumento y su nuevo sueldo

"""

# 1 entrada de datos
#sueldo = float(input("Ingrese el sueldo del trabajador: $"))

# 2 evaluar
# if sueldo < 8000:
#     aumento = sueldo*0.12
# else:
#     aumento = sueldo*0.08
# nuevo_sueldo = sueldo + aumento
# print(f'El Aumento es ${aumento:.2f}, el nuevo sueldo es: ${nuevo_sueldo:.2f}')

"""
*CATEGORIAS
RECURSOS HUMANOS = 3
CONTABILIDAD = 5

"""
codigo_empleado = input("Ingrese el codigo del empleado: ")
categoria = int(input("Ingrese la categoria: "))
antiguedad = int(input("Ingrese los años de antiguedad: "))
#flag= bandera
respuesta = False
if categoria == 3 or categoria == 5:
    if antiguedad >= 5:
        respuesta = True
elif categoria == 2 and antiguedad >= 10:
    respuesta = True
if respuesta:
    resultado = "Reune las caracteristicas para el puesto"
else:
    resultado = " No reunes las caracteristicas para el puesto"
    print(f'El Empleado con código {codigo_empleado}' + resultado)