#!/usr/bin/env python3

import time
import json
import re
from tqdm import tqdm
import sys
import os
import shutil
import atexit
from distutils.spawn import find_executable
from ast import literal_eval
from psutil import virtual_memory
import argparse
import subprocess
from subprocess import PIPE, STDOUT
from pathlib import Path
import cv2
import numpy as np
import statistics
from scipy import interpolate
from math import isnan
import matplotlib.pyplot as plt
from scenedetect.video_manager import VideoManager
from scenedetect.scene_manager import SceneManager
from scenedetect.detectors import ContentDetector
from multiprocessing.managers import BaseManager
import concurrent
import concurrent.futures

# Todo: Separation, Clip encoder objects, Threading instead of multiprocessing.

if sys.version_info < (3, 6):
    print('Python 3.6+ required')
    sys.exit()

if sys.platform == 'linux':
    def restore_term():
        os.system("stty sane")
    atexit.register(restore_term)

# Stuff for updating encoded progress in real-time
class MyManager(BaseManager):
    pass

def Manager():
    m = MyManager()
    m.start()
    return m

class Counter():
    def __init__(self, total, initial):
        self.tqdm_bar = tqdm(total=total, initial=initial, dynamic_ncols=True, unit="fr", leave=True, smoothing=0.01)

    def update(self, value):
        self.tqdm_bar.update(value)

MyManager.register('Counter', Counter)

class Av1an:

    def __init__(self):
        """Av1an - Python all-in-one toolkit for AV1, VP9, VP8 encodes."""
        self.FFMPEG = 'ffmpeg -y -hide_banner -loglevel error '
        self.d = dict()
        self.encoders = {'svt_av1': 'SvtAv1EncApp', 'rav1e': 'rav1e', 'aom': 'aomenc', 'vpx': 'vpxenc'}

    def terminate(self):
        os.kill(os.getpid(), 9)

    @staticmethod
    def read_vmaf_xml(file):
        with open(file, 'r') as f:
            file = f.readlines()
            file = [x.strip() for x in file if 'vmaf="' in x]
            vmafs = []
            for i in file:
                vmf = i[i.rfind('="') + 2: i.rfind('"')]
                vmafs.append(float(vmf))

        vmafs = [round(float(x), 5) for x in vmafs if isinstance(x, float)]
        calc = [x for x in vmafs if isinstance(x, float) and not isnan(x)]
        mean = round(sum(calc) / len(calc), 2)
        perc_1 = round(np.percentile(calc, 1), 2)
        perc_25 = round(np.percentile(calc, 25), 2)
        perc_75 = round(np.percentile(calc, 75), 2)

        return vmafs, mean, perc_1, perc_25, perc_75

    @staticmethod
    def get_keyframes(file):
        """ Read file info and return list of all keyframes """
        cmd = ["ffmpeg", "-hide_banner", "-i", file.absolute(), "-vf", "showinfo", "-f", "null", "-"]
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
        keyframes = []
        while True:
            line = pipe.stdout.readline().strip()
            if len(line) == 0 and pipe.poll() is not None:
                break
            if "iskey:1" in line:
                r = re.findall(r"n: *([^ ]+?) ", line)
                keyframes.append(int(r[0]))
        return keyframes

    @staticmethod
    def get_cq(command):
        """Return cq values from command"""
        matches = re.findall(r"--cq-level= *([^ ]+?) ", command)
        return int(matches[-1])

    @staticmethod
    def man_cq(command: str, cq: int):
        """Return command with new cq value"""
        mt = '--cq-level='
        cmd = command[:command.find(mt) + 11] + str(cq) + command[command.find(mt) + 13:]
        return cmd

    @staticmethod
    def frame_probe(source: Path):
        """Get frame count."""
        cmd = ["ffmpeg", "-hide_banner", "-i", source.absolute(), "-map", "0:v:0", "-f", "null", "-"]
        r = subprocess.run(cmd, stdout=PIPE, stderr=PIPE)
        matches = re.findall(r"frame=\s*([0-9]+)\s", r.stderr.decode("utf-8") + r.stdout.decode("utf-8"))
        return int(matches[-1])

    @staticmethod
    def get_brightness(video):
        """Getting average brightness value for single video."""
        brightness = []
        cap = cv2.VideoCapture(video)
        try:
            while True:
                # Capture frame-by-frame
                _, frame = cap.read()

                # Our operations on the frame come here
                gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

                # Display the resulting frame
                mean = cv2.mean(gray)
                brightness.append(mean[0])
                if cv2.waitKey(1) & 0xFF == ord('q'):
                    break
        except cv2.error:
            pass

        # When everything done, release the capture
        cap.release()
        brig_geom = round(statistics.geometric_mean([x + 1 for x in brightness]), 1)

        return brig_geom

    def log(self, info):
        """Default logging function, write to file."""
        with open(self.d.get('logging'), 'a') as log:
            log.write(time.strftime('%X') + ' ' + info)

    def call_cmd(self, cmd, capture_output=False):
        """Calling system shell, if capture_output=True output string will be returned."""
        if capture_output:
            return subprocess.run(cmd, shell=True, stdout=PIPE, stderr=STDOUT).stdout

        with open(self.d.get('logging'), 'a') as log:
            subprocess.run(cmd, shell=True, stdout=log, stderr=log)

    def check_executables(self):
        if not find_executable('ffmpeg'):
            print('No ffmpeg')
            self.terminate()

        # Check if encoder executable is reachable
        if self.d.get('encoder') in self.encoders:
            enc = self.encoders.get(self.d.get('encoder'))

            if not find_executable(enc):
                print(f'Encoder {enc} not found')
                self.terminate()
        else:
            print(f'Not valid encoder {self.d.get("encoder")} ')
            self.terminate()

    def process_inputs(self):
        # Check input file for being valid
        if not self.d.get('input'):
            print('No input file')
            self.terminate()

        inputs = self.d.get('input')

        if inputs[0].is_dir():
            inputs = [x for x in inputs[0].iterdir() if x.suffix in (".mkv", ".mp4", ".mov", ".avi", ".flv", ".m2ts")]

        valid = np.array([i.exists() for i in inputs])

        if not all(valid):
            print(f'File(s) do not exist: {", ".join([str(inputs[i]) for i in np.where(not valid)[0]])}')
            self.terminate()

        if len(inputs) > 1:
            self.d['queue'] = inputs
        else:
            self.d['input'] = inputs[0]

    def config(self):
        """Creation and reading of config files with saved settings"""
        cfg = self.d.get('config')
        if cfg:
            if cfg.exists():
                with open(cfg) as f:
                    c: dict = dict(json.load(f))
                    self.d.update(c)

            else:
                with open(cfg, 'w') as f:
                    c = dict()
                    c['video_params'] = self.d.get('video_params')
                    c['encoder'] = self.d.get('encoder')
                    c['ffmpeg'] = self.d.get('ffmpeg')
                    c['audio_params'] = self.d.get('audio_params')
                    json.dump(c, f)

        # Changing pixel format, bit format
        self.d['pix_format'] = f'-strict -1 -pix_fmt {self.d.get("pix_format")}'
        self.d['ffmpeg_pipe'] = f' {self.d.get("ffmpeg")} {self.d.get("pix_format")} -f yuv4mpegpipe - |'

        # Make sure that vmaf calculated after encoding
        if self.d.get('vmaf_target'):
            self.d['vmaf'] = True

        if self.d.get("vmaf_path"):
            if not Path(self.d.get("vmaf_path")).exists():
                print(f'No such model: {Path(self.d.get("vmaf_path")).as_posix()}')
                self.terminate()

    def arg_parsing(self):
        """Command line parse and sanity checking."""
        parser = argparse.ArgumentParser()
        parser.add_argument('--mode', '-m', type=int, default=0, help='0 - local, 1 - master, 2 - encoder')

        # Input/Output/Temp
        parser.add_argument('--input', '-i', nargs='+', type=Path, help='Input File')
        parser.add_argument('--temp', type=Path, default=Path('.temp'), help='Set temp folder path')
        parser.add_argument('--output_file', '-o', type=Path, default=None, help='Specify output file')

        # PySceneDetect split
        parser.add_argument('--scenes', '-s', type=str, default=None, help='File location for scenes')
        parser.add_argument('--threshold', '-tr', type=float, default=50, help='PySceneDetect Threshold')
        parser.add_argument('--extra_split', '-xs', type=int, default=0, help='Number of frames after which make split')

        # Encoding
        parser.add_argument('--passes', '-p', type=int, default=2, help='Specify encoding passes')
        parser.add_argument('--video_params', '-v', type=str, default='', help='encoding settings')
        parser.add_argument('--encoder', '-enc', type=str, default='aom', help='Choosing encoder')
        parser.add_argument('--workers', '-w', type=int, default=0, help='Number of workers')
        parser.add_argument('-cfg', '--config', type=Path, help='Parameters file. Save/Read: '
                                                                'Video, Audio, Encoder, FFmpeg parameteres')

        # FFmpeg params
        parser.add_argument('--ffmpeg', '-ff', type=str, default='', help='FFmpeg commands')
        parser.add_argument('--audio_params', '-a', type=str, default='-c:a copy', help='FFmpeg audio settings')
        parser.add_argument('--pix_format', '-fmt', type=str, default='yuv420p', help='FFmpeg pixel format')

        # Misc
        parser.add_argument('--logging', '-log', type=str, default=None, help='Enable logging')
        parser.add_argument('--resume', '-r', help='Resuming previous session', action='store_true')
        parser.add_argument('--no_check', '-n', help='Do not check encodings', action='store_true')
        parser.add_argument('--keep', help='Keep temporally folder after encode', action='store_true')

        # Boost
        parser.add_argument('--boost', help='Experimental feature, decrease CQ of clip based on brightness.'
                                            'Darker = lower CQ', action='store_true')
        parser.add_argument('--boost_range', default=15, type=int, help='Range/strength of CQ change')
        parser.add_argument('--boost_limit', default=10, type=int, help='CQ limit for boosting')

        # Grain
        # Todo: grain stuf
        parser.add_argument('--grain', help='Exprimental feature, adds generated grain based on video brightness',
                            action='store_true')
        parser.add_argument('--grain_range')

        # Vmaf
        parser.add_argument('--vmaf', help='Calculating vmaf after encode', action='store_true')
        parser.add_argument('--vmaf_path', type=Path, default=None, help='Path to vmaf models')

        # Target Vmaf
        parser.add_argument('--vmaf_target', type=float, help='Value of Vmaf to target')
        parser.add_argument('--vmaf_steps', type=int, default=4, help='Steps between min and max qp for target vmaf')
        parser.add_argument('--min_cq', type=int, default=25, help='Min cq for target vmaf')
        parser.add_argument('--max_cq', type=int, default=50, help='Max cq for target vmaf')
        parser.add_argument('--vmaf_plots', help='Make plots of probes in temp folder', action='store_true')

        # Server parts
        parser.add_argument('--host', nargs='+', type=str, help='ips of encoders')

        # Store all vars in dictionary
        self.d = vars(parser.parse_args())

    def outputs_filenames(self):
        if self.d.get('output_file'):
            self.d['output_file'] = self.d.get('output_file').with_suffix('.mkv')
        else:
            self.d['output_file'] = Path(f'{self.d.get("input").stem}_av1.mkv')

    def determine_resources(self):
        """Returns number of workers that machine can handle with selected encoder."""

        # If set by user, skip
        if self.d.get('workers') != 0:
            return

        cpu = os.cpu_count()
        ram = round(virtual_memory().total / 2 ** 30)

        if self.d.get('encoder') == 'aom' or self.d.get('encoder') == 'rav1e' or self.d.get('encoder') == 'vpx':
            self.d['workers'] = round(min(cpu / 2, ram / 1.5))

        elif self.d.get('encoder') == 'svt_av1':
            self.d['workers'] = round(min(cpu, ram)) // 5

        # fix if workers round up to 0
        if self.d.get('workers') == 0:
            self.d['workers'] = 1

    def set_logging(self):
        """Setting logging file."""
        if self.d.get('logging'):
            self.d['logging'] = f"{self.d.get('logging')}.log"
        else:
            self.d['logging'] = self.d.get('temp') / 'log.log'

        self.log(f"Av1an Started\nCommand:\n{' '.join(sys.argv)}\n")

    def setup(self):
        """Creating temporally folders when needed."""
        # Make temporal directories, and remove them if already presented
        if not self.d.get('resume'):
            if self.d.get('temp').is_dir():
                shutil.rmtree(self.d.get('temp'))

        (self.d.get('temp') / 'split').mkdir(parents=True, exist_ok=True)
        (self.d.get('temp') / 'encode').mkdir(exist_ok=True)

        if self.d.get('logging') is os.devnull:
            self.d['logging'] = self.d.get('temp') / 'log.log'

    def extract_audio(self, input_vid: Path):
        """Extracting audio from source, transcoding if needed."""
        audio_file = self.d.get('temp') / 'audio.mkv'
        if audio_file.exists():
            self.log('Reusing Audio File\n')
            return

        # Checking is source have audio track
        check = fr'{self.FFMPEG} -ss 0 -i "{input_vid}" -t 0 -vn -c:a copy -f null -'
        is_audio_here = subprocess.run(check, shell=True, stdout=PIPE, stderr=STDOUT).stdout == 0

        # If source have audio track - process it
        if is_audio_here:
            self.log(f'Audio processing\n'
                     f'Params: {self.d.get("audio_params")}\n')
            cmd = f'{self.FFMPEG} -i "{input_vid}" -vn ' \
                  f'{self.d.get("audio_params")} {audio_file}'
            self.call_cmd(cmd)

    def call_vmaf(self, source: Path, encoded: Path, file=False):

        model: Path = self.d.get("vmaf_path")
        if model:
            mod = f":model_path={model}"
        else:
            mod = ''

        # For vmaf calculation both source and encoded segment scaled to 1080
        # for proper vmaf calculation
        fl = source.with_name(encoded.stem).with_suffix('.xml').as_posix()
        cmd = f'ffmpeg -hide_banner -r 60 -i {source.as_posix()} -r 60 -i {encoded.as_posix()}  ' \
              f'-filter_complex "[0:v]scale=-1:1080:flags=spline[scaled1];' \
              f'[1:v]scale=-1:1080:flags=spline[scaled2];' \
              f'[scaled2][scaled1]libvmaf=log_path={fl}{mod}" -f null - '

        call = self.call_cmd(cmd, capture_output=True)
        if file:
            return fl

        call = call.decode().strip()
        vmf = call.split()[-1]
        try:
            vmf = float(vmf)
        except ValueError:
            vmf = 0
        return vmf

    def reduce_scenes(self, scenes):
        """Windows terminal can't handle more than ~600 scenes in length."""
        if len(scenes) > 600:
            scenes = scenes[::2]
            self.reduce_scenes(scenes)
        return scenes

    def scene_detect(self, video: Path):
        """
        Running PySceneDetect detection on source video for segmenting.
        Optimal threshold settings 15-50
        """
        # Skip scene detection if the user choose to
        if self.d.get('scenes') == '0':
            self.log('Skipping scene detection\n')
            return ''

        try:
            video_manager = VideoManager([str(video)])
            scene_manager = SceneManager()
            scene_manager.add_detector(ContentDetector(threshold=self.d.get('threshold')))
            base_timecode = video_manager.get_base_timecode()

            # If stats file exists, load it.
            scenes = self.d.get('scenes')
            if scenes:
                scenes = Path(scenes)
                if scenes.exists():
                    # Read stats from CSV file opened in read mode:
                    with scenes.open() as stats_file:
                        stats = stats_file.read().strip()
                        self.log('Using Saved Scenes\n')
                        return stats

            # Work on whole video
            video_manager.set_duration()

            # Set downscale factor to improve processing speed.
            video_manager.set_downscale_factor()

            # Start video_manager.
            video_manager.start()

            # Perform scene detection on video_manager.
            self.log(f'Starting scene detection Threshold: {self.d.get("threshold")}\n')

            # Fix for cli batch encoding
            progress = False if self.d.get('queue') else True

            scene_manager.detect_scenes(frame_source=video_manager, show_progress=progress)

            # Obtain list of detected scenes.
            scene_list = scene_manager.get_scene_list(base_timecode)

            self.log(f'Found scenes: {len(scene_list)}\n')

            scenes = [str(scene[0].get_frames()) for scene in scene_list]

            # Fix for windows character limit
            if sys.platform != 'linux':
                scenes = self.reduce_scenes(scenes)

            scenes = ','.join(scenes[1:])

            # We only write to the stats file if a save is required:
            if self.d.get('scenes'):
                Path(self.d.get('scenes')).write_text(scenes)
            return scenes

        except Exception as e:
            self.log(f'Error in PySceneDetect: {e}\n')
            print(f'Error in PySceneDetect{e}\n')
            self.terminate()

    def split(self, video: Path, frames):
        """Split video by frame numbers, or just copying video."""

        cmd = [
            "ffmpeg", "-hide_banner", "-y",
            "-i", video.absolute().as_posix(),
            "-map", "0:v:0",
            "-an",
            "-c", "copy",
            "-avoid_negative_ts", "1"
        ]

        if len(frames) > 0:
            cmd.extend([
                "-f", "segment",
                "-segment_frames", frames
            ])
        cmd.append(os.path.join(self.d.get("temp"), "split", "%05d.mkv"))
        pipe = subprocess.Popen(cmd, stdout=PIPE, stderr=STDOUT)
        while True:
            line = pipe.stdout.readline().strip()
            if len(line) == 0 and pipe.poll() is not None:
                break

    def frame_check(self, source: Path, encoded: Path):
        """Checking is source and encoded video frame count match."""
        try:
            status_file = Path(self.d.get("temp") / 'done.json')
            with status_file.open() as f:
                d = json.load(f)

            if self.d.get("no_check"):
                s1 = Av1an.frame_probe(source)
                d['done'][source.name] = s1
                with status_file.open('w') as f:
                    json.dump(d, f)
                    return

            s1, s2 = [Av1an.frame_probe(i) for i in (source, encoded)]

            if s1 == s2:
                d['done'][source.name] = s1
                with status_file.open('w') as f:
                    json.dump(d, f)
            else:
                print(f'Frame Count Differ for Source {source.name}: {s2}/{s1}')
        except IndexError:
            print('Encoding failed, check validity of your encoding settings/commands and start again')
            self.terminate()
        except Exception as e:
            _, _, exc_tb = sys.exc_info()
            print(f'\nError frame_check: {e}\nAt line: {exc_tb.tb_lineno}\n')

    def get_video_queue(self, source_path: Path):
        """Returns sorted list of all videos that need to be encoded. Big first."""
        queue = [x for x in source_path.iterdir() if x.suffix == '.mkv']

        done_file = self.d.get('temp') / 'done.json'
        if self.d.get('resume') and done_file.exists():
            try:
                with open(done_file) as f:
                    data = json.load(f)
                data = data['done'].keys()
                queue = [x for x in queue if x.name not in data]
            except Exception as e:
                _, _, exc_tb = sys.exc_info()
                print(f'Error at resuming {e}\nAt line {exc_tb.tb_lineno}')

        queue = sorted(queue, key=lambda x: -x.stat().st_size)

        if len(queue) == 0:
            # TODO: this could also be because we're resuming but everything
            # is done.
            print('Error: No files found in .temp/split, probably splitting not working')
            self.terminate()

        return queue

    def svt_av1_encode(self, inputs):
        """SVT-AV1 encoding command composition."""
        encoder = 'SvtAv1EncApp'
        pipe = self.d.get("ffmpeg_pipe")
        params = self.d.get("video_params")
        passes = self.d.get('passes')
        commands = []
        if not params:
            print('-w -h -fps is required parameters for svt_av1 encoder')
            self.terminate()

        if passes == 1:
            commands = [
                (f'-i {file[0]} {pipe} ' +
                 f'  {encoder} -i stdin {params} -b {file[1].with_suffix(".ivf")} -',
                 (file[0], file[1].with_suffix('.ivf')))
                for file in inputs]

        if passes == 2:
            p2i = '-input-stat-file '
            p2o = '-output-stat-file '
            commands = [
                (f'-i {file[0]} {pipe} {encoder} -i stdin {params} {p2o} '
                 f'{file[0].with_suffix(".stat")} -b {file[0]}.bk - ',
                 f'-i {file[0]} {pipe} '
                 f'{encoder} -i stdin {params} {p2i} {file[0].with_suffix(".stat")} -b '
                 f'{file[1].with_suffix(".ivf")} - ',
                 (file[0], file[1].with_suffix('.ivf')))
                for file in inputs]

        return commands

    def aom_vpx_encode(self, inputs):
        """AOM encoding command composition."""
        enc = self.encoders.get(self.d.get('encoder'))
        single_p = f'{enc} --passes=1 '
        two_p_1 = f'{enc} --passes=2 --pass=1'
        two_p_2 = f'{enc} --passes=2 --pass=2'
        passes = self.d.get('passes')
        pipe = self.d.get("ffmpeg_pipe")
        params = self.d.get("video_params")
        commands = []
        if not params:
            if enc == 'vpxenc':
                p = '--codec=vp9 --threads=4 --cpu-used=1 --end-usage=q --cq-level=40'
                self.d["video_params"], params = p, p
            if enc == 'aomenc':
                p = '--threads=4 --cpu-used=6 --end-usage=q --cq-level=40'
                self.d["video_params"], params = p, p

        if passes == 1:
            commands = [
                (f'-i {file[0]} {pipe} {single_p} {params} -o {file[1].with_suffix(".ivf")} - ',
                 (file[0], file[1].with_suffix('.ivf')))
                for file in inputs]

        if passes == 2:
            commands = [
                (f'-i {file[0]} {pipe} {two_p_1} {params} --fpf={file[0].with_suffix(".log")} -o {os.devnull} - ',
                 f'-i {file[0]} {pipe} {two_p_2} {params} --fpf={file[0].with_suffix(".log")} -o {file[1].with_suffix(".ivf")} - ',
                 (file[0], file[1].with_suffix('.ivf')))
                for file in inputs]

        return commands

    def rav1e_encode(self, inputs):
        """Rav1e encoding command composition."""
        passes = self.d.get('passes')
        pipe = self.d.get("ffmpeg_pipe")
        params = self.d.get("video_params")
        commands = []

        if not self.d.get("video_params"):
            self.d["video_params"] = ' --tiles 8 --speed 10 --quantizer 100'

        if passes in (1, 2):
            commands = [
                (f'-i {file[0]} {pipe} '
                 f' rav1e -  {params}  '
                 f'--output {file[1].with_suffix(".ivf")}',
                 (file[0], file[1].with_suffix('.ivf')))
                for file in inputs]

        # 2 encode pass not working with FFmpeg pipes :(
        if passes == 2:
            commands = [
                (f'-i {file[0]} {pipe} '
                 f' rav1e - --first-pass {file[0].with_suffix(".stat")} {params} '
                 f'--output {file[1].with_suffix(".ivf")}',
                 f'-i {file[0]} {pipe} '
                 f' rav1e - --second-pass {file[0].with_suffix(".stat")} {params} '
                 f'--output {file[1].with_suffix(".ivf")}',
                 (file[0], file[1].with_suffix('.ivf')))
                for file in inputs]

        return commands

    def compose_encoding_queue(self, files):
        """Composing encoding queue with split videos."""
        inputs = [(self.d.get('temp') / "split" / file.name,
                   self.d.get('temp') / "encode" / file.name,
                   file) for file in files]

        if self.d.get('encoder') in ('aom', 'vpx'):
            queue = self.aom_vpx_encode(inputs)

        elif self.d.get('encoder') == 'rav1e':
            queue = self.rav1e_encode(inputs)

        elif self.d.get('encoder') == 'svt_av1':
            queue = self.svt_av1_encode(inputs)

        self.log(f'Encoding Queue Composed\n'
                 f'Encoder: {self.d.get("encoder").upper()} Queue Size: {len(queue)} Passes: {self.d.get("passes")}\n'
                 f'Params: {self.d.get("video_params")}\n')

        # Catch Error
        if len(queue) == 0:
            print('Error in making command queue')
            self.terminate()

        return queue

    def boost(self, command: str, br_geom, new_cq=0):
        """Based on average brightness of video decrease(boost) Quantize value for encoding."""
        b_limit = self.d.get('boost_limit')
        b_range = self.d.get('boost_range')
        try:
            cq = Av1an.get_cq(command)
            if not new_cq:
                if br_geom < 128:
                    new_cq = cq - round((128 - br_geom) / 128 * b_range)
                    new_cq = max(b_limit, new_cq)

                else:
                    new_cq = cq
            cmd = Av1an.man_cq(command, new_cq)

            return cmd, new_cq

        except Exception as e:
            _, _, exc_tb = sys.exc_info()
            print(f'Error in encoding loop {e}\nAt line {exc_tb.tb_lineno}')

    def plot_vmaf(self):

        if not self.d.get("vmaf"):
            return
        print('Calculating Vmaf...\r', end='')
        if self.d.get("vmaf_path"):
            model = f'model_path={self.d.get("vmaf_path")}'
        else:
            model = ''

        inp: Path = self.d.get('input')
        out: Path = self.d.get('output_file')
        xml: str = "vmaf.xml"

        # For vmaf calculation both source and encoded segment scaled to 1080
        # for proper vmaf calculation
        cmd = f'ffmpeg -hide_banner -r 60 -i {inp.as_posix()} -r 60 -i {out.as_posix()}  ' \
              f'-filter_complex "[0:v]scale=-1:1080:flags=spline[scaled1];' \
              f'[1:v]scale=-1:1080:flags=spline[scaled2];' \
              f'[scaled2][scaled1]libvmaf=log_path={xml}:{model}" -f null - '
        self.call_cmd(cmd, capture_output=True)

        if not Path(xml).exists():
            print(f'Vmaf calculation failed for files:\n {inp.stem} {out.stem}')
            self.terminate()

        vmafs, mean, perc_1, perc_25, perc_75 = Av1an.read_vmaf_xml(xml)

        # Plot
        plt.figure(figsize=(15, 4))

        for i in range(0, 100):
            plt.axhline(i, color='grey', linewidth=0.4)

            if i % 5 == 0:
                plt.axhline(i, color='black', linewidth=0.6)

        plt.plot(range(len(vmafs)), vmafs,
                 label=f'Frames: {len(vmafs)}\nMean:{mean}\n'
                       f'1%: {perc_1} \n25%: {perc_25} \n75%: {perc_75}', linewidth=0.7)
        plt.ylabel('VMAF')
        plt.legend(loc="lower right", markerscale=0, handlelength=0, fancybox=True, )
        plt.ylim(int(perc_1), 100)
        plt.tight_layout()
        plt.margins(0)

        # Save
        file_name = str(self.d.get('output_file').stem) + '_plot.png'
        plt.savefig(file_name, dpi=500)

    def target_vmaf(self, source):
        # TODO speed up for vmaf stuff
        # TODO reduce complexity

        if self.d.get('vmaf_steps') < 4:
            print('Target vmaf require more than 3 probes/steps')
            self.terminate()

        vmaf_target = self.d.get('vmaf_target')
        mincq = self.d.get('min_cq')
        maxcq = self.d.get('max_cq')
        steps = self.d.get('vmaf_steps')
        frames = Av1an.frame_probe(source)
        probe = source.with_suffix(".mp4")
        plot_probes = self.d.get('vmaf_plots')
        ffmpeg = self.d.get('ffmpeg')

        try:
            # Making 4 fps probing file
            cmd = f'{self.FFMPEG} -i {source.as_posix()} ' \
                  f'-r 4 -an {ffmpeg} -c:v libx264 -crf 0 {source.with_suffix(".mp4")}'
            self.call_cmd(cmd)

            # Make encoding fork
            q = list(np.unique(np.linspace(mincq, maxcq, num=steps, dtype=int, endpoint=True)))

            # Moving highest cq to first check, for early skips
            # checking highest first, lowers second, for early skips
            q.insert(0, q.pop(-1))
            # Encoding probes, 1 pass, highest speed
            single_p = 'aomenc  -q --passes=1 '
            params = "--threads=8 --end-usage=q --cpu-used=6 --cq-level="
            cmd = [[f'{self.FFMPEG} -i {probe} {self.d.get("ffmpeg_pipe")} {single_p} '
                    f'{params}{x} -o {probe.with_name(f"v_{x}{probe.stem}")}.ivf - ',
                    probe, probe.with_name(f'v_{x}{probe.stem}').with_suffix('.ivf'), x] for x in q]

            # Encoding probe and getting vmaf
            ls = []
            pr = []
            for count, i in enumerate(cmd):
                self.call_cmd(i[0])

                v = self.call_vmaf(i[1], i[2], file=True)
                _, mean, perc_1, perc_25, perc_75 = Av1an.read_vmaf_xml(v)

                pr.append(round(mean, 1))
                ls.append((round(mean, 3), i[3]))

                # Early Skip on big CQ
                if count == 0 and round(mean) > vmaf_target:
                    self.log(f"File: {source.stem}, Fr: {frames}\n"
                             f"Probes: {pr}, Early Skip High CQ\n"
                             f"Target CQ: {maxcq}\n\n")
                    return maxcq, f'Target: CQ {maxcq} Vmaf: {round(mean, 2)}\n'

                # Early Skip on small CQ
                if count == 1 and round(mean) < vmaf_target:
                    self.log(f"File: {source.stem}, Fr: {frames}\n"
                             f"Probes: {pr}, Early Skip Low CQ\n"
                             f"Target CQ: {mincq}\n\n")
                    return mincq, f'Target: CQ {mincq} Vmaf: {round(mean, 2)}\n'

            x = [x[1] for x in sorted(ls)]
            y = [float(x[0]) for x in sorted(ls)]

            # Interpolate data
            f = interpolate.interp1d(x, y, kind='cubic')
            xnew = np.linspace(min(x), max(x), max(x) - min(x))

            # Getting value closest to target
            tl = list(zip(xnew, f(xnew)))
            vmaf_target_cq = min(tl, key=lambda x: abs(x[1] - vmaf_target))

            if plot_probes:
                # Saving plot of got data
                plt.plot(x, y, 'x', color='tab:blue')
                plt.plot(xnew, f(xnew), color='tab:blue')
                plt.plot(vmaf_target_cq[0], vmaf_target_cq[1], 'o', color='red')

                for x in range(0, 100):
                    plt.axhline(x, color='grey', linewidth=0.4)
                    plt.axvline(x, color='grey', linewidth=0.3)

                    if x % 5 == 0:
                        plt.axhline(x, color='black', linewidth=0.6)

                plt.xlim(mincq, maxcq)
                vmafs = [int(x[1]) for x in tl if isinstance(x[1], float) and not isnan(x[1])]
                plt.ylim(min(vmafs), max(vmafs) + 1)
                plt.ylabel('VMAF')
                plt.xlabel('CQ')
                plt.title(f'Chunk: {probe.stem}, Frames: {frames}')
                plt.tight_layout()
                temp = self.d.get('temp') / probe.stem
                plt.savefig(temp, dpi=300)
                plt.close()

            self.log(f"File: {source.stem}, Fr: {frames}\n"
                     f"Probes: {sorted(pr)}\n"
                     f"Target CQ: {round(vmaf_target_cq[0])}\n\n")

            return int(vmaf_target_cq[0]), f'Target: CQ {int(vmaf_target_cq[0])} Vmaf: {round(float(vmaf_target_cq[1]), 2)}\n'

        except Exception as e:
            _, _, exc_tb = sys.exc_info()
            print(f'Error in vmaf_target {e} \nAt line {exc_tb.tb_lineno}')
            self.terminate()

    def encode(self, commands):
        """Single encoder command queue and logging output."""
        counter = commands[1]
        commands = commands[0]
        encoder = self.d.get('encoder')
        # Passing encoding params to ffmpeg for encoding.
        # Replace ffmpeg with aom because ffmpeg aom doesn't work with parameters properly.
        try:
            st_time = time.time()
            source, target = Path(commands[-1][0]), Path(commands[-1][1])
            frame_probe_source = Av1an.frame_probe(source)

            # Target Vmaf Mode
            if self.d.get('vmaf_target'):
                tg_cq, tg_vf = self.target_vmaf(source)

                cm1 = self.man_cq(commands[0], tg_cq)

                if self.d.get('passes') == 2:
                    cm2 = self.man_cq(commands[1], tg_cq)
                    commands = (cm1, cm2) + commands[2:]
                else:
                    commands = cm1 + commands[1:]

            else:
                tg_vf = ''

            # Boost
            if self.d.get('boost'):
                br = self.get_brightness(source.absolute().as_posix())

                com0, cq = self.boost(commands[0], br)

                if self.d.get('passes') == 2:
                    com1, _ = self.boost(commands[1], br, cq)
                    commands = (com0, com1) + commands[2:]
                else:
                    commands = com0 + commands[1:]

                boost = f'Avg brightness: {br}\nAdjusted CQ: {cq}\n'
            else:
                boost = ''

            self.log(f'Enc: {source.name}, {frame_probe_source} fr\n{tg_vf}{boost}\n')

            # Queue execution
            for i in commands[:-1]:
                f, e = i.split('|')
                f = self.FFMPEG + f
                f, e = f.split(), e.split()

                try:
                    frame = 0

                    ffmpeg_pipe = subprocess.Popen(f, stdout=PIPE, stderr=STDOUT)
                    pipe = subprocess.Popen(e, stdin=ffmpeg_pipe.stdout, stdout=PIPE,
                                            stderr=STDOUT,
                                            universal_newlines=True)
                    if encoder in ('aom', 'vpx'):
                        while True:
                            line = pipe.stdout.readline().strip()
                            if len(line) == 0 and pipe.poll() is not None:
                                break
                            if 'Pass 2/2' in line or 'Pass 1/1' in line:
                                match = re.search(r"frame.*?\/([^ ]+?) ", line)
                                if match:
                                    new = int(match.group(1))
                                    if new > frame:
                                        counter.update(new - frame)
                                        frame = new

                    elif encoder == 'rav1e':
                        while True:
                            line = pipe.stdout.readline().strip()
                            if len(line) == 0 and pipe.poll() is not None:
                                break
                            match = re.search(r"encoded.*? ([^ ]+?) ", line)
                            if match:
                                new = int(match.group(1))
                                if new > frame:
                                    counter.update(new - frame)
                                    frame = new

                    elif encoder == 'svt_av1':
                        while True:
                            line = pipe.stdout.readline().strip()
                            if len(line) == 0 and pipe.poll() is not None:
                                break
                        counter.update(frame_probe_source)

                except Exception as e:
                    _, _, exc_tb = sys.exc_info()
                    print(f'Error at encode {e}\nAt line {exc_tb.tb_lineno}')

            self.frame_check(source, target)

            frame_probe = Av1an.frame_probe(target)

            enc_time = round(time.time() - st_time, 2)

            self.log(f'Done: {source.name} Fr: {frame_probe}\n'
                     f'Fps: {round(frame_probe / enc_time, 4)} Time: {enc_time} sec.\n\n')
        except Exception as e:
            _, _, exc_tb = sys.exc_info()
            print(f'Error in encoding loop {e}\nAt line {exc_tb.tb_lineno}')

    def concatenate_video(self):
        """With FFMPEG concatenate encoded segments into final file."""
        with open(f'{self.d.get("temp") / "concat" }', 'w') as f:

            encode_files = sorted((self.d.get('temp') / 'encode').iterdir())
            f.writelines(f"file '{file.absolute()}'\n" for file in encode_files)

        # Add the audio file if one was extracted from the input
        audio_file = self.d.get('temp') / "audio.mkv"
        if audio_file.exists():
            audio = f'-i {audio_file} -c:a copy'
        else:
            audio = ''

        try:
            cmd = f'{self.FFMPEG} -f concat -safe 0 -i {self.d.get("temp") / "concat"} ' \
                  f'{audio} -c copy -y "{self.d.get("output_file")}"'
            concat = self.call_cmd(cmd, capture_output=True)
            if len(concat) > 0:
                raise Exception

            self.log('Concatenated\n')

            # Delete temp folders
            if not self.d.get('keep'):
                shutil.rmtree(self.d.get('temp'))

        except Exception as e:
            _, _, exc_tb = sys.exc_info()
            print(f'Concatenation failed, FFmpeg error\nAt line: {exc_tb.tb_lineno}\nError:{str(concat)}')
            self.log(f'Concatenation failed, aborting, error: {e}\n')
            self.terminate()

    def encoding_loop(self, commands):
        """Creating process pool for encoders, creating progress bar."""
        try:
            enc_path = self.d.get('temp') / 'split'
            done_path = self.d.get('temp') / 'done.json'

            if self.d.get('resume') and done_path.exists():
                self.log('Resuming...\n')

                with open(done_path) as f:
                    data = json.load(f)

                total = data['total']
                done = len(data['done'])
                initial = sum(data['done'].values())

                self.log(f'Resumed with {done} encoded clips done\n\n')
            else:
                initial = 0
                total = self.frame_probe(self.d.get('input'))
                d = {'total': total, 'done': {}}
                with open(done_path, 'w') as f:
                    json.dump(d, f)

            clips = len([x for x in enc_path.iterdir() if x.suffix == ".mkv"])
            w = min(self.d.get('workers'), clips)

            print(f'\rQueue: {clips} Workers: {w} Passes: {self.d.get("passes")}\n'
                  f'Params: {self.d.get("video_params").strip()}')

            with concurrent.futures.ThreadPoolExecutor(max_workers=self.d.get('workers')) as executor:
                counter = Manager().Counter(total, initial)
                future_cmd = {executor.submit(self.encode, (cmd, counter)): cmd for cmd in commands}
                for future in concurrent.futures.as_completed(future_cmd):
                    future_cmd[future]
                    try:
                        future.result()
                    except Exception as exc:
                        print(f'Encoding error: {exc}')
                        self.terminate()
        except KeyboardInterrupt:
            self.terminate()

    def extra_split(self, frames):
        if len(frames) > 0:
            f = literal_eval(frames)
            if len(f) > 1:
                f = list(f)
        else:
            f = []
        f.append(Av1an.frame_probe(self.d.get('input')))
        split_distance = self.d.get('extra_split')

        # Get all keyframes of original video
        keyframes = Av1an.get_keyframes(self.d.get('input'))

        t = f[:]
        t.insert(0, 0)
        splits = list(zip(t, f))
        for i in splits:
            # Getting distance between splits
            distance = (i[1] - i[0])

            if distance > split_distance:
                # Keyframes that between 2 split points
                candidates = [k for k in keyframes if i[1] > k > i[0]]

                if len(candidates) > 0:
                    # Getting number of splits that need to be inserted
                    to_insert = min((i[1] - i[0]) // split_distance, (len(candidates)))
                    for k in range(0, to_insert):
                        # Approximation of splits position
                        aprox_to_place = (((k + 1) * distance) // (to_insert + 1)) + i[0]

                        # Getting keyframe closest to approximated
                        key = min(candidates, key=lambda x: abs(x - aprox_to_place))
                        f.append(key)
        self.log(f'Applying extra splits\nSplit distance: {split_distance}\nNew splits:{len(f)}\n')
        result = [str(x) for x in sorted(f)]
        result = ','.join(result)
        return result

    def setup_routine(self):
        """
        All pre encoding routine.
        Scene detection, splitting, audio extraction
        """
        if self.d.get('resume') and (self.d.get('temp') / 'done.json').exists():
            self.set_logging()

        else:
            self.setup()
            self.set_logging()

            # Splitting video and sorting big-first
            framenums = self.scene_detect(self.d.get('input'))

            if self.d.get('extra_split'):
                framenums = self.extra_split(framenums)

            self.split(self.d.get('input'), framenums)

            # Extracting audio
            self.extract_audio(self.d.get('input'))

    def video_encoding(self):
        """Encoding video on local machine."""
        self.outputs_filenames()
        self.setup_routine()

        files = self.get_video_queue(self.d.get('temp') / 'split')

        # Make encode queue
        commands = self.compose_encoding_queue(files)

        # Determine resources if workers don't set
        self.determine_resources()

        self.encoding_loop(commands)

        self.concatenate_video()

        self.plot_vmaf()

    def main_queue(self):
        # Video Mode. Encoding on local machine
        tm = time.time()
        if self.d.get('queue'):
            for file in self.d.get('queue'):
                tm = time.time()
                self.d['input'] = file
                print(f'Encoding: {file}')
                self.d['output_file'] = None
                self.video_encoding()
                print(f'Finished: {round(time.time() - tm, 1)}s\n')
        else:
            self.video_encoding()
            print(f'Finished: {round(time.time() - tm, 1)}s')

    def main_thread(self):
        """Main."""
        self.arg_parsing()

        # Read/Set parameters
        self.config()

        # Check all executables
        self.check_executables()

        self.process_inputs()
        self.main_queue()

def main():
    # Main thread
    try:
        Av1an().main_thread()
    except KeyboardInterrupt:
        print('Encoding stopped')
        sys.exit()

if __name__ == '__main__':
    main()


def BFS(tree, root, goals):
    # init list of nodes was visted
    visted = dict()
    # init list of nodes will be passed througt, start with head node
    opens = [root]
    # init list of nodes was has been passed
    closed = list()
    isDone = False
    while not isDone:
        if len(opens) <= 0:
            break
        # current node
        node = opens[0]
        closed.append(node)
        if visted.get(node, False) == True:
            break
        else:
            visted[node] = True
        if(node in goals):
            isDone = True
            break
        opens.pop(0)
        childNodes = tree.get(node)
        if(childNodes):
            opens.extend(childNodes)
    print('\nBFS')
    if(isDone):
        print(' => '.join(closed))
    else:
        print(f'Not found [{", ".join(goals)}] in this tree')


# -*- coding: utf-8 -*-
"""
Created on Tue Feb 19 14:23:04 2019

@author: khaled.ghobashy
"""

import bpy
import numpy as np

from smbd.utilities.numerics.spatial_alg import triad

class cylinder_geometry(object):

    def __init__(self,arg1,arg2,ro=10,ri=0):
        self.name = 'cyl'
        self.p1 = arg1
        self.p2 = arg2
        self.ro = ro
        self.ri = ri
        self.n = 30
        self.axis = self.p2 - self.p1
        self.norm = self.axis/np.linalg.norm(self.axis)
        self.create_obj()

    @property
    def R(self):
        arr = np.array(self.obj.location)
        arr = np.reshape(arr, (3,1))
        return arr

    def create_obj(self):
        self._create_data()
        verts = self.data['verts']
        faces = self.data['faces']
        mesh = bpy.data.meshes.new('%s_mesh'%self.name)
        self.mesh = mesh
        obj  = bpy.data.objects.new(self.name, mesh)
        self.obj = obj
        mesh.from_pydata(verts, [], faces)
        mesh.update()
        bpy.context.scene.objects.link(obj)
        obj.rotation_mode = 'QUATERNION'
        obj.select = True
        bpy.context.scene.objects.active = obj
        bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS')
        obj.select = False

    def _create_data(self):
        c1_verts = self._create_circle_verts(self.p1)
        c2_verts = self._create_circle_verts(self.p2)
        faces = self._create_cylinder_faces()
        self.data = {'verts':c1_verts+c2_verts,'faces':faces}

    def _create_circle_verts(self,p):
        p = p[:,0]
        frame = triad(self.norm)
        v1 = frame[:,0]
        v2 = frame[:,1]
        angle = np.linspace(0,2*np.pi,self.n)
        verts = [tuple(p + self.ro*np.cos(i)*v1 + self.ro*np.sin(i)*v2) for i in angle]
        verts.append(verts[0])
        return verts

    def _create_cylinder_faces(self):
        n = self.n + 1
        faces = [(i, i+1, i+n+1, i+n) for i in range(self.n)]
        return faces

class triangular_prism(object):

    def __init__(self,p1,p2,p3,l=10):
        self.name = 'prism'
        self.p1 = p1
        self.p2 = p2
        self.p3 = p3
        self.l = l
        self.create()

    @property
    def R(self):
        arr = np.array(self.obj.location)
        arr = np.reshape(arr,(3,1))
        return arr

    def create(self):
        self._create_verts()
        self._create_faces()
        self._extrude()
        self._create_mesh()
        self._create_obj()

    def _create_verts(self):
        self._verts = [self.p1,self.p2,self.p3]
        self.n = len(self._verts)+1
        self._verts.append(self.p1)

    def _create_faces(self):
        top_face = tuple(range(self.n-1))
        bot_face = tuple(range(self.n,2*self.n,1))
        side_faces = [(i,i+1,i+self.n+1,i+self.n) for i in range(self.n-1)]
        self.faces = [top_face,bot_face] + side_faces

    def _extrude(self):
        v = self._get_normal() * self.l/2
        self.top_verts = [i+v for i in self._verts]
        self.bot_verts = [i-v for i in self._verts]
        self.top_verts = [tuple(i[:,0]) for i in self.top_verts]
        self.bot_verts = [tuple(i[:,0]) for i in self.bot_verts]

    def _create_mesh(self):
        self.mesh = bpy.data.meshes.new('%s_mesh'%self.name)
        side_verts = self.top_verts + self.bot_verts
        cape_verts = self.top_verts[:-1] + self.bot_verts[:-1]
        verts = side_verts + cape_verts
        self.mesh.from_pydata(verts, [], self.faces)
        self.mesh.update()

    def _create_obj(self):
        self.obj = obj  = bpy.data.objects.new(self.name, self.mesh)
        bpy.context.scene.objects.link(self.obj)
        obj.rotation_mode = 'QUATERNION'
        obj.select = True
        bpy.context.scene.objects.active = obj
        bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS')
        obj.select = False

    def _get_normal(self):
        verts = self._verts
        a1 = verts[1] - verts[0]
        a2 = verts[2] - verts[0]
        v = np.cross(a2,a1,axisa=0,axisb=0)
        v = np.reshape(v,(3,1))
        v = v/np.linalg.norm(v)
        return abs(v)

class composite_geometry(object):
    pass


from collections import defaultdict
class Solution(object):
    def alienOrder(self, words):
        """
        :type words: List[str]
        :rtype: str
        """
        #build the graph
        V = set()
        Adj = defaultdict(list)

        for i,word in enumerate(words):
            for c in word:
                V.add(c)
            if i != len(words)-1:
                nextword = words[i+1]
                for j in range(min(len(word),len(nextword))):
                    if word[j]!=nextword[j]:
                        break
                if word[j]!= nextword[j]:
                    Adj[word[j]].append(nextword[j])

        #calculate the indegree of each node
        indegree = defaultdict(int)
        for v in V:
            for nextv in Adj[v]:
                indegree[nextv] += 1

        #topological sort
        candidate = []
        output = ""
        for v in V:
            if indegree[v] == 0:
                candidate.append(v)

        while len(candidate) > 0:
            v = candidate.pop()
            for nextv in Adj[v]:
                indegree[nextv] -= 1
                if indegree[nextv] == 0:
                    candidate.append(nextv)
            V.remove(v)
            del Adj[v]
            output += v

        if V:
            return ""

        return output


# -*- coding: utf-8 -*-
"""
 Created with IntelliJ IDEA.
 Description:
 User: jinhuichen
 Date: 4/15/2019 10:30 AM
 Description:
"""
import numpy as np
from queue import Queue
from simpleflow.graph import Graph

# Create a default graph.
DEFAULT_GRAPH = Graph()

# ------------------------------------------------------------------------------
# Function for gradients computation. 广度优先遍历
# ------------------------------------------------------------------------------

def compute_gradients(target_op):
    ''' Backpropagation implementation computing gradient of target operation wrt
        all the other connected nodes.

    :param target_op: The target operation whose gradient wrt other nodes would
                      be computed.
    :type target_op: Any operation type.

    :return grad_table: A table containing node objects and gradients.
    :type grad_table: dict.
    '''
    # A dict containing a mapping between node and gradient value of target_op wrt the node's output.
    # NOTE: It is the gradient wrt the node's OUTPUT NOT input.
    grad_table = {
        target_op: np.ones_like(target_op.output_value)
    }

    # The gradient wrt target_op itself is 1.

    # Perform a breadth-first search staring from the target_op in graph.
    # Queue for node traverasl.
    queue = Queue()
    queue.put(target_op)

    # Set for visited nodes.
    visited = set()
    visited.add(target_op)

    while not queue.empty():
        node = queue.get()

        # Compute gradient wrt the node's output.
        if node != target_op:
            grads_wrt_node_output = filter(lambda item: item is not None, map(
                lambda output_node: output_node.compute_gradient(node, grad=grad_table[output_node]),
                node.output_nodes
            ))
            # 相加所有的偏导
            grad_table[node] = sum(grads_wrt_node_output)

        # 放入邻接节点到队列
        if hasattr(node, 'input_nodes'):
            for input_node in node.input_nodes:
                if input_node not in visited:
                    visited.add(input_node)
                    queue.put(input_node)

    return grad_table


import pandas as pd
import xlrd
from collections import OrderedDict
import simplejson as json
# Read from an excel file
sourceSDFile = "C:\\Users\\Brandon\Documents\\GitHub\\School-District-Surveys-Project\\Resources\\SchoolsCountyStateList.xls"
#pd.ExcelFile class returns a DataFrame
#xslx = pd.ExcelFile(sourceSDFile)
sheetName = "sdlist_1516"
#open the workbook
print("Starting: Reading File")
wb = xlrd.open_workbook(sourceSDFile)
print("Completed: Reading File")
#Primary Sheet
primarySheet = wb.sheet_by_name(sheetName)

# List to hold dictionaries
list = []
print("Starting: Processing data into a local list")
for rownum in range(2, primarySheet.nrows):
    item = OrderedDict()
    row_values = primarySheet.row_values(rownum)
    item["StateAbbr"] = row_values[0]
    item["StateFIPS"] = row_values[1]
    item["DistrictIDNumber"] = row_values[2]
    item["SchoolDistrictName"] = row_values[3]
    item["CountyNames"] = row_values[4]
    item["CountyFIPS"] = row_values[5]
    list.append(item)
print("Complete: Processing data into a local list")

print("Starting: Serializing list to JSON")
# Serialize the lsit of dicts to JSON
j = json.dumps(list)
print("Complete: Serializing list to JSON")

# Write to file
print("Starting: Write JSON data to disk")
with open("C:\\Users\\Brandon\Documents\\GitHub\\School-District-Surveys-Project\\Resources\\data.json",'w') as f:
     f.write(j)

print("Complete: Write JSON data to disk")

#dataFrame = pd.read_excel(xslx, sheetName)
#print(dataFrame.head())
#StateAbbr(String),StateFIPS(INT),DistrictIDNumber(String),SchoolDistrictName(String)
#CountyNames(String), CountyFIPS (String)


# Copyright 2018 The Cirq Developers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Abstract base class for things sampling quantum circuits."""

from typing import List, Union, TYPE_CHECKING
import abc
import asyncio
import threading

from cirq import study

if TYPE_CHECKING:
    import cirq

class Sampler(metaclass=abc.ABCMeta):
    """Something capable of sampling quantum circuits. Simulator or hardware."""

    def run(
            self,
            program: Union['cirq.Circuit', 'cirq.Schedule'],
            param_resolver: 'cirq.ParamResolverOrSimilarType' = None,
            repetitions: int = 1,
    ) -> 'cirq.TrialResult':
        """Samples from the given Circuit or Schedule.

        By default, the `run_async` method invokes this method on another
        thread. So this method is supposed to be thread safe.

        Args:
            program: The circuit or schedule to sample from.
            param_resolver: Parameters to run with the program.
            repetitions: The number of times to sample.

        Returns:
            TrialResult for a run.
        """
        return self.run_sweep(program, study.ParamResolver(param_resolver),
                              repetitions)[0]

    @abc.abstractmethod
    def run_sweep(
            self,
            program: Union['cirq.Circuit', 'cirq.Schedule'],
            params: 'cirq.Sweepable',
            repetitions: int = 1,
    ) -> List['cirq.TrialResult']:
        """Samples from the given Circuit or Schedule.

        In contrast to run, this allows for sweeping over different parameter
        values.

        Args:
            program: The circuit or schedule to sample from.
            params: Parameters to run with the program.
            repetitions: The number of times to sample.

        Returns:
            TrialResult list for this run; one for each possible parameter
            resolver.
        """

    async def run_async(self, program: Union['cirq.Circuit', 'cirq.Schedule'],
                        *, repetitions: int) -> 'cirq.TrialResult':
        """Asynchronously samples from the given Circuit or Schedule.

        By default, this method calls `run` on another thread and yields the
        result via the asyncio event loop. However, child classes are free to
        override it to use other strategies.

        Args:
            program: The circuit or schedule to sample from.
            repetitions: The number of times to sample.

        Returns:
            An awaitable TrialResult.
        """
        results = await self.run_sweep_async(program, study.UnitSweep,
                                             repetitions)
        return results[0]

    async def run_sweep_async(
            self,
            program: Union['cirq.Circuit', 'cirq.Schedule'],
            params: 'cirq.Sweepable',
            repetitions: int = 1,
    ) -> List['cirq.TrialResult']:
        """Asynchronously sweeps and samples from the given Circuit or Schedule.

        By default, this method calls `run_sweep` on another thread and yields
        the result via the asyncio event loop. However, child classes are free
        to override it to use other strategies.

        Args:
            program: The circuit or schedule to sample from.
            params: One or more mappings from parameter keys to parameter values
                to use. For each parameter assignment, `repetitions` samples
                will be taken.
            repetitions: The number of times to sample.

        Returns:
            An awaitable TrialResult.
        """
        return await run_on_thread_async(lambda: self.run_sweep(
            program, params=params, repetitions=repetitions))

async def run_on_thread_async(func):
    loop = asyncio.get_event_loop()
    done = loop.create_future()  # type: asyncio.Future['cirq.TrialResult']

    def run():
        try:
            result = func()
        except Exception as exc:
            loop.call_soon_threadsafe(done.set_exception, exc)
        else:
            loop.call_soon_threadsafe(done.set_result, result)

    t = threading.Thread(target=run)
    t.start()
    return await done


#!/usr/bin/python

# Determine installed RAM size for machine (in megabytes)

import getopt
import sys
import subprocess

def usage(name):
    print("Usage: %s [-h] [-v] [-M] [-L]" % name)
    print(" -h               Print this message")
    print(" -v               Verbose Mode")
    print(" -M               Mac only")
    print(" -L               Linux only")

def show(verbose, str):
    if verbose:
        sys.stderr.write(str + '\n')

#For Mac.  Return gigabytes
def runMac(verbose = False):
    key = 'hw.memsize'
    cmd = ['sysctl', key]
    cmdline = " ".join(cmd)
    try:
        process = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
    except Exception as ex:
        show(verbose, "Cannot run command '%s' (%s)" % (cmdline, str(ex)))
        return 0
    code = process.wait()
    if code != 0:
        show(verbose, "Running '%s' returned code %d" % (cmdline, code))
        return 0
    (stdout, stderr) = process.communicate()
    lines = stdout.split('\n')
    if len(lines) < 1:
        show(verbose, "Runnning command '%s' produced no result" % cmdline)
        return 0
    fields = lines[0].split()
    if fields[0] != key + ':':
        show(verbose, "Got unexpected keyword '%s'" % fields[0])
        return 0
    try:
        bytes = int(fields[1])
    except Exception as ex:
        show(verbose, "Couldn't find byte count in response '%s'" % stdout)
        return 0
    return bytes/2**20

def runLinux(verbose = False):
    cmd = ['free', '-m']
    cmdline = " ".join(cmd)
    try:
        process = subprocess.Popen(cmd, stdout = subprocess.PIPE, stderr = subprocess.PIPE)
    except Exception as ex:
        show(verbose, "Cannot run command '%s' (%s)" % (cmdline, str(ex)))
        return 0
    code = process.wait()
    if code != 0:
        show(verbose, "Running '%s' returned code %d" % code)
        return 0
    (stdout, stderr) = process.communicate()
    col = 0
    lines = stdout.split('\n')
    if len(lines) < 2:
        show(verbose, "Running '%s' produced only %d lines" % len(lines))
    headings = lines[0].split()
    if len(headings) < 2 or headings[0] != 'total':
        show(verbose, "Bad header line '%s'.  headings[1] = %s" % (lines[0], headings[0]))
        return 0
    data = lines[1].split()
    if len(data) < 2 or data[0] != 'Mem:':
        show(verbose, "Bad data line '%s'" % lines[1])
        return 0
    try:
        mb = int(data[1])
        return mb
    except:
        show(verbose, "Cannot extract gigabyte count from line '%s'" % data)
        return 0

def megabytes(verbose = False, tryMac = True, tryLinux = True):
    mb = 0
    if tryMac:
        show(verbose, "Trying Mac")
        mb = runMac(verbose)
    if mb == 0 and tryLinux:
        show(verbose, "Trying Linux")
        mb = runLinux(verbose)
    if mb == 0:
        show(verbose, "Couldn't find memory size")
    return mb

def run(name, args):
    verbose = False
    tryMac = True
    tryLinux = True
    mb = 0
    optlist, args = getopt.getopt(args, 'hvLM')
    for (opt, val) in optlist:
        if opt == '-h':
            usage(name)
            return
        elif opt == '-v':
            verbose = True
        elif opt == '-M':
            tryMac = True
            tryLinux = False
        elif opt == '-L':
            tryLinux = True
            tryMac = False
    mb = megabytes(verbose, tryMac, tryLinux)
    print(str(mb))

if __name__ == "__main__":
    run(sys.argv[0], sys.argv[1:])


result = []
cnt = 0
while True:
    cnt = 0
    word = input()
    if word == "0":
        break
    for i in range(len(word)//2):
        if word[i] != word[(-i-1)]:
            result.append("no")
            cnt = 1
            break
    if cnt == 1:
        continue
    result.append("yes")

for i in result:
    print(i)


"""origame URL Configuration

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

from origame import views

schema_view = get_schema_view(
    openapi.Info(title="Origame API", default_version="v1"),
    public=True,
    permission_classes=(permissions.AllowAny,),
)

urlpatterns = [
    path("admin/", admin.site.urls),
    path("ping/", views.ping, name="request-ping"),
    path("version/", views.version, name="request-app-version"),

    # API Documentation
    path(
        "api/swagger-docs/",
        schema_view.with_ui("swagger", cache_timeout=0),
        name="schema-swagger-ui",
    ),
    path("api/docs/", include_docs_urls(title="Origame API")),

    url(r'^auth/', include('djoser.urls')),
    url(r'^auth/', include('djoser.urls.jwt')),

    path("api/crm/", include('crm.urls'))
]


import sys
import io
import numpy as np
import time

from ESGIZenotech import load_binary_stl
from ESGIZenotech import AABB
from ESGIZenotech import voxelize
from ESGIZenotech import bitstream
from ESGIZenotech import run_demo
from ESGIZenotech import run_numpy_stl_demo
from ESGIZenotech import bitstream_v1
from ESGIZenotech import bitstream_v2

def run_local(filename):
    s = time.time()
    with io.open(filename, 'rb') as stl_f:
        stl = load_binary_stl(stl_f)

    print(stl)
    print(stl.count)
    # todo plot stl
    print("load time:", time.time() - s)
    s = time.time()

    root = AABB(centre=np.array([0, 0, 0]), size=np.array([512, 512, 512]))
    occupied = voxelize(stl, root, 10)

    print("occupied time:", time.time() - s)
    s = time.time()

    # import pdb
    # pdb.set_trace()
    st = bitstream(occupied)
    # stream size
    print(len(st))
    print("bitstream time:", time.time() - s)

# 优化后的 bitstream
def run_bitstream_v1(filename, level=10):
    s = time.time()
    with io.open(filename, 'rb') as stl_f:
        stl = load_binary_stl(stl_f)

    print("triangle count", stl.count)
    # todo plot stl
    print("load time: ", time.time() - s, "s")
    s = time.time()

    root = AABB(centre=np.array([0, 0, 0]), size=np.array([512, 512, 512]))
    occupied = voxelize(stl, root, level)
    length = occupied.shape[0]

    print("cube level: ", level)
    print("cube size: ", length*length*length)
    print("cube point count: ", sum(sum(sum(occupied))))
    print("calc occupied time: ", time.time() - s, "s")
    s = time.time()

    #import pdb
    #pdb.set_trace()
    stream, flag = bitstream_v1(occupied)
    # stream size
    print("after compress bitstream size: ", len(stream))
    print("calc bitstream_v1 time:", time.time() - s, "s")

    # show cube
    show_cube(occupied)

# 优化后的 bitstream
def run_bitstream_v2(filename, level=10):
    s = time.time()
    with io.open(filename, 'rb') as stl_f:
        stl = load_binary_stl(stl_f)

    print("triangle count", stl.count)
    # todo plot stl
    print("load time: ", time.time() - s, "s")
    s = time.time()

    root = AABB(centre=np.array([0, 0, 0]), size=np.array([512, 512, 512]))
    occupied = voxelize(stl, root, level)
    length = occupied.shape[0]

    print("cube level: ", level)
    print("cube size: ", length*length*length)
    print("cube point count: ", sum(sum(sum(occupied))))
    print("calc occupied time: ", time.time() - s, "s")
    s = time.time()

    # import pdb
    # pdb.set_trace()
    stream, flag = bitstream_v2(occupied)
    # stream size
    print("after compress bitstream size: ", len(stream))
    print("calc bitstream_v1 time:", time.time() - s, "s")

    show_cube(occupied)

    import pdb
    pdb.set_trace()
    print('ok')

def show_cube(occupied):
    # show cube
    from matplotlib import pyplot
    from mpl_toolkits.mplot3d import Axes3D

    length = occupied.shape[0]
    points_index =  np.argwhere(occupied > 0)

    X = np.arange(length)
    Y = np.arange(length)
    Z = np.zeros((length, length))
    for pi, pj, pk in points_index:
        Z[pi][pj] = max(Z[pi][pj], pk)

    xx, yy = np.meshgrid(X, Y)
    X, Y = xx.ravel(), yy.ravel()
    dz = Z.ravel()
    # Construct arrays with the dimensions for the 16 bars.
    dx = dy = 1

    #
    dz_index = np.argwhere(dz>0)
    X1 = X[dz_index][:, 0]
    Y1 = Y[dz_index][:, 0]
    dz1 = dz[dz_index][:, 0]

    dz2 = (dz1 - length // 2)

    figure = pyplot.figure()
    axes = figure.gca(projection='3d')
    axes.bar3d(X1, Y1, 0, dx, dy, dz2, zsort='min')
    axes.set_xlabel('X')
    axes.set_ylabel('Y')
    axes.set_zlabel('Z(value)')

    pyplot.show()

def run_show_demo():
    from stl import mesh
    import math
    import numpy

    # Create 3 faces of a cube
    data = numpy.zeros(6, dtype=mesh.Mesh.dtype)

    # Top of the cube
    data['vectors'][0] = numpy.array([[0, 1, 1],
                                      [1, 0, 1],
                                      [0, 0, 1]])
    data['vectors'][1] = numpy.array([[1, 0, 1],
                                      [0, 1, 1],
                                      [1, 1, 1]])
    # Front face
    data['vectors'][2] = numpy.array([[1, 0, 0],
                                      [1, 0, 1],
                                      [1, 1, 0]])
    data['vectors'][3] = numpy.array([[1, 1, 1],
                                      [1, 0, 1],
                                      [1, 1, 0]])
    # Left face
    data['vectors'][4] = numpy.array([[0, 0, 0],
                                      [1, 0, 0],
                                      [1, 0, 1]])
    data['vectors'][5] = numpy.array([[0, 0, 0],
                                      [0, 0, 1],
                                      [1, 0, 1]])

    # Since the cube faces are from 0 to 1 we can move it to the middle by
    # substracting .5
    data['vectors'] -= .5

    # Generate 4 different meshes so we can rotate them later
    meshes = [mesh.Mesh(data.copy()) for _ in range(4)]

    # Rotate 90 degrees over the Y axis
    meshes[0].rotate([0.0, 0.5, 0.0], math.radians(90))

    # Translate 2 points over the X axis
    meshes[1].x += 2

    # Rotate 90 degrees over the X axis
    meshes[2].rotate([0.5, 0.0, 0.0], math.radians(90))
    # Translate 2 points over the X and Y points
    meshes[2].x += 2
    meshes[2].y += 2

    # Rotate 90 degrees over the X and Y axis
    meshes[3].rotate([0.5, 0.0, 0.0], math.radians(90))
    meshes[3].rotate([0.0, 0.5, 0.0], math.radians(90))
    # Translate 2 points over the Y axis
    meshes[3].y += 2

    # Optionally render the rotated cube faces
    from matplotlib import pyplot
    from mpl_toolkits import mplot3d

    # Create a new plot
    figure = pyplot.figure()
    axes = mplot3d.Axes3D(figure)

    # Render the cube faces
    for m in meshes:
        # import pdb
        # pdb.set_trace()
        axes.add_collection3d(mplot3d.art3d.Poly3DCollection(m.vectors))

    # Auto scale to the mesh size
    scale = numpy.concatenate([m.points for m in meshes]).flatten()
    axes.auto_scale_xyz(scale, scale, scale)

    # Show the plot to the screen
    pyplot.show()

def main():
    if sys.argv[1] == 'showdemo':
        run_show_demo()
        return
    elif sys.argv[1] == 'numpystl':
        filename = sys.argv[2]
        # 使用 numpy-stl 库
        run_numpy_stl_demo(filename)
    elif sys.argv[1] == 'local':
        filename = sys.argv[2]
        run_local(filename)
    elif sys.argv[1] == 'demo':
        filename = sys.argv[2]
        run_demo(files=[filename])
    elif sys.argv[1] == 'bitv1':
        filename = sys.argv[2]
        # size (1/2/4/8)
        length = int(sys.argv[3])
        # default is 1
        level = 10 - int(np.log2(length))
        run_bitstream_v1(filename, level)
    elif sys.argv[1] == 'bitv2':
        filename = sys.argv[2]
        # size (1/2/4/8)
        length = int(sys.argv[3])
        # default is 1
        level = 10 - int(np.log2(length))
        run_bitstream_v2(filename, level)

if __name__ == '__main__':
    main()


import json
import numpy as np
import math

map = [{"time":x/10.0,"velocity":1.0,"acceleration":0.0,
        "pose":{"translation":{"x":2*np.cos(x/10.0),"y":2*np.sin(x/10.0)},
        "rotation":{"radians":0.5}},"curvature":2.0} for x in range(0, 130, 1)]

def generatePartialCircle (initialAngle, finalAngle, radius, velocity, initialX, initialY):
   totalTime = (finalAngle - initialAngle) * radius / velocity
   rotationSpeed = (finalAngle - initialAngle) / totalTime
   theta = initialAngle - math.pi / 2
   xTranslation = initialX - radius * math.cos(theta)
   yTranslation = initialY - radius * math.sin(theta)
   circle = [{"time":t,"velocity":velocity,"acceleration":0.0,
        "pose":{"translation":rotateThenTranslate(theta, xTranslation, yTranslation, radius*np.cos(rotationSpeed * t + initialAngle), radius*np.sin(rotationSpeed * t + initialAngle)),
        "rotation":{"radians":rotationSpeed * t + initialAngle}},"curvature":1.0/radius} for t in np.arange(0, totalTime, 0.1)]
   return circle

def rotateThenTranslate(theta, xTranslation, yTranslation, x, y):
   newX = x * math.cos(theta) - y * math.sin(theta)
   newY = x * math.sin(theta) + y * math.cos(theta)
   newX = newX + xTranslation
   newY = newY + yTranslation
   return {"x": newX, "y": newY}

def accelerateLinearTrajectory(initialVelocity, finalVelocity, acceleration, initialX, initialY):
   totalTime = (finalVelocity - initialVelocity) / acceleration

   return [{"time":t,"velocity":initialVelocity + t*acceleration,"acceleration":acceleration,
        "pose":{"translation":{"x":((initialVelocity + t*acceleration)**2 - initialVelocity**2) / (2 * acceleration) + initialX, "y":initialY},
        "rotation":{"radians":math.atan2(initialY, initialX)}},"curvature":0} for t in np.arange(0, totalTime, 0.1)]

firstMove = accelerateLinearTrajectory(0, 2.0, 0.5, 0,0)
lastPoint = firstMove[-1]["pose"]["translation"]

circleMove = generatePartialCircle(0, 2* math.pi, 1.5, 2.0, lastPoint["x"], lastPoint["y"])
lastPoint = circleMove[-1]["pose"]["translation"]

finalMove = accelerateLinearTrajectory(2.0, 0.0, -0.5, lastPoint["x"], lastPoint["y"])

fullMove = firstMove + circleMove + finalMove
if(False):
        print(firstMove)
        print()
        print()
        print()
        print(circleMove)
else:
        print(json.dumps(fullMove))
        print()


# ###########DOESNT WORK!!!!############ #

import random
import pygame
from time import *

class Network:
    def __init__(self, entitys, layers, inputs, outputs, height):
        self.hynemans = [Hyneman(layers, inputs, outputs, height) for a in range(entitys)]
        self.gen = self.x = self.y = 0

    def draw(self):
        global screen

    def __str__(self):
        a = self.hynemans[0]
        # print(a.inputs)
        inputs = []
        g=False
        for i in range(len(a.inputs)):
            # inputs.append(str(int(a.inputs[i]*10)))
            # if i != len(a.inputs)-1:
            if i == 1:
                # print(inputs)
                inputs.append('+')
                # print(a.output)
                # g = inputs[-1] == '/'
                # continue
            inputs.append(str(int(a.inputs[i]*10)))
        best = ['{}'.format(a.output) for a in self.hynemans[0:5]]
        string = 'Best: {} = {}'.format(' '.join(inputs), ', '.join(best))
        # string = 'Best: {} = {}'.format(' '.join(inputs), (a.output if g or a.output == [] else round(a.output, 4)))

        return string

    def run_generation(self):
        self.gen += 1
        ranks = []
        self.x, self.y = [random.randint(1, 10)/10 for a in range(2)]
        x,y = self.x, self.y
        # x,y = [0,0]
        # sleep(1)
        for i in range(1, len(self.hynemans)):
            inputs = []
            self.hynemans[i].run_gen(x,y)
            a = self.hynemans[i]
            for j in range(len(a.inputs)):
                if j == 1:
                    inputs.append('+')
                inputs.append(str(int(a.inputs[j]*10)))
            m = ' '.join(inputs)
            # print(m)
            actual = eval(m)

            ranks.append((abs(self.hynemans[i].output-actual), self.hynemans[i]))

        ranks.sort()
        # print(ranks)
        # they are now ranked
        hynemans = len(ranks)
        ranks = ranks[:hynemans//4]

        # print(ranks)
        # print(len(ranks))
        ranks += [(1, Hyneman.get_mutate(a[1], self.gen)) for a in ranks]
        ranks += [(1, Hyneman.get_mutate(a[1], self.gen)) for a in ranks]
        ranks += [(1, Hyneman.get_mutate(ranks[a][1], self.gen)) for a in range(4)]
        # print(len(ranks))
        # print(ranks)
        ranks = [a[1] for a in ranks]

        self.hynemans = ranks

        # print(self)
        # run check and record index of failed hynemans

class Hyneman:
    def __init__(self, layers, inputs, outputs, height):
        ins = [InputNode() for a in range(inputs)]
        outs = [OutputNode() for a in range(outputs)]
        self.nodes = [ins] + [[Node() for b in range(height)] for a in range(layers-2)] + [outs]

        # ins = [[(random.random()*4)-2 for b in range(height)] for a in range(inputs)]
        # outs = [[(random.random()*4)-2 for b in range(outputs)] for a in range(height)]
        # self.synapses = [ins]+[[[(random.random()*4)-2 for i in range(height)] for j in range(height)] for b in range(layers-2)]+[outs]

        ins = [[0 for b in range(height)] for a in range(inputs)]
        outs = [[0 for b in range(outputs)] for a in range(height)]
        self.synapses = [ins]+[[[0 for i in range(height)] for j in range(height)] for b in range(layers-2)]+[outs]

        self.inputs = []
        self.output = []

    def __lt__(self, other):
        return (True, False)[random.randint(0, 1)]

    def run_gen(self, x=None, y=None):
        self.inputs = []
        if x and y or [x,y] == [0,0]:
            self.inputs = [x,y]
        self.output = []
        for i, layer in enumerate(self.nodes):
            for j, node in enumerate(layer):
                if i == 0 and not x and not y and [x,y] != [0,0]:
                    # if x and y:
                    #     self.nodes[i][j].value = self.inputs[j]
                    # else:
                    print('here ')
                    self.inputs.append(self.nodes[i][j].get_value(self, j))
                elif i == len(self.nodes)-1:
                    self.output = self.nodes[i][j].get_value(self, (i, j))
                else:
                    self.nodes[i][j].get_value(self, (i, j), (x/10,y/10))

    @staticmethod
    def get_mutate(hyneman, gen):
        h = Hyneman(0,0,0,0)
        h.nodes = hyneman.nodes
        h.synapses = hyneman.synapses

        for i in range(len(h.synapses)):
            for j in range(len(h.synapses[i])):
                # print(hyneman.synapses[i][j])
                for k in range(len(h.synapses[i][j])):
                    # h.synapses[i][j][k] += (random.randint(-1000, 1000)/10000)/((gen//1000)+1)
                    h.synapses[i][j][k] += (random.randint(-500, 500)/10000)
        return h

class Node:
    def __init__(self):
        self.value = 0

    def get_value(self, network, index, meh=None):
        val = 0
        for i, node in enumerate(network.nodes[index[0]-1]):
            x = network.synapses[index[0]-1]
            # if isinstance(node, InputNode) or node.value*x[i][index[1]] != 0:
                # print(node.value, node.__class__)
            # print(i, index, x, node)
            val += node.value*x[i][index[1]]
            # print('{}: {}'.format(i, node.value))
        # self.value = (1/(1+(1*(10**(-val)))))
        self.value = ((1/(1+(1*(10**(-val)))))-0.5)*2

        return self.value

class InputNode(Node):
    # pass
    def get_value(self, network, index, xy):
        # self.value = random.randint(0, 1)
        # self.value = random.randint(1, 10)/10
        self.value = xy[index[1]]
        # print(self.value)
        return self.value

class OutputNode(Node):
    def get_value(self, network, index):
        super().get_value(network, index)
        # print(self.value*2)
        return (self.value)*20

if __name__ == '__main__':
    n = Network(100, 6, 2, 1, 4)

    # screen = pygame.display.set_mode((1024, 768))
    x = 0
    while True:
        old_hynemans = n.hynemans
        n.run_generation()
        if x % 100 == 0:
            print('Generation', x, ': ', n)
        x += 1
        # n.draw(old_hynemans)
        # sleep(1)


import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('download (2).png')

# Converting to grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Applying threshold
ret, thresh = cv2.threshold(gray, 100, 255, cv2.THRESH_BINARY)

# Finding Contours
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Drawing Contours
img = cv2.drawContours(img, contours, -1, (0, 255, 0), 4)

plt.subplot(121), plt.imshow(gray)
plt.subplot(122), plt.imshow(img)
plt.show()

# Moments
cnt = contours[0]
M = cv2.moments(cnt)
print(M)

# Centroid
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])
print('Centroid = ', cx, ',', cy)

# Contour Area
area = cv2.contourArea(cnt)
print('Area = ', area)

# Contour perimeter
per = cv2.arcLength(cnt, True)
print('Cnt perimeter = ', per)

# BOUNDING SHAPES
image = cv2.imread('img_2.png')
gray2 = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret1, thresh2 = cv2.threshold(gray2, 100, 255, cv2.THRESH_BINARY)
cont, hier = cv2.findContours(thresh2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
image = cv2.drawContours(image, cont, -1, (0, 255, 0), 4)
image2 = image.copy()
image3 = image.copy()

plt.subplot(121), plt.imshow(gray2)
plt.subplot(122), plt.imshow(image)
plt.show()

# Straight Bounding Rectangle
cnt1 = cont[0]
x, y, w, h = cv2.boundingRect(cnt1)
image = cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 3)
cv2.imshow('Rectangle', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

# Rotated Bounding Rectangle
rect = cv2.minAreaRect(cnt1)
box = cv2.boxPoints(rect)
box = np.int0(box)
im = cv2.drawContours(image, [box], 0, (0, 0, 255), 3)
cv2.imshow('rotated rectangle', im)
cv2.waitKey(0)
cv2.destroyAllWindows()

# Minimum Enclosing Circle
(x0, y0), radius = cv2.minEnclosingCircle(cnt1)
center = (int(x0), int(y0))
radius = int(radius)
im2 = cv2.circle(image2, center, radius, (100, 100, 10), 3)
cv2.imshow('circle', im2)
cv2.waitKey(0)
cv2.destroyAllWindows()

# Fitting an Ellipse
ellipse = cv2.fitEllipse(cnt1)
im3 = cv2.ellipse(image2, ellipse, (100, 50, 150), 3)
cv2.imshow('ellipse', im3)
cv2.waitKey(0)
cv2.destroyAllWindows()

# CONTOURS PROPERTIES

# Aspect Ratio
# It is the ratio of width to height of bounding rectangle.
aspect_ratio = float(w) / h
print('Aspect Ratio = ', aspect_ratio)

# Extent
# Ratio of contour area to bounding rectangle area.
extent = float(area) / (w * h)
print('Extent = ', extent)

# Solidity
# Ratio of contour area to its convex hull area
hull = cv2.convexHull(cnt1)
hull_area = cv2.contourArea(hull)
solidity = float(area) / hull_area
print('Solidity = ', solidity)

# Equivalent Diameter
# Diameter of the circle whose area is same as the contour area.
equi_diameter = np.sqrt(4 * area / np.pi)
print('Equivalent Diameter = ', equi_diameter)

# Orientation
# The angle at which object is directed.
(x1, y1), (MA, ma), angle = cv2.fitEllipse(cnt1)
print('Orientation = ', angle)

# Extreme Points
leftmost = tuple(cnt1[cnt1[:, :, 0].argmin()][0])
rightmost = tuple(cnt1[cnt1[:, :, 0].argmax()][0])
topmost = tuple(cnt1[cnt1[:, :, 1].argmin()][0])
bottommost = tuple(cnt1[cnt1[:, :, 1].argmax()][0])
im4 = cv2.circle(image3, leftmost, 0, (0, 0, 255), 5)
im4 = cv2.circle(im4, rightmost, 0, (0, 0, 255), 5)
im4 = cv2.circle(im4, topmost, 0, (0, 0, 255), 5)
im4 = cv2.circle(im4, bottommost, 0, (0, 0, 255), 5)
cv2.imshow('points', im4)
cv2.waitKey(0)
cv2.destroyAllWindows()


# 实例022：比赛对手
# 题目 两个乒乓球队进行比赛，各出三人。甲队为a,b,c三人，乙队为x,y,z三人。已抽签决定比赛名单。有人向队员打听比赛的名单。
# a说他不和x比，c说他不和x,z比，请编程序找出三队赛手的名单。

if __name__ == '__main__':
    # 已对对战成员顺序固定，分别是x、y、z
    jia = ['a', 'b', 'c']
    yi = ['x', 'y', 'z']
    for e1 in jia:
        left1 = list(filter(lambda i: i != e1, jia))
        if e1 == 'a' or e1 == 'c':
            continue
        for e2 in left1:
            left2 = list(filter(lambda i: i != e2, left1))
            for e3 in left2:
                if e3 != 'c':
                    print('{0},{1},{2}'.format(e1, e2, e3))


class Solution:
    def isNumber(self, s):
        s = s.strip(" ")  # "1 "情况，去掉多于的空格
        if s == "":
            return False
        def isDigit(s):  # 是否是整数
            if s == "":
                return False
            for char in s:
                if char not in "0123456789":
                    return False
            return True
        def isDecimal(s): # 是否是小数
            pdot = s.find(".")
            if pdot == -1:
                return False
            before = isDigit(s[ :pdot])
            after = isDigit(s[pdot+1: ])
            ans = before and after or(before and s[pdot+1: ] == "") or (s[ :pdot] == "" and after)
            return ans
        def isSicentific(s):# 是否是科学计数法
            pE = s.find("e")
            if pE == -1:
                return False
            before = isDigit(s[ :pE]) or isDecimal(s[ :pE])  # 3.4e5，判断e前面的是否是小数或者整数
            after = s[pE+1:] != "" and \
                    ( isDigit(s[pE+1: ]) or
                     (s[pE+1] in "-+" and isDigit(s[pE+2: ])))# s[pE+1:] != ""是短路运算，如果3.5e这种情况，就不做后面运算了。s[pE + 2:]防止溢出
                                                              # 3.5e-5，判断e后面的是否为整数，或者是否为带符号的整数。
            return before and after

        ans = isDigit(s) or isDecimal(s) or isSicentific(s) or \
              s[0] in "+-" and (isDigit(s[1:]) or isDecimal(s[1:]) or isSicentific(s[1:])) # 无符号的十进制数或者有符号的十进制数
        return ans
print(Solution().isNumber("2e0"))

字符串/65. 有效数字.py


import sys
import yaml
import operator

NUM_SYM = u"<num>"
EOS_SYM = u"<eos>"
RARE_SYM = u"<rare>"
UNK_SYM = u"<unk>"
lstProgressSymbol = ['-', '\\', '|', '/']

def sortDictByValue(dInput, reverse=False):
	return sorted(dInput.items(), key=operator.itemgetter(1), reverse=reverse)

def printProgressSymbol(status):
    idx = status % len(lstProgressSymbol)
    sys.stdout.write("\r")
    sys.stdout.write(lstProgressSymbol[idx])
    sys.stdout.flush()

def printSomething(str):
	sys.stdout.write(str)
	sys.stdout.flush()

def loadModelConfig(path2config):
	config = {}
	with open(path2config) as fin:
		config = yaml.load(fin)
	return config


"""
Puede cambiar los valores de las variables definidas en una clase
para diferentes instancias(objetos) de esta clase.
"""
print("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.")
class MyClass:
    variable1 = 45
    variable2 = 180

    def foo(self):
        print("Hello from function foo")

my_object = MyClass()
my_object1 = MyClass()

my_object.variable2 = 3

print(my_object.variable2)
print(my_object1.variable2)

my_object.foo()

print(my_object.variable1)

print("-----------------------------------------------------------------------")

class MiClase:
    numero1 = 5
    numero2 = 10

    def impresion(self):
        for i in range(2):
            print("hola")

miclase1 = MiClase()
print(str(miclase1.numero1) + "----" + str(miclase1.numero2))
miclase1.impresion()

miclase2 = MiClase()
miclase2.numero1 = 4
miclase2.numero2 = 8
print(str(miclase2.numero1) + "----" + str(miclase2.numero2))
miclase2.impresion()

print("::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.")


#!/usr/bin/env python
import tkinter as tk
import tkinter.ttk as ttk

from dbmanager import DBM
from delivery_frame import DeliveryFrame
from pallet_frame import PalletFrame
from production_frame import ProductionFrame

class Root(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.status = StatusBar(self)
        self.status.pack(side='bottom', fill='x')

        self.appFrame = Application(self)
        self.appFrame.pack(side='top', fill='both', expand='True')

class StatusBar(ttk.Frame):
    def __init__(self, master):
        ttk.Frame.__init__(self, master)
        self.sep = ttk.Separator(self)
        self.sep.pack()
        self.label = ttk.Label(self, anchor='w')
        self.label.pack(fill='x')

    def set(self, format, *args):
        self.label.config(text=format % args)
        self.label.update_idletasks()

    def clear(self, *args):
        self.label.config(text="")
        self.label.update_idletasks()

class Application(ttk.Notebook):
    def __init__(self, root):
        ttk.Notebook.__init__(self, root)
        db = DBM()

        tab1 = PalletFrame(self, db, self.master.status)
        tab2 = ProductionFrame(self, db, self.master.status)
        tab3 = DeliveryFrame(self, db, self.master.status)

        self.add(tab1, text="Pallets")
        self.add(tab2, text="Production")
        self.add(tab3, text="Delivery")

        self.pack(side='top', fill='both', expand='yes')

        tab1.bind('<FocusIn>', tab1.status_bar.clear)
        tab2.bind('<FocusIn>', tab2.status_bar.clear)
        tab3.bind('<FocusIn>', tab3.status_bar.clear)

root = Root()
root.title("Production")
root.mainloop()


#!usr/bin/python
import time
import datetime
import operator
from dateutil.relativedelta import relativedelta

successList=[]
currentCIK=0
counter=0
percentComplete=0
startingLocation=0
endingLocation=0
DEF14CIK=0
compare10K=[]
compareDEF14=[]
numberOfMatches=0
# 10KCIK=0

inListFor10K=open("10KTemp.txt", "r")
inListForDEF14=open("DEF14Temp.txt", "r")

for line in inListFor10K:
    line=line.replace("\n", " ")
    line=line.strip()
    compare10K.append(line)

for line in inListForDEF14:
    line=line.replace("\n", " ")
    line=line.strip()
    compareDEF14.append(line)

print(str(len(compare10K)))
print(str(len(compareDEF14)))
# time.sleep(5)
totalChecks= len(compareDEF14)
# sixMonths=datetime.timedelta(months = 6)

#For all of the lines in the def 14, extract the filing date and submit it into the datetime object
#Take note of the current CIK number for comparison later. Also take note of the starting location of the CIK chunk so it can be sent back to that point.
#Create a counter for the number of lines in the file, so the speed can be O(n). Each time a line is searched in the inner loop, update the counter
#For all of the lines after and including the current number, check to see if the CIK number is the same as the outer loop. If it isn't, then end the that loop.
#Once that loop is ended, check the CIK to see if its still the same as the last one. If it is, then you want to go back to the start of that CIK, and check all of them again.
#If it's a different CIK, then continue the search through the list, updating the start point for return trips.

currentFilingDate=datetime.date(1,1,1)
for j in range(len(compareDEF14)):
    currentFilingDate=datetime.date(1,1,1)

    splitCompareDEF14=compareDEF14[j].split(",")
    currentCIK=splitCompareDEF14[0]
    try:
        while int(currentCIK) > int(compare10K[startingLocation].split(",")[0]):
            startingLocation=startingLocation+1
            endingLocation=startingLocation
            currentFilingDate=datetime.date(1,1,1)

    except IndexError as e:
        pass
    filingDateDEF14=splitCompareDEF14[7].split("-")
    dateDEF14=datetime.date(int(filingDateDEF14[0]),int(filingDateDEF14[1]),int(filingDateDEF14[2]))
    if int(currentCIK) == int(compare10K[startingLocation].split(",")[0]):
        try:
            for i in range (len(compare10K)):
                splitCompare10K=compare10K[startingLocation+i].split(",")
                if splitCompareDEF14[0] == splitCompare10K[0]:
                    #do everything that will be done in normal running of the loop
                    filingDate10K=splitCompare10K[7].split("-")
                    date10K=datetime.date(int(filingDate10K[0]),int(filingDate10K[1]),int(filingDate10K[2]))
                    if (currentFilingDate <= date10K)  and (date10K <= dateDEF14):
                        currentFilingDate=date10K
                        if splitCompareDEF14[5] == splitCompare10K[5]:
                            splitCompareDEF14[2]=splitCompare10K[2]
                            endingLocation=startingLocation+i
                            numberOfMatches=numberOfMatches+1
                            break
                        #if it is the first date that is smaller than the DEF14, it will be its corresponding 10K
                else:
                    endingLocation=startingLocation+i
                    #exit from the loop
                    break
                endingLocation=endingLocation+1
        except IndexError as e:
            break
    counter=counter+1
    percentComplete=(counter/totalChecks) *100
    print(str(percentComplete) + "% complete")
    successList.append(splitCompareDEF14[0] + "," + splitCompareDEF14[1] + "," + splitCompareDEF14[2] + "," + splitCompareDEF14[3] + "," + splitCompareDEF14[4] + "," + splitCompareDEF14[5] + "," + splitCompareDEF14[6] + "," + splitCompareDEF14[7])

print("Number of Matches:" + str(numberOfMatches))
successListOut=open("stataFinal.txt","w+")
for line in successList:
    successListOut.write(line + "\n")
successListOut.close()


# -*- coding: utf-8 -*-
"""
Created on Sat Aug  3 21:57:13 2019

@author: Dominic
"""

from math import exp
import numpy as np
from ..finutils.FinHelperFunctions import normaliseWeights
from ..models.FinGaussianCopula1FModel import lossDbnHeterogeneousAdjBinomial

class FinPortfolioCreditDefaultMode(object):

    def __init__(self,
                 weights):

        self._numCredits = len(weights)
        self._weights = weights

###############################################################################

    def lossDistribution(self,
                         tmat,
                         hazardRates,
                         recoveryRates,
                         betaValues,
                         numPoints):

        if tmat < 0.0:
            raise ValueError("Maturity must be positive")

        if len(hazardRates) != self._numCredits:
            raise ValueError("Hazard rates dop not have " /
                             + str(self._numCredits) + "elements.")

        if len(recoveryRates) != self._numCredits:
            raise ValueError("Recovery rates dop not have " /
                             + str(self._numCredits) + "elements.")

        if len(betaValues) != self._numCredits:
            raise ValueError("Beta values do not have " /
                             + str(self._numCredits) + "elements.")

        if numPoints < 1:
            raise ValueError("Num points must be > 0")

        self._hazardRates = hazardRates
        self._recoveryRates = recoveryRates
        self._betaValues = betaValues

        weights = normaliseWeights(self._weights)
        defaultProbs = np.zeros(self._numCredits)

        for j in range(0, self._numCredits):
            defaultProbs[j] = 1.0 - exp(-hazardRates[j] * tmat)

        totalLoss = 0.0
        for i in range(0, self._numCredits):
            totalLoss = totalLoss + weights[i] * (1.0 - recoveryRates[i])
        avgLoss = totalLoss / self._numCredits

        lossRatio = np.zeros(self._numCredits)
        for i in range(0, self._numCredits):
            lossRatio[i] = weights[i] * (1.0 - recoveryRates[i]) / avgLoss

        self._support = np.linspace(0.0, totalLoss, self._numCredits+1)
        self._lossDbn = lossDbnHeterogeneousAdjBinomial(self._numCredits,
                                                        defaultProbs,
                                                        lossRatio,
                                                        betaValues,
                                                        numPoints)

        return (self._support, self._lossDbn)

###############################################################################


##
# This module requires lib: https://darkcode0x00.com/download
# Current source: https://github.com/darkcode357/thg-framework
##
from lib.thg.core.BaseXmodeClass.BaseMod import BaseMod
from lib.thg.core.BaseXmodeClass.BaseOption import BaseOption
import requests
from lib.thg.core.auxiliary.Web import Url

class Exploit(BaseMod):
    def __init__(self):
        super(Exploit, self).__init__()
        self.update_info(
            {
                "name": "Telegram Message Client",
                "description": """ This module will send a Telegram message to given chat ID with the
            given bot token. Please refer to the module documentation for info
            on how to retrieve the bot token and corresponding chat ID values.""",
                "author": ["darkcode0x00"],
                "references": [
                    "telegram api",
                ],
                "disclosure_date": "2020, 9, 5",
                "service_name": "torch",
                "service_version": "telegram send bot msg 0.1",
            }
        )
        self.register_options(
            [
                BaseOption(
                    name="BOT_TOKEN",
                    required=True,
                    description="Telegram BOT token",
                    value="",
                ),
                BaseOption(
                    name="CHAT_ID",
                    required=True,
                    description="Chat ID for the BOT",
                    value="",
                ),
                BaseOption(
                    name="MSG", required=True, description="Message content", value=""
                ),
            ]
        )

    def check(self):
        url_check = "https://api.telegram.org"
        if Url(url_check).check_url_open()[:3] == str(200):
            print("url ok")
        else:
            print(Url(url_check).check_url_open())

    def exploit(self):
        token = self.options.get_option("BOT_TOKEN")
        Chat_id = self.options.get_option("CHAT_ID")
        MSG = self.options.get_option("MSG")
        print(MSG)
        url = f"https://api.telegram.org/bot{token}/sendMessage"
        data = {"chat_id": f"{Chat_id}", "text": f"{MSG}"}
        requests.post(url, data).json()
        print(f"mensagem envida =>[{MSG}]")

"""

    register_options(
      [

      ], self.class
    )
  end

  def message
    datastore['MSG']
  end

  def formatting
    datastore['FORMATTING']
  end

  def bot_token
    datastore['BOT_TOKEN']
  end

  def run
    params = { chat_id: datastore['CHAT_ID'], parse_mode: formatting, text: message }
    uri.query = URI.encode_www_form(params)
    res = Net::HTTP.get_response(uri)

    if res.is_a?(Net::HTTPSuccess)
      print_good('Message sent!')
    else
      print_error('Unable to send the message!')
      print_error("API Status: #{res.code}")
    end
  end
end
"""


listaA = [
    ['P1', 13],
    ['P2', 6],
    ['P3', 7],
    ['P4', 50],
    ['P5', 2],
    ['P6', 200],
]
# sort na lista da lista......
print(sorted(listaA,key=lambda i: i[0], reverse=True))
print(listaA)


'''

Wraps HTML
 and <h_> tags around paragraphs in .txt files.

'''

with open('output.html', 'w') as clear:
  clear.write('')

with open('output.html', 'a') as html:
  with open('input.txt') as txt:
    for line in txt:
      line = line.replace('\n','')
                             # Place h1 headings in this list
      if line.replace('\n','') in ['']:
        html.write(f'
{line}
\n')
                               # Place h2 headings in this list
      elif line.replace('\n','') in ['']:
        html.write(f'
{line}
\n')
                               # Place h3 headings in this list
      elif line.replace('\n','') in ['']:
        html.write(f'
{line}
\n')

      # Append heading conditions at will

      elif line != '' and line != '\n':
        html.write(f'
{line}
\n')

with open('output.html', 'rb+') as trunc:
    trunc.seek(-1, os.SEEK_END)
    trunc.truncate()