import os
import sys
import time
import re
import utility
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager

class PHAB():

    def __init__(self, id, ssh_client):
        chrome_options = Options()
        chrome_options.add_argument('--headless')
        chrome_options.add_argument('--no-sandbox')
        chrome_options.add_argument('--disable-gpu')
        chrome_options.add_argument('--window-size=1280x1024')
        chrome_options.add_argument('--disable-dev-shm-usage')
        chrome_service = Service(ChromeDriverManager().install())
        self.driver = webdriver.Chrome(service=chrome_service, options=chrome_options)
        self.ssh_client = ssh_client
        self.phab_url = r"https://phab.corp.fortinet.com/"
        self.task_id = id
        self.task_title = ""
        self.task_url = ""
        self.diff_id = ""
        self.diff_url = ""
        self.diff_folder = ""

    def phab_cs_log(self, text, type="INFO"):
        utility.cs_log(text, type)

    def open_site(self, url):
        self.phab_cs_log("Opening Task URL: " + url + '\n')
        self.task_url = url
        self.driver.get(url)

    def close_driver(self):
        self.driver.quit()

    def login(self, user, password):
        self.driver.find_element(By.ID, 'UQ0_0').send_keys(user)
        self.driver.find_element(By.ID, 'UQ0_1').send_keys(password)
        self.driver.find_element(By.NAME, "__submit__").click()

    def create_url_shortcut(self, task_folder_path):
        title_element = self.driver.find_elements(By.CLASS_NAME, "phui-header-header")
        title = title_element[0].text
        title = re.sub('[^0-9a-zA-Z]+', ' ', title).lstrip()
        self.task_title = title
        self.phab_cs_log("Creating Task Shortcut for: " + self.task_id + " " + title + ".url\n")
        elements = self.driver.find_elements(By.CLASS_NAME, "phui-property-list-properties")[0]
        labels = elements.text.split('\n')
        for i in range(0, len(labels)):
            if "Mantis" in labels[i]:
                self.mantis_id = labels[i + 1]

        if os.name != 'nt':
            win_sep = r"\A".replace('A', '')
            link_path = task_folder_path + win_sep + self.task_id + " " + title + ".url"
            cmd1 = "echo " + "[InternetShortcut]>" + '"' + link_path + '"'
            cmd2 = "echo URL=" + self.task_url + ">>" + '"' + link_path + '"'
            cmd3 = "echo F|xcopy " + '"' + link_path + '" "' + link_path.replace('.url', '_.url') + '"'
            cmd4 = "del /q " + '"' + link_path + '"'
            self.ssh_client.exec_cmd(cmd1)
            self.ssh_client.exec_cmd(cmd2)
            self.ssh_client.exec_cmd(cmd3)
            self.ssh_client.exec_cmd(cmd4)
        else:
            f = open(task_folder_path + os.sep + self.task_id + " " + title + ".url", "w+")
            f.truncate(0)
            f.write("[InternetShortcut]\nURL=" + self.task_url)
            f.flush()
            f.close()

    def update_checklist(self, check_list_temp_path, task_folder_path):
        if os.name != 'nt':
            win_sep = r"\A".replace('A', '')
            check_list_path = task_folder_path + win_sep + self.task_id + win_sep + "Checklist_" + self.task_id + ".txt"
            result = self.ssh_client.exec_cmd("if exist " + '"' + check_list_path + '"' + " (echo YES) else (echo NO)")
            if "NO" in result:
                f = open(os.getcwd() + os.sep + "templates" + os.sep + "Checklist_T.txt", "r+")
                txt = f.read()
                f.close()
                start_index = txt.find('Mantis ID:')
                end_index = txt.find('\n', start_index)
                txt = txt.replace(txt[start_index:end_index], 'Mantis ID: ' + self.mantis_id)
                start_index = txt.find('Bug Description:')
                end_index = txt.find('\n', start_index)
                txt = txt.replace(txt[start_index:end_index], 'Bug Description: ' + self.task_title)
                for line in txt.split('\n'):
                    line = line.replace('\n', '')
                    if len(line) < 1:
                        cmd = "echo.>>" + '"' + task_folder_path + win_sep + self.task_id + win_sep + "Checklist_" + self.task_id + ".txt" + '"' + '\n'
                    else:
                        cmd = "echo " + line.replace('<', '^<') + ">>" + '"' + task_folder_path + win_sep + self.task_id + win_sep + "Checklist_" + self.task_id + ".txt" + '"' + '\n'
                    self.ssh_client.exec_cmd(cmd)
        else:
            f = open(check_list_temp_path, 'r+')
            txt = f.read()
            f.close()
            start_index = txt.find('Mantis ID:')
            end_index = txt.find('\n', start_index)
            txt = txt.replace(txt[start_index:end_index], 'Mantis ID: ' + self.mantis_id)
            start_index = txt.find('Bug Description:')
            end_index = txt.find('\n', start_index)
            txt = txt.replace(txt[start_index:end_index], 'Bug Description: ' + self.task_title)
            f = open(check_list_temp_path, 'w+')
            f.truncate(0)
            f.write(txt)
            f.flush()
            f.close()

    def get_diff_id(self):
        self.phab_cs_log("Getting DIFF...\n")
        diff_xpath = '//*[@id="phabricator-standard-page-body"]/div[2]/div/div[2]/div/div[2]/div[1]/div[2]/div[1]/div/dl/dd[1]/span/a'
        diff_element = self.driver.find_elements(By.XPATH, diff_xpath)
        if len(diff_element) == 0:
            self.phab_cs_log("DIFF not created...EXIT\n")
            self.close_driver()
            sys.exit(0)
        self.diff_id = diff_element[0].text.split(":")[0]
        self.diff_url = self.phab_url + self.diff_id
        self.phab_cs_log("DIFF: " + self.diff_id + ' ' + self.diff_url + '\n')
        self.driver.get(self.diff_url)

    def get_build_folder(self, image_path):
        elements = self.driver.find_elements(By.XPATH, "//*[contains(text(),'Build')]")
        build_folder_path = ""
        for item in reversed(elements):
            if "smb" in item.text:
                build_folder_path = item.text.split('\n')[-1].split(':')[-1]
                break
        if build_folder_path == "":
            self.phab_cs_log("Build Not Available\n")
            self.close_driver()
            sys.exit(0)

        if 'trunk' in build_folder_path:
            index = build_folder_path.find("trunk") + len("trunk")
            build_folder_path = build_folder_path[0:index + 1]

        diff = list(filter(None, build_folder_path.split('/')))[4]
        build_folder_path = '/'.join(build_folder_path.split('/')[0:7])
        self.phab_cs_log("Build: " + build_folder_path.replace('/', os.sep) + '\n')

        if os.name != 'nt':
            cmd1 = "echo " + "[InternetShortcut]>" + '"' + image_path + '\\' + "trunk_" + diff + ".url" + '"'
            cmd2 = "echo URL=file:" + build_folder_path + ">>" + '"' + image_path + '\\' + "trunk_" + diff + ".url" + '"'
            self.ssh_client.exec_cmd(cmd1)
            self.ssh_client.exec_cmd(cmd2)
        else:
            from win32com.client import Dispatch
            shell = Dispatch('WScript.Shell')
            shortcut = shell.CreateShortCut(image_path + os.sep + "trunk_" + diff + ".lnk")
            shortcut.Targetpath = build_folder_path.replace('/', os.sep)
            shortcut.save()

    def rename_folder(self, src):
        os.rename(src, src + ' - ' + self.task_title)


import tensorflow as tf
import time
import argparse
import sys
import os
from datetime import datetime
from model import FinetuneModel as fm
from dataGenerator import getInputs

# Basic model parameters as external flags.
FLAGS = None

def run_training(tf_list,skip_layer):
    with tf.Graph().as_default():
        images,labels=getInputs(tf_list,batch_size=FLAGS.batch_size,num_epochs=FLAGS.num_epochs,
                                shape=[227,227,3])
        fmodel=fm(x=images,keep_prob=FLAGS.keep_prob,num_classes=FLAGS.num_cls,skip_layer=skip_layer,weights_path=FLAGS.w_path)
        score,_=fmodel.inference()
        loss=fmodel.loss(labels=labels)
        tf.summary.scalar('loss', loss)
        train_op=fmodel.training(learning_rate=FLAGS.l_rate)
        accuracy=fmodel.accuracy(labels=labels)
        tf.summary.scalar('acc',accuracy)
        merged_summary = tf.summary.merge_all()
        init_op=tf.group(tf.global_variables_initializer(),tf.local_variables_initializer())

        writer = tf.summary.FileWriter(FLAGS.fw_path)

        # Initialize an saver for store model checkpoints
        saver = tf.train.Saver()

        sess=tf.Session()
        sess.run(init_op)
        fmodel.load_initial_weights(sess=sess)
        # Start input enqueue threads.
        coord = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(sess=sess, coord=coord)

        step = 0
        try:
            while not coord.should_stop():
                start_time = time.time()
                if step%20==0:
                    s,_=sess.run([merged_summary,train_op])
                    writer.add_summary(s, step)
                    print("{} batch number: {}".format(datetime.now(), step))
                else:
                    sess.run(train_op)
                step+=1
                if step%175==0:
                    checkpoint_name=os.path.join(FLAGS.ckpt_path,'model.ckpt')
                    saver.save(sess=sess,save_path=checkpoint_name)
        except tf.errors.OutOfRangeError:
            print('Done training for %d epochs, %d steps.' % (FLAGS.num_epochs, step))
        finally:
            # When done, ask the threads to stop.
            coord.request_stop()
            # Wait for threads to finish.
        coord.join(threads)
        sess.close()

def tflist(path):
    tf_list=[]
    for parent, _, filenames in os.walk(path):
        for name in filenames:
            if os.path.splitext(name)[1] != '.tfrecords':
                continue
            tf_list.append(os.path.join(parent,name))

    return tf_list

def main(_):
    train_layer=['fc8','laten','fc7']
    tf_list=tflist(FLAGS.tf_path)
    run_training(tf_list, train_layer)
    # try:
    #     tfrecords_idx=open(FLAGS.tfrecords_idx,'r')
    #     lines=tfrecords_idx.readlines()
    #     tf_list=[]
    #     for line in lines:
    #         tf_list.append(line.strip())
    #     run_training(tf_list,skip_layer)
    #
    # except IOError as err:
    #     print("FileError:"+str(err))

if __name__ == '__main__':
  parser = argparse.ArgumentParser()
  parser.add_argument(
      'num_cls',
      type=int,
      default=2,
      help='Number of classes.'
  )
  parser.add_argument(
      'tf_path',
      type=str,
      default='/tmp/data/tf.idx',
      help='Directory with the tfrecords file dir.'
  )
  parser.add_argument(
      'w_path',
      type=str,
      default='/tmp/data/bvlc_alexnet.npy',
      help='caffe bvlc_alexnet.npy path'
  )
  parser.add_argument(
      '--l_rate',
      type=float,
      default=0.01,
      help='Initial learning rate.'
  )
  parser.add_argument(
      '--num_epochs',
      type=int,
      default=10,
      help='Number of epochs to run trainer.'
  )
  parser.add_argument(
      '--keep_prob',
      type=float,
      default=0.5,
      help='Number of dropout rate.'
  )

  parser.add_argument(
      '--batch_size',
      type=int,
      default=100,
      help='Batch size.'
  )
  parser.add_argument(
      'fw_path',
      type=str,
      help='path to tensorboard savedir'
  )
  parser.add_argument(
      'ckpt_path',
      type=str,
      help='path to chekpoint savedir'
  )
  FLAGS, unparsed = parser.parse_known_args()
  tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)


#jackalopeTest

jackalopes = [0,0]
years = 0
while len(jackalopes) < 1000:
    viable = []
    i = len(jackalopes)-1
    while i >= 0:
        if jackalopes[i] > 9:
            jackalopes.remove(jackalopes[i])
        else:
            jackalopes[i] += 1
        i-=1
    years += 1
    for age in jackalopes:
        if age >= 4 and age <= 8:
            viable.append(age)
    for jackalope in viable:
        jackalopes.append(0)

print(f"It will take {years} years to create a population of 1,000 jackalopes.")


import aoc

input = [x.split(" ") for x in aoc.input(2, 2022).splitlines()]

win = {"A": "Y", "B": "Z", "C": "X"}
lose = {"A": "Z", "B": "X", "C": "Y"}

scoring = {}
scoring["A"] = scoring["X"] = 1
scoring["B"] = scoring["Y"] = 2
scoring["C"] = scoring["Z"] = 3

@aoc.bench
def part1():
    score = 0

    for them, me in input:
        if win[them] == me:
            score += scoring[me] + 6
        elif lose[them] == me:
            score += scoring[me]
        else:
            score += scoring[me] + 3

    print(score)

@aoc.bench
def part2():
    score = 0

    for them, outcome in input:
        if outcome == "X":
            score += scoring[lose[them]]
        elif outcome == "Z":
            score += scoring[win[them]] + 6
        else:
            score += scoring[them] + 3

    print(score)

part1()
part2()


from ..component_utils import dateformat, get_description
from ..ProcesE1 import ProcesE1

class E101(ProcesE1.ProcesE1):
    def __init__(self):
        ProcesE1.ProcesE1.__init__(self)

    def step_name(self):
        return '01'

    def get_data(self, wiz, cursor, uid, step):
        result = ProcesE1.ProcesE1.get_data(self, wiz, cursor, uid, step)
        result['type'] = 'E101'
        result['tipus_solicitud'] = get_description(step.tipus_sollicitud, "TABLA_122")
        result['codi_subjacent'] = step.atr_subjacent.codi_sollicitud
        result['data_subjacent'] = dateformat(step.atr_subjacent.data_sollicitud)
        start_date = self.get_log_date(wiz, cursor, uid, step)
        if start_date:
            result['day'] = dateformat(start_date)
            result['date'] = start_date
        return result


from urllib.request import urlopen

import os
import time
import math
import datetime
import random
from bs4 import BeautifulSoup
from requests.exceptions import ConnectionError
from urllib3.exceptions import MaxRetryError, NewConnectionError
from selenium.common.exceptions import WebDriverException, TimeoutException
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

'''
TODO
1. Przepisać wpisywanie dat i filtrów na dodanie do linka
2. Zrobić konwertowanie walut (dolar i euro) - usunąć proxy z poza europy i stanów
'''

def check_booking(city:str, people:dict, dates:tuple, out_file:str, counter=5):
    """
    Parameters
    ----------
    city : str
        City for which is searching
    people : dict
        Dictionary containing number of adults, children and age of each child
    dates : tuple
        Datetime objects of starting and ending date
    out_file : str
        Name of file to which results will be saved

    Check for offers on booking.com
    """

    if counter <= 0:
        return

    url = generateUrl(city, people, dates)
    proxy = chooseProxy()
    options = webdriver.ChromeOptions()
    # options.add_argument(f'--proxy-server={proxy}')
    # options.add_argument('--headless')
    try:
        with webdriver.Chrome(executable_path='/home/kamil/Desktop/Wakacje/files/chromedriver', options=options) as browser:
            browser.get(url)
            WebDriverWait(browser, 45).until(
                EC.presence_of_element_located((By.XPATH, '/html/body'))
            )
            # couldn't load with given IP, proxy error
            if 'ERR_' in browser.page_source:
                print(f'Page couldn\'t load with IP {proxy}')
                check_booking(city, people, dates, out_file, counter=(counter - 1))
                return
            soup = BeautifulSoup(browser.page_source, features='html.parser')
            # couldn't find city
            if city[0].lower() not in str(soup.title).lower():
                print(f'Couldn\'t find {city[0]}')
                return
            links = getSearchLinks(soup, url)

    except TimeoutException:
        print(f'Too long waiting time for {city[0]}, IP {proxy}')
        check_booking(city, people, dates, out_file, counter=(counter - 1))
        return
    except WebDriverException:
        # no element on page
        print('IP ' + proxy + ', WebDriverException')
        check_booking(city, people, dates, out_file, counter=(counter - 1))
        return
    except (ConnectionError, MaxRetryError, NewConnectionError):
        print(f'Too many requests for {city[0]}, IP {proxy}')
        check_booking(city, people, dates, out_file, counter=(counter - 1))
        return
    else:
        for link in links:
            time.sleep(random.randint(2, 5))
            save(city, dates, link, out_file)
        print(f'Found {len(links)} for {city[0]} on {proxy}')

def generateUrl(city, people, dates):
    """
    Parameters
    ----------
    city : str
        City for which is searching
    people : dict
        Dictionary containing number of adults, children and age of each child
    dates : tuple
        Datetime objects of starting and ending date

    Generates search url for booking.com with given data
    """

    # basic url
    url = 'https://www.booking.com/searchresults.pl.html?'
    # city name
    url += f'ss={city[0]}'
    # start date
    url += f'&checkin_year={dates[0].year}'
    url += f'&checkin_month={dates[0].month}'
    url += f'&checkin_monthday={dates[0].day}'
    # end date
    url += f'&checkout_year={dates[1].year}'
    url += f'&checkout_month={dates[1].month}'
    url += f'&checkout_monthday={dates[1].day}'
    # people
    url += f'&group_adults={people.get("adults", 0)}'
    url += f'&group_children={people.get("children", 0)}'
    for age in people.get('ages', []):
        url += f'&age={age}'
    # url += f'&no_rooms={}'
    # show only avaliable
    url += '&nflt=oos%3D1%3B'
    return url

# def getSearchLinks(browser, url, secondary=False):
#     # dodać &offset=25 do linku
#     """
#     Return the result links from webpage

#     Parameters
#     ----------
#     browser : webdriver.Chrome
#         The browser used to connect and scrap webpage
#     url : str
#         A link of search page
#     secondary : bool
#         Specifies if its the first page of search (False), or one of the next (True)
#     """

#     browser.get(url)
#     time.sleep(5)
#     soup = BeautifulSoup(browser.page_source, features='html.parser')
#     links = set()
#     results = soup.select('#hotellist_inner>div')
#     for div in results:
#         if div.get('class') and 'sr_separator_first' in div.get('class'):
#             return links
#         link = div.select_one('div a')
#         if link:
#             links.add('https://www.booking.com' + link.get('href'))

#     if secondary:
#         return links

#     number_of_results_h1 = soup.select_one('.sr_header h1')
#     if number_of_results_h1 is not None:
#         number_of_results = int(''.join(i for i in number_of_results_h1.text if i.isdigit()))
#         for i in range(math.floor(number_of_results/25)):
#             links = links | getSearchLinks(browser, url + f'&offset={25 * (i+1)}', True)

#     return links

# def save(city, dates, url, results_file, counter=3):
#     """
#     Open given url, extract data and save to file.

#     Parameters
#     ----------
#     city : str
#         Name of city for search
#     dates : tuple
#         A pair of `datetime` objects, one for starting and one for ending date
#     url : str
#         Link to page of hotel
#     results_file : str
#         Name of the file for saving
#     """

#     if counter <= 0:
#         return

#     if not os.path.exists(results_file):
#         with open(results_file, 'w+') as f:
#             f.write('MIEJSCOWOŚĆ \t WIELKOŚĆ \t ODLEGŁOŚĆ DO MORZA \t NAZWA \t DATA \t CENA ZA CAŁOŚĆ \t CENA ZA DZIEŃ \t NR TELEFONU \t LINK \n')

#     proxy = chooseProxy()
#     options = webdriver.ChromeOptions()
#     options.add_argument(f'--proxy-server={proxy}')
#     # options.add_argument('--headless')
#     # options.add_argument('--ignore-certificate-errors')

#     try:
#         with webdriver.Chrome(executable_path='/home/kamil/Desktop/Wakacje/files/chromedriver', options=options) as browser:
#             browser.get(url)
#             WebDriverWait(browser, 45).until(EC.presence_of_element_located((By.XPATH, '/html/body/div')))
#             if 'ERR_' in browser.page_source:
#                 # couldnt load with given IP, proxy error
#                 print(f'Page couldn\'t load with IP {proxy}')
#                 save(city, dates, url, results_file, counter=(counter - 1))
#                 return
#             soup = BeautifulSoup(browser.page_source, features='html.parser')
#             with open('soup.html', 'w+') as f:
#                 f.write(str(soup))

#     except (WebDriverException, ConnectionError, MaxRetryError, NewConnectionError):
#         save(city, dates, url, results_file, counter=(counter - 1))
#         return

#     else:
#         days = (dates[1] - dates[0]).days
#         price_for_all = soup.select('.totalPrice .bui-price-display__value.prco-text-nowrap-helper.prco-inline-block-maker-helper')
#         if price_for_all is not None and len(price_for_all) > 0:
#             price_for_all = price_for_all[0].text
#             multiplier = {
#                 '€': 4.40,
#                 '$': 3.70,
#                 'zł': 1.00,
#                 '': 0.00
#             }
#             for currency in multiplier:
#                 if currency in price_for_all:
#                     value_multiplier = multiplier.get(currency)
#                     break
#             price_for_all = float(''.join(i for i in price_for_all if i.isdigit() or i == '.')) * value_multiplier
#             price_for_day = price_for_all / days
#         else:
#             price_for_all = 0.00
#             price_for_day = 0.00

#         place_name = soup.select_one('#hp_hotel_name')
#         if place_name is not None:
#             place_name = place_name.text.splitlines()[2].replace('\n', '')

#         with open(results_file, 'a+') as f:
#             f.write('%s \t %d \t %.2f km \t %s \t %s \t %.2f zł \t %.2f zł \t %s \t %s \n' % (
#                 city[0],
#                 city[2],
#                 city[1],
#                 str(place_name),
#                 dates[0].strftime('%d.%m') + ' - ' + dates[1].strftime('%d.%m'),
#                 price_for_all,
#                 price_for_day,
#                 '---',
#                 url
#             ))

def chooseProxy():
    """
    Choose a proxy IP address, at random from two groups.
    Group `proxysBest` have adresses with 100% avaliability
    and response times below 20s. Group `proxysGood` have
    avaliability above 75%, but worse response times (sometimes
    up to one minute). The group is chosen with 75-25 chance, and
    inside the grouo address is chosen with uniform probability.
    """

    proxysBest = [
        '80.187.140.74:8080',   #8/8        6s
        '18.159.45.67:3128',    #8/8        15s
        '199.217.116.5:5836',   #5/5        17s
        '173.249.30.74:8080',   #5/5        7s
        '134.122.93.160:3128',  #5/5        8s
        '195.154.233.185:5836', #5/5        14s
        '95.217.120.170:8888',  #5/5        7s
        '148.251.153.226:3128', #5/5        19s
    ]
    proxysGood = [
        '91.52.26.73:8080',     #6/8
        '51.161.62.117:8080',   #5/5
        '206.198.131.172:8080', #4/5
        '212.83.131.192:80',    #3/5
        '80.23.125.226:3128',   #5/5
        '80.109.201.225:3128',  #4/5
    ]
    if random.random() < 0.75:
        return random.choice(proxysBest)
    else:
        return random.choice(proxysGood)


"""
XML Codec (output only)

Output a resource structure as XML

XML has a unique attribute in the form of the text. This is plain text that can
be placed within a pair of tags.

To support this the XML codec includes a TextField, any TextField found on a
resource will be exported (if multiple are defined they will all be exported
into the one text block).

The TextField is for all intents and purposes just a StringField, other codecs
will export any value as a String.

"""
import datetime
from io import StringIO
from typing import TextIO
from xml.sax import saxutils

from odin import fields, serializers
from odin.fields import StringField, composite
from odin.utils import attribute_field_iter_items, element_field_iter_items, getmeta

XML_TYPES = {
    datetime.date: serializers.date_iso_format,
    datetime.time: serializers.time_iso_format,
    datetime.datetime: serializers.datetime_iso_format,
}

CONTENT_TYPE = "application/xml"

class TextField(StringField):
    """
    Special String field for representing XML text blocks.
    """

def _serialize_to_string(value):
    if value.__class__ in XML_TYPES:
        return XML_TYPES[value.__class__](value)
    else:
        return str(value)

def dump(
    fp: TextIO,
    resource,  # type: Resource
    line_ending: str = "",
):
    """
    Dump a resource to a file like object.
    :param fp: File pointer or file like object.
    :param resource: Resource to dump
    :param line_ending: End of line character to apply
    """
    meta = getmeta(resource)

    # Write container and any attributes
    attributes = "".join(
        f" {f.name}={saxutils.quoteattr(_serialize_to_string(v))}"  # Encode attributes
        for f, v in attribute_field_iter_items(resource)
    )
    fp.write(f"<{meta.name}{attributes}>{line_ending}")

    # Write any element fields
    for field, value in element_field_iter_items(resource):
        if isinstance(field, composite.ListOf):
            if field.use_container:
                fp.write(f"<{field.name}>{line_ending}")
            for v in value:
                dump(fp, v, line_ending)
            if field.use_container:
                fp.write(f"</{field.name}>{line_ending}")

        elif isinstance(field, composite.DictAs):
            if value is not None:
                dump(fp, value, line_ending)

        elif isinstance(field, fields.ArrayField):
            for v in value:
                fp.write(
                    f"<{field.name}>{_serialize_to_string(v)}</{field.name}>{line_ending}"
                )

        elif isinstance(field, TextField):
            if value is not None:
                fp.write(f"{saxutils.escape(_serialize_to_string(value))}{line_ending}")

        else:
            fp.write(
                f"<{field.name}>{saxutils.escape(_serialize_to_string(value))}</{field.name}>{line_ending}"
            )

    fp.write(f"</{meta.name}>{line_ending}")

def dumps(resource, **kwargs):
    """
    Dump a resource to a string.

    :param resource: Resource to dump
    """
    f = StringIO()
    dump(f, resource, **kwargs)
    return f.getvalue()


import random
import numpy as numpy
from functools import reduce

def sign(vals):
    return numpy.asarray(list(map(lambda val: -1 if val <= 0 else 1, vals)))

def classify(iteration, factor):
    counters = []
    data = numpy.loadtxt('data.txt')
    for i in range(iteration):
        if iteration > 1:
            data = numpy.asarray(sorted(data, key = lambda k: random.random()))
        w_0 = numpy.ones((data.shape[0], 1))
        X = numpy.concatenate((w_0, data[:, :-1]), axis = 1)
        Y = data[:, -1:]
        W = numpy.zeros((data.shape[1], 1))
        isAllCorrect = False
        counter = 0

        while not isAllCorrect:
            isAllCorrect = True
            for row, x in enumerate(X):
                if sign(numpy.dot(x, W)) * Y[row] < 0:
                    W = W + factor * (Y[row] * x)[numpy.newaxis].T
                    isAllCorrect = False
                    counter = counter + 1

        counters.append(counter)

    return round(reduce(lambda x, y: x + y, counters) / len(counters))

if __name__ == '__main__':
    print(classify(2000, 1))


import os
import sys
import xacro
import tempfile
import launch
from launch_ros.actions import Node
from launch.actions import ExecuteProcess, IncludeLaunchDescription
from launch.substitutions import LaunchConfiguration
from launch.launch_description_sources import PythonLaunchDescriptionSource
from ament_index_python.packages import get_package_share_directory

sys.path.append(os.path.dirname(os.path.realpath(__file__)))

PKG_THIS = get_package_share_directory("point_cloud_registration")
PKG_GAZEBO_ROS = get_package_share_directory("gazebo_ros")
SIMULATE_MODEL = "turtlebot3_burger.urdf.xacro"

def to_urdf(xacro_path, parameters=None):
    urdf_path = tempfile.mktemp(prefix="%s_" % os.path.basename(xacro_path))
    doc = xacro.process_file(xacro_path, mappings=parameters)
    out = xacro.open_output(urdf_path)
    out.write(doc.toprettyxml(indent="  "))
    return urdf_path

octomap_params = {
    "resolution": 0.15,
    "frame_id": "odom",
    "base_frame_id": "camera_depth_optical_frame",
    "height_map": True,
    "colored_map": True,
    "color_factor": 0.8,
    "filter_ground": False,
    "filter_speckles": False,
    "ground_filter/distance": 0.04,
    "ground_filter/angle": 0.15,
    "ground_filter/plane_distance": 0.07,
    "compress_map": True,
    "incremental_2D_projection": False,
    "sensor_model/max_range": -1.0,
    "sensor_model/hit": 0.7,
    "sensor_model/miss": 0.4,
    "sensor_model/min": 0.12,
    "sensor_model/max": 0.97,
    "color/r": 0.0,
    "color/g": 0.0,
    "color/b": 1.0,
    "color/a": 1.0,
    "color_free/r": 0.0,
    "color_free/g": 0.0,
    "color_free/b": 1.0,
    "color_free/a": 1.0,
    "publish_free_space": False,
}

def generate_launch_description():
    use_sim_time = LaunchConfiguration("use_sim_time", default="True")
    world = LaunchConfiguration("world", default="env3")

    rviz_config_dir = os.path.join(PKG_THIS, "rviz", "rviz.rviz")
    rviz_node = Node(
        name="rviz2",
        package="rviz2",
        executable="rviz2",
        output = "screen",
        arguments=["-d", rviz_config_dir],
        parameters=[{"use_sim_time": False}],
    )

    urdf = to_urdf(
        os.path.join(PKG_THIS, "urdf", SIMULATE_MODEL),
        { "use_nominal_extrinsics": "true", "add_plug": "true", "use_sim_time": use_sim_time },
    )
    robot_state_publisher = Node(
        name="robot_state_publisher",
        package="robot_state_publisher",
        executable="robot_state_publisher",
        namespace="",
        output="screen",
        arguments = [urdf],
    )

    gazebo_server = IncludeLaunchDescription(
        PythonLaunchDescriptionSource(os.path.join(PKG_GAZEBO_ROS, "launch", "gzserver.launch.py")),
        launch_arguments={ "world": [PKG_THIS, "/sdf/worlds/", world, "_world.sdf"] }.items(),
    )

    gazebo_client = IncludeLaunchDescription(
        PythonLaunchDescriptionSource(os.path.join(PKG_GAZEBO_ROS, "launch", "gzclient.launch.py")),
    )

    gazebo_sim_time = ExecuteProcess(
        cmd=["ros2", "param", "set", "/gazebo", "use_sim_time", use_sim_time],
        output="screen",
    )

    octomap_server_node = Node(
        package="octomap_server2",
        executable="octomap_server",
        output="screen",
        remappings=[("cloud_in", "/depth/color/points")],
        parameters=[octomap_params],
    )

    return launch.LaunchDescription([
        # rviz_node,
        robot_state_publisher,
        gazebo_server,
        gazebo_client,
        gazebo_sim_time,
        # octomap_server_node,
    ])


# !usr/bin/python
# -*- coding: utf-8 -*-
# __author__ = 'XueQinwen'

import os
import re
import math
import time
import shutil
import json
from biocluster.workflow import Workflow
from biocluster.api.file.lib.transfer import MultiFileTransfer
from biocluster.core.exceptions import OptionError

class VcfLddecayWorkflow(Workflow):
    def __init__(self, wsheet_object):
        self._sheet = wsheet_object
        super(VcfLddecayWorkflow, self).__init__(wsheet_object)
        options = [
            {"name": "vcf_file", "type": "infile", "format": "dna_gmap.vcf"},
            {"name": "group_file","type": "infile","format":"denovo_rna_v2.common"},
            {"name": "max_missing", "type": "float", "default": 30.0},  # 缺失率
            {"name": "maf", "type": "float", "default": 0.05},  # 次要等位基因频率min
            {"name": "main_id", "type": "string"},
            {"name": "update_info", "type": "string"}
        ]
        self.add_option(options)
        self.revise_infiles()
        self.set_options(self._sheet.options())
        # self.filter = self.add_tool("tool_lab.vcf_filter")
        # self.plink = self.add_tool("tool_lab.vcf_plink")
        self.lddecay = self.add_module('tool_lab.ld_analysis')

    def check_option(self):
        """
        参数检查
        """
        if not self.option("vcf_file"):
            raise OptionError("必须输入vcf文件")
        if not self.option("group_file"):
            raise OptionError("必须输入分组文件")
        if not self.option("max_missing"):
            raise OptionError("必须设置最大缺失率")
        if not self.option("maf"):
            raise OptionError("必须设置maf")

    # def run_filter(self):
    #     self.filter.set_options({
    #         'vcf_file':self.option("vcf_file"),
    #         'max_missing':self.option("max_missing"),
    #         "maf":self.option('maf')
    #     })
    #     self.filter.on('end',self.run_plink)
    #     self.filter.run()

    # def run_plink(self):
    #     self.filter_vcf = os.path.join(self.filter.output_dir,"pop.recode.vcf")
    #     self.plink.set_options({
    #         'vcf_file': self.filter_vcf,
    #     })
    #     self.plink.on('end',self.run_lddecay)
    #     self.plink.run()

    def run_lddecay(self):
        group_file = self.option("group_file").prop["path"]
        group_dict = {}
        with open(group_file,"r") as gf:
            while 1:
                line = gf.readline()
                if not line:
                    break
                fd = line.rstrip().split("\t")
                if group_dict.has_key(fd[1]):
                    group_dict[fd[1]] = group_dict[fd[1]] +","+fd[0]
                else:
                    group_dict[fd[1]] = fd[0]
        self.lddecay.set_options({
            'vcf_file':self.option("vcf_file"),
            'max_missing':str(self.option('max_missing')/100),
            "min_maf":str(self.option("maf")),
            "group_dict":json.dumps(group_dict)
        })
        self.lddecay.on('end',self.set_output)
        self.lddecay.run()

    def set_output(self):
        self.logger.info('strat set_output as {}'.format(
            self.__class__.__name__))
        decay_path = os.path.join(self.lddecay.output_dir,"ld_decay_dir")
        draw_path = os.path.join(self.lddecay.output_dir,"ld_draw_dir")
        try:
            shutil.copytree(decay_path,
                                os.path.join(self.output_dir, "ld_decay_dir"))
            shutil.copytree(draw_path,
                                os.path.join(self.output_dir, "ld_draw_dir"))
        except Exception as e:
            self.set_error("设置结果目录失败{}".format(e))
        self.set_db()

    def set_db(self):
        self.logger.info("开始导表")
        pictrue_path = self._sheet.output + "/ld_draw_dir/ld.pdf"
        self.logger.info(pictrue_path)
        api_vcf_lddecay = self.api.api("tool_lab.vcf_lddecay")
        api_vcf_lddecay.add_detail(self.option("main_id"),pictrue_path)
        api_vcf_lddecay.vcf_ld_detail(self.option("main_id"),os.path.join(self.lddecay.work_dir,"gro_list"))
        self.logger.info("导表结束")
        self.end()

    def run(self):
        self.run_lddecay()
        super(VcfLddecayWorkflow, self).run()

    def end(self):
        result_dir = self.add_upload_dir(self.output_dir)
        result_dir.add_relpath_rules([
            [".", "", "结果输出目录"],
        ])
        result_dir.add_regexp_rules([
            ["", "", ""]
        ])
        super(VcfLddecayWorkflow, self).end()

if __name__ == '__main__':
    from biocluster.wsheet import Sheet
    import random
    data = {
        'name': 'test_vcf_lddecay',
        'id': 'vcf_lddecay_' +  str(random.randint(1, 10000)),
        'type': 'workflow',
        'options': {
        "vcf_file": "/mnt/ilustre/users/sanger-dev/sg-users/xueqinwen/test_WGS/6.ld-decay/pop.recode.vcf",
        "group_file":"/mnt/ilustre/users/sanger-dev/sg-users/xueqinwen/test_WGS/6.ld-decay/group.list",
        "main_id" : "5e9e6a6017b2bf2049a81be2"
        }
    }
    wsheet = Sheet(data=data)
    wf = VcfLddecayWorkflow(wsheet)
    wf.run()


# http://e-maxx.ru/algo/mst_prim

# graph - adjacency matrix
def prim1(graph):
    V = len(graph)
    if V == 0:
        return 0

    # min cost to connect i-th vertex with already constructed tree
    # get 0-th vertex first
    mins = [float('inf')] * V
    mins[0] = 0

    result = 0

    for i in range(V):
        minJ = -1
        m = float('inf')
        for j in range(V):
            if 0 <= mins[j] < m:
                minJ = j
                m = mins[j]
        if minJ == -1:
            # not possible to build
            return -1

        result += m
        mins[minJ] = -1

        for j in range(V):
            if mins[j] > 0 and graph[j][minJ] < mins[j]:
                mins[j] = graph[j][minJ]

    return result

if __name__ == '__main__':
    assert 0 == prim1([])
    assert 5 == prim1([[0, 5], [5, 0]])
    assert 5 == prim1([[0, 2, 3], [2, 0, 4], [3, 4, 0]])


# Desarrollado por Brayan Baquero y Juliana Castillo
# Asignatura de Inteligencia Artificial
# Profesor : Manuel Alexander Cadena
# Universidad de Cundinamarca
# Ingenieria de Sistemas

import sys
def dijkstra_con_direccionalidad(grafo, origen):
    visitados = set()
    distancia = {nodo: sys.maxsize for nodo in grafo}
    distancia[origen] = 0
    ruta_mas_corta = {}
    while len(visitados) != len(grafo):
        nodo_actual = min((nodo for nodo in grafo if nodo not in visitados), key=lambda n: distancia[n])
        visitados.add(nodo_actual)

        for vecino, peso in grafo[nodo_actual].items():
            nueva_distancia = distancia[nodo_actual] + peso
            if nueva_distancia < distancia[vecino]:
                distancia[vecino] = nueva_distancia
                ruta_mas_corta[vecino] = nodo_actual
    return distancia, ruta_mas_corta
num_nodos = int(input("Ingrese el número de nodos: "))
grafo = {}
for i in range(num_nodos):
    valor_nodo = input(f"Ingrese el valor para el nodo {i}: ")
    grafo[valor_nodo] = {}
for nodo in grafo:
    num_aristas = int(input(f"Ingrese el número de aristas para el nodo {nodo}: "))
    for i in range(num_aristas):
        vecino = input(f"Ingrese el vecino para el nodo {nodo}: ")
        peso = int(input(f"Ingrese el peso para la arista {nodo} -> {vecino}: "))
        grafo[nodo][vecino] = peso
origen = input("Ingrese el nodo de origen: ")
distancia, ruta_mas_corta = dijkstra_con_direccionalidad(grafo, origen)
print("Distancias más cortas desde el nodo de origen:")
for nodo, dist in distancia.items():
    print(f"Nodo: {nodo}, Distancia: {dist}")
print("Ruta más corta hacia cada nodo:")
for nodo, ruta in ruta_mas_corta.items():
    print(f"Nodo: {nodo}, Ruta: {ruta} -> {nodo}")


import json
import functools
import os.path
import logging
import tempfile
import subprocess
import ftrack_api.session

logger = logging.getLogger('com.ftrack.recipes.make-non-encode-web-playable')

# Gathered from https://en.wikipedia.org/wiki/Video_file_format
ENCODING_SUPPORTED_EXTENSIONS_VIDEO = [
    '.3g2',
    '.3gp',
    '.asf',
    '.avi',
    '.drc',
    '.flv',
    '.m2v',
    '.m4p',
    '.m4v',
    '.m4v',
    '.mkv',
    '.mng',
    '.mov',
    '.mp2',
    '.mp4',
    '.mpe',
    '.mpeg',
    '.mpg',
    '.mpv',
    '.mxf',
    '.nsv',
    '.ogg',
    '.ogv',
    '.qt',
    '.rm',
    '.rmvb',
    '.roq',
    '.svi',
    '.vob',
    '.webm',
    '.wmv',
    '.yuv',
]

# change these to match full path to the exact executables.
ffmpeg_cmd = 'ffmpeg'
ffprobe_cmd = 'ffprobe'

def exec_cmd(cmd):
    '''execute the provided *cmd*'''
    try:
        process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        (stdout, stderr) = process.communicate()
    except Exception:
        logger.exception('Failed to exectue command "{}"'.format(cmd[0]))
        raise

    if process.returncode:
        logger.error(
            (
                'Subprocess failed, dumping output:\n'
                '--------------- {0} -----------------\n'
                '{1}'
                '--------------------------------------'
            ).format(cmd[0], stderr)
        )
        raise EnvironmentError('Subprocess failed: %s' % cmd[0])

    return stdout

def generate_thumbnail(filepath):
    '''generate thumbnail from the given *filepath*'''
    destination = tempfile.NamedTemporaryFile(suffix='.jpg').name

    cmd = [ffmpeg_cmd]
    cmd += ['-v', 'error']
    cmd += ['-i', filepath]
    cmd += ['-ss', '0']
    cmd += ['-an', '-vframes', '1']
    cmd += ['-vcodec', 'mjpeg']
    cmd += ['-f', 'image2']
    cmd += [destination]

    exec_cmd(cmd)
    return destination

def get_info(filepath):
    '''get file information from the given *filepath*'''
    cmd = [ffprobe_cmd]
    cmd += ['-v', 'error']
    cmd += ['-print_format', 'json']
    cmd += ['-show_format']
    cmd += ['-show_streams']
    cmd += [filepath]
    result = exec_cmd(cmd)

    try:
        result = json.loads(result)
    except Exception:
        raise IOError('ffprobe failed')

    try:
        streams = result.get('streams', {})
        video_info = [
            stream for stream in streams if stream.get('codec_type') == 'video'
        ][0]
        format_info = result.get('format', {})

        frame_rates = video_info.get('r_frame_rate', '0/0').split('/')
        frame_rate = float(frame_rates[0]) / float(frame_rates[1])
    except Exception:
        frame_rate = 0

    frame_out = int(video_info.get('nb_frames', 0))
    if not frame_out:
        duration = float(format_info.get('duration', 0))
        frame_out = int(duration * frame_rate)

    meta = {
        'frameIn': 0,
        'frameOut': frame_out,
        'frameRate': frame_rate,
    }

    return meta

def callback(event, session):
    '''Non encoding make-web-playable hook.'''
    # http://ftrack-python-api.rtd.ftrack.com/en/stable/example/web_review.html?highlight=reviewable

    # run new event
    server_location = session.get('Location', ftrack_api.symbol.SERVER_LOCATION_ID)

    version_id = event['data']['versionId']
    path = event['data']['path']

    version = session.get('AssetVersion', version_id)

    # Validate that the path is an accessible file.
    if not os.path.isfile(path):
        raise ValueError('"{0}" is not a valid filepath.'.format(path))

    # Validate file is of the supported format
    _, file_extension = os.path.splitext(path)
    if file_extension not in ENCODING_SUPPORTED_EXTENSIONS_VIDEO:
        logger.error('"{0}" is not in a valid file format.'.format(path))
        return

    # disable previous event if we are in any accepted format.
    event.stop()

    # publish the file for review without re encoding.
    component = version.create_component(
        path=path, data={'name': 'ftrackreview-mp4'}, location=server_location
    )
    metadata = get_info(path)
    component['metadata']['ftr_meta'] = json.dumps(metadata)

    # generate and publish thumbnail
    thumbnail_path = generate_thumbnail(path)
    version.create_thumbnail(thumbnail_path)

    session.commit()
    logger.info('make-reviewable hook completed.')

def subscribe(session):
    '''Subscribe to events.'''
    topic = 'ftrack.connect.publish.make-web-playable'
    logger.info('Subscribing to event topic: {0!r}'.format(topic))
    # add new make web playable without encoding

    # Note, we are forcing the priority to a higher value (20)
    # than the default one (100) so we can intercept the old event
    # and stop it before it gets triggered, allowing us to override its behaviour.

    session.event_hub.subscribe(
        'topic="{0}" and source.user.username="{1}"'.format(topic, session.api_user),
        functools.partial(callback, session=session),
        priority=20,
    )

def register(session, **kw):
    '''Register plugin. Called when used as an plugin.'''
    # Validate that session is an instance of ftrack_api.Session. If not,
    # assume that register is being called from an old or incompatible API and
    # return without doing anything.
    if not isinstance(session, ftrack_api.session.Session):
        logger.debug(
            'Not subscribing plugin as passed argument {0!r} is not an '
            'ftrack_api.Session instance.'.format(session)
        )
        return

    subscribe(session)
    logger.debug('Plugin registered')


def calculate(s):
    """
    :type s: str
    :rtype: int
    """
    s = s.replace(' ', '')
    fix = postfix(s)
    print(fix)
    temp = []
    sign = {
        '+': lambda x, y: x + y,
        '-': lambda x, y: x - y,
        '/': lambda x, y: x / y,
        '*': lambda x, y: x * y,
        '×': lambda x, y: x * y,
        '%': lambda x, y: x % y,
    }
    while fix:
        i = fix[0]
        fix.pop(0)
        if i not in '+-×*/%':
            temp.append(int(i))
        else:
            b, a = temp.pop(), temp.pop()
            temp.append(sign[i](a, b))
    return temp[0]

def postfix(s):
    """
    字符串转后缀表达式
    :param s: str
    :return: list
    """
    res = []
    temp = []
    # 优先级
    priority = {
        '+': 1, '-': 1, '*': 2,
        '×': 2, '/': 2, '%': 2,
    }
    for i in s:
        if i not in '*×/%+-()':
            res.append(i)
        elif i == ')':
            for j in temp[::-1]:
                if j == '(':
                    temp.pop()
                    break
                res.append(temp.pop())
        else:
            while True:
                # 判断优先级
                if not temp or temp[-1] == '(' or i == '(' or priority[i] > priority[temp[-1]]:
                    temp.append(i)
                    break
                else:
                    res.append(temp.pop())
                    pass
    res += temp[::-1]
    return res

print(calculate('1 + 1'))
print(calculate(' 2-1 + 2 '))
print(calculate('(1+(4+5+2)-3)+(6+8)'))
print(calculate('1+((2-3+2)×4)-5'))
# ['1', '1', '+']
# 2
# ['2', '1', '-', '2', '+']
# 3
# ['1', '4', '5', '+', '2', '+', '+', '3', '-', '6', '8', '+', '+']
# 23
# ['1', '2', '3', '-', '2', '+', '4', '×', '+', '5', '-']
# 0


from django.urls import path, re_path

from . import views

urlpatterns = [

    path("", views.index, name="index"),
    path("search", views.search, name="search"),
    path("create", views.create, name="create"),
    path('randoms', views.randoms, name="randoms"),
    path('edit/<str:name>/', views.edit, name="edit"),
    path('wiki/<str:name>/', views.title, name='entry')
]

# path('<str:page_title>', views.title, name="page_title")
# declare apps with
# app_name = "encyclopedia"
# urlpatterns = [
#    path("", views.index, name="index")
# ]
#  path('<str:name>', views.title, name="name")


file = open("Day7rawData", "r")
lines = file.readlines()
from time import perf_counter
import time

class Directory:
    instances = []
    def __init__(self, name, subdirectories=None, parent=None, size=0):
        self.__class__.instances.append(self)
        self.parent = parent
        self.name = name
        self.subdirectories = []
        self.size = size
        if subdirectories is not None:
            for subdirectory in subdirectories:
                self.add_subdirectory(subdirectory)
    def __repr__(self):
        return self.name
    def add_subdirectory(self, folder):
        self.subdirectories.append(folder)
        folder.parent = self
    def add_size(self,files):
        self.size += files
    def update_parents(self, files):
        if self.parent is None:
            self.add_size(files)
        else:
            self = self.parent
            self.add_size(files)
            self.update_parents(files)

subfolders = []
file_sizes = 0
directory = Directory("/", subfolders, None, file_sizes)
current_directory = directory

for line in lines:
    if "$ cd /" in line:
        pass
    elif "$ cd" in line and ".." not in line:
        # cd only lets us move within a folder
        # whatever it does we need to make sure it only moves down (or nowhere)
        for subdirectory in current_directory.subdirectories:
            z = (current_directory.name + "/" + line.split()[-1]).replace("//","/")
            if z == subdirectory.name:
                current_directory = subdirectory
    elif "dir " in line:
        # dir means we need to append a subfolder to the current directory
            current_directory.add_subdirectory(Directory((current_directory.name+"/"+line.split()[-1]).replace("//","/")))
        # DRY the replace here is repeating, could likely avoid by setting a better starting variable
    elif "$ ls" in line:
        pass
    elif "$ cd .." in line:
        current_directory = current_directory.parent
    elif str(line[0]).isdigit():
        # if the line has no cd, ls, or dir mentions, update the file sizes of all relevant directories
        current_directory.add_size(int(line.split()[0]))
        current_directory.update_parents(int(line.split()[0]))

total = 0
target = directory.size

t1 = time.perf_counter_ns()
for thing in Directory.instances:
    #print([total, thing.size])
    if thing.size < 100001:
        total += thing.size
    if thing.size - 8381165 >= 0 and thing.size < target:
        target = thing.size
t2 = time.perf_counter_ns()
print(t2 - t1)
print(total)
print(target)


''' Example script to run a full analysis on telescope data for BCGS lab course. The script calls
    typical steps of test beam data reconstruction. For simplicity fits are fitted with a straight line.

    Setup
    -----

    The telescope consists of 5 planes with 15cm clearance between the planes.
    The data was taken at ELSA with 2.5 GeV/c.

    The Mimosa26 has an active area of 21.2mm x 10.6mm and the pixel matrix
    consists of 1152 columns and 576 rows (18.4um x 18.4um pixel size).
    The total size of the chip is 21.5mm x 13.7mm x 0.036mm
    (radiation length 9.3660734)

    The matrix is divided into 4 areas. For each area the threshold can be set up
    individually. The quartes are from column 0-287, 288-575, 576-863 and 864-1151.
'''

import os
import inspect
import logging

from beam_telescope_analysis import hit_analysis
from beam_telescope_analysis import dut_alignment
from beam_telescope_analysis import track_analysis
from beam_telescope_analysis import result_analysis
from beam_telescope_analysis.tools import data_selection, analysis_utils
from beam_telescope_analysis.telescope.telescope import Telescope

logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - [%(levelname)-8s] (%(threadName)-10s) %(message)s")

def run_analysis(hit_files):
    # Create output subfolder where all output data and plots are stored
    output_folder = os.path.join(os.path.split(hit_files[0])[0], 'output_eutelescope')
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    mask_files = [(os.path.splitext(hit_file)[0] + '_mask.h5') for hit_file in hit_files]
    cluster_files = [(os.path.splitext(hit_file)[0] + '_clustered.h5') for hit_file in hit_files]

    z_positions = [0.0, 150000.0, 300000.0, 450000.0, 600000.0]  # in um. To be adjusted.
    material_budget = [7e-4, 7e-4, 7e-4, 7e-4, 7e-4]  # 5 Mimosa26 planes
    initial_configuration = os.path.join(output_folder, 'telescope.yaml')
    telescope = Telescope()
    telescope.add_dut(dut_type="Mimosa26", dut_id=0, translation_x=0, translation_y=0, translation_z=z_positions[0], rotation_alpha=0, rotation_beta=0, rotation_gamma=0, material_budget=material_budget[0], name="Telescope 1")
    telescope.add_dut(dut_type="Mimosa26", dut_id=1, translation_x=0, translation_y=0, translation_z=z_positions[1], rotation_alpha=0, rotation_beta=0, rotation_gamma=0, material_budget=material_budget[1], name="Telescope 2")
    telescope.add_dut(dut_type="Mimosa26", dut_id=2, translation_x=0, translation_y=0, translation_z=z_positions[2], rotation_alpha=0, rotation_beta=0, rotation_gamma=0, material_budget=material_budget[2], name="Telescope 3")
    telescope.add_dut(dut_type="Mimosa26", dut_id=3, translation_x=0, translation_y=0, translation_z=z_positions[3], rotation_alpha=0, rotation_beta=0, rotation_gamma=0, material_budget=material_budget[3], name="Telescope 4")
    telescope.add_dut(dut_type="Mimosa26", dut_id=4, translation_x=0, translation_y=0, translation_z=z_positions[4], rotation_alpha=0, rotation_beta=0, rotation_gamma=0, material_budget=material_budget[4], name="Telescope 5")
    telescope.save_configuration(initial_configuration)
    prealigned_configuration = os.path.join(output_folder, 'telescope_prealigned.yaml')
    aligned_configuration = os.path.join(output_folder, 'telescope_aligned.yaml')

    # Generate noisy pixel mask for all DUTs
    thresholds = [2, 2, 2, 2, 2]
    # last plane has noisy cluster, use larger median filter to mask cluster
    pixel_mask_names = ["NoisyPixelMask", "NoisyPixelMask", "NoisyPixelMask", "NoisyPixelMask", "NoisyPixelMask"]
    mask_files = hit_analysis.mask(
        telescope_configuration=initial_configuration,
        input_hit_files=hit_files,
        pixel_mask_names=pixel_mask_names,
        thresholds=thresholds)

    # Cluster hits from all DUTs
    use_positions = [False, False, False, False, False]
    min_hit_charges = [0, 0, 0, 0, 0]
    max_hit_charges = [1, 1, 1, 1, 1]
    column_cluster_distances = [3, 3, 3, 3, 3]
    row_cluster_distances = [3, 3, 3, 3, 3]
    frame_cluster_distances = [0, 0, 0, 0, 0]
    cluster_files = hit_analysis.cluster(
        telescope_configuration=initial_configuration,
        select_duts=None,
        input_hit_files=hit_files,
        input_mask_files=[None if val else mask_files[i] for i, val in enumerate(use_positions)],
        use_positions=use_positions,
        min_hit_charges=min_hit_charges,
        max_hit_charges=max_hit_charges,
        column_cluster_distances=column_cluster_distances,
        row_cluster_distances=row_cluster_distances,
        frame_cluster_distances=frame_cluster_distances)

    # Correlate each DUT with the first DUT
    hit_analysis.correlate(
        telescope_configuration=initial_configuration,
        input_files=cluster_files,
        output_correlation_file=os.path.join(output_folder, 'Correlation.h5'),
        resolution=(100.0, 100.0),
        select_reference_duts=0)

    # Create pre-alignment, take first DUT as reference
    prealigned_configuration = dut_alignment.prealign(
        telescope_configuration=initial_configuration,
        input_correlation_file=os.path.join(output_folder, 'Correlation.h5'),
        reduce_background=True,
        select_reference_dut=0)

    # Merge all cluster tables into a single table
    hit_analysis.merge_cluster_data(
        telescope_configuration=initial_configuration,
        input_cluster_files=cluster_files,
        output_merged_file=os.path.join(output_folder, 'Merged.h5'))

    # Create alignment, take first and last DUT as reference ("select_telescope_duts" parameter)
    # The position (translation and rotation) of telescope DUTs are not changed
    aligned_configuration = dut_alignment.align(
        telescope_configuration=prealigned_configuration,
        input_merged_file=os.path.join(output_folder, 'Merged.h5'),
        select_duts=[[0, 1, 2, 3, 4]],  # align the telescope planes first
        select_telescope_duts=[0, 1, 2, 3, 4],  # telescope planes
        select_fit_duts=[[0, 1, 2, 3, 4]],
        select_hit_duts=[[0, 1, 2, 3, 4]],
        max_iterations=[5],
        max_events=(100000),
        track_chi2=15.0,
        quality_distances=[(18.4 * 2, 18.4 * 2), (18.4 * 2, 18.4 * 2), (18.4 * 2, 18.4 * 2), (18.4 * 2, 18.4 * 2), (18.4 * 2, 18.4 * 2)],
        isolation_distances=(1000.0, 1000.0),
        use_limits=True,
        plot=True)

    # Find tracks from the tracklets and create a track candidates table
    track_analysis.find_tracks(
        telescope_configuration=aligned_configuration,
        input_merged_file=os.path.join(output_folder, 'Merged.h5'),
        output_track_candidates_file=os.path.join(output_folder, 'TrackCandidates_aligned.h5'),
        align_to_beam=True)

    # Fit the track candidates, assign quality flags, and create a track table
    # Simple straight line fit
    track_analysis.fit_tracks(
        telescope_configuration=aligned_configuration,
        input_track_candidates_file=os.path.join(output_folder, 'TrackCandidates_aligned.h5'),
        output_tracks_file=os.path.join(output_folder, 'Tracks_aligned.h5'),
        select_duts=[0, 1, 2, 3, 4],
        select_fit_duts=[0, 1, 2, 3, 4],
        select_hit_duts=[0, 1, 2, 3, 4],
        exclude_dut_hit=True,
        quality_distances=[(18.4 * 2, 18.4 * 2), (18.4 * 2, 18.4 * 2), (18.4 * 2, 18.4 * 2), (18.4 * 2, 18.4 * 2), (18.4 * 2, 18.4 * 2)],
        isolation_distances=(1000.0, 1000.0),
        use_limits=False,
        plot=True)

    # Calculate the unconstrained residuals from all tracks
    result_analysis.calculate_residuals(
        telescope_configuration=aligned_configuration,
        input_tracks_file=os.path.join(output_folder, 'Tracks_aligned.h5'),
        output_residuals_file=os.path.join(output_folder, 'Residuals_aligned.h5'),
        select_duts=[0, 1, 2, 3, 4],
        nbins_per_pixel=20,
        use_limits=True)

    # Do additional track selection cuts on the tracks table
    data_selection.select_tracks(
        telescope_configuration=aligned_configuration,
        input_tracks_file=os.path.join(output_folder, 'Tracks_aligned.h5'),
        output_tracks_file=os.path.join(output_folder, 'Tracks_aligned_selected.h5'),
        select_duts=[0, 1, 2, 3, 4],
        select_hit_duts=[0, 1, 2, 3, 4],
        select_no_hit_duts=None,
        select_quality_duts=[[1, 2, 3, 4], [0, 2, 3, 4], [0, 1, 3, 4], [0, 1, 2, 4], [0, 1, 2, 3]],
        query='(track_chi2 < 15.0)')

    # Calculate the unconstrained residuals from final tracks (with chi^2 cut and quality selection)
    result_analysis.calculate_residuals(
        telescope_configuration=aligned_configuration,
        input_tracks_file=os.path.join(output_folder, 'Tracks_aligned_selected.h5'),
        output_residuals_file=os.path.join(output_folder, 'Residuals_aligned_selected.h5'),
        select_duts=[0, 1, 2, 3, 4],
        nbins_per_pixel=20,
        use_limits=True)

# Main entry point is needed for multiprocessing under Windows
if __name__ == '__main__':
    # Get the absolute path of example data
    tests_data_folder = os.path.join(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))), 'data')
    # The location of the data files, one file per DUT
    hit_files = [analysis_utils.get_data(
        path='examples/TestBeamData_Mimosa26_DUT%d.h5' % i,
        output=os.path.join(tests_data_folder, 'TestBeamData_Mimosa26_DUT%d.h5' % i)) for i in range(5)]

    run_analysis(hit_files=hit_files)


from dataclasses import fields
from pickle import LIST
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.forms import DateInput, ModelForm

from relatorios.models import TableActionModel, TableEventModel, User
from .choices_coordenacao import LISTA_COORDENACAO

#Crianndo um Formulario para Registro
class RegisterEmployee(UserCreationForm):
    username = forms.CharField(help_text="Necessário ter um Usuario para ser seu login", widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Digite um usuario para acessar sua conta'}))
    first_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Primeiro Nome'}), max_length=32, help_text='Digite o seu Primeiro nome')
    last_name = forms.CharField(widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Sobrenome'}), max_length=32, help_text='Sobrenome')
    email = forms.EmailField(widget=forms.EmailInput(attrs={'class': 'form-control', 'placeholder': 'Email'}), max_length=64, help_text='Entre com um Endereço Válido')
    password1 = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Senha'}))
    password2 = forms.CharField(widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': 'Digite a senha novamente'}))
    sector_name = forms.ChoiceField(
        choices=LISTA_COORDENACAO,
    )
    #Usando o Models User do 'relatorios/models'
    class Meta(UserCreationForm):
        model = User
        fields = UserCreationForm.Meta.fields + ('sector_name','first_name', 'last_name', 'email',)

    def save(self, commit=True):
        user = super(UserCreationForm, self).save(commit=False)

        user.email = self.cleaned_data['email']
        user.first_name = self.cleaned_data['first_name']
        user.last_name = self.cleaned_data['last_name']
        user.sector_name = self.cleaned_data['sector_name']
        user.set_password(self.cleaned_data['password1'])

        if User.objects.filter(email=user.email).exists():
            raise forms.ValidationError('Email já cadastrado')
        elif User.objects.filter(username=user.username).exists():
            raise forms.ValidationError('Este usuário já existe')
        else:
            if commit:
                user.save()

    def __init__(self, *args, **kwargs):
        super(RegisterEmployee, self).__init__(*args, **kwargs)
        for visible in self.visible_fields():
            visible.field.widget.attrs['class'] = 'form-control my-1'

class TableActionForm(ModelForm):
    class Meta:
        model = TableActionModel
        fields = ['acao_realizada', 'tecnico_presencial', 'tecnico_nao_presencial',
        'outras_acoes', 'numbers_employee', 'description_action', 'date_actions']
        widgets = {
            'date_actions': forms.DateInput(attrs={'type':'date'}),
        }
    def __init__(self, *args, **kwargs):
        super(TableActionForm, self).__init__(*args, **kwargs)
        self.fields['numbers_employee'].label = "Numero de Funcionarios Atendidos"

class TableEventForm(ModelForm):
    class Meta:
        model = TableEventModel
        fields = ['title_event', 'event_feature', 'date_initial', 'date_final']
        widgets = {
            'title_event': forms.TextInput(),
            'date_initial': forms.DateInput(attrs={'type':'date'}),
            'date_final': forms.DateInput(attrs={'type':'date'})
        }

    def clean(self):
        super(TableEventForm, self).clean()

        title_event = self.cleaned_data.get("title_event")
        event_feature = self.cleaned_data.get("event_feature")
        date_initial = self.cleaned_data.get("date_initial")
        date_final = self.cleaned_data.get("date_final")

        return self.cleaned_data

    def __init__(self, *args, **kwargs):
        super(TableEventForm, self).__init__(*args, **kwargs)
        self.fields['event_feature'].label = "Característica do Evento"


'''This module handles the collecting of covid news from the API'''
import logging
import json
import requests
from flask import Markup

FORMAT = '%(levelname)s: %(asctime)s: %(message)s'
logging.basicConfig(filename='log_file.log', format=FORMAT, level=logging.INFO)

with open('config.json') as config_file:
    data = json.load(config_file)
    data = data["keys"]

def news_API_request(covid_terms:str = "Covid COVID-19 coronavirus") -> list:
    """This function creates a URL and retrives all the covid articles
    from it, returning them in a list of dictionaries.

    Args:
        covid_terms (str, optional): Terms related to coronavirus in order to
        filter through news articles. Defaults to "Covid COVID-19 coronavirus".

    Returns:
        list: List of covid articles stored as dictionaries
    """
    #Creates URL and collects covid news articles
    api_key = data["news"]
    base_url = 'https://newsapi.org/v2/everything?'
    final_url = base_url+"q="+covid_terms+"&apikey="+api_key
    covid_news = requests.get(final_url).json()
    news_articles = covid_news['articles']

    #changes content to description for better format
    for content in news_articles:
        content['content'] = content['description'] + "  " + Markup("<a href=" +
            content["url"] + ">" + "Read More" + "<a>")
    logging.info('NEWS REQUEST')

    return news_articles


import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
import torch
import copy

class ImageDataset():
    def __init__(self, imgPath="./data/images.npy", labelPath="./data/labels.npy", boxPath="./data/boxes.npy", boxLabelPath="./data/boxLabels.npy", countsPath="./data/counts.csv", range=None):
        # self.device = torch.device("cpu")
        self.device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")
        self.count = pd.read_csv(countsPath)
        self.range = len(self.count) if range is None else range
        self.images = preprocess(np.load(imgPath).astype('float32'))[0:range]
        self.labels = np.load(labelPath).astype('float32')[0:range]
        self.boxes = np.load(boxPath).astype('float32')[0:range]
        self.boxLabels = np.load(boxLabelPath).astype('float32')[0:range]
        self.prune()
        self.train_test_split()

    def prune(self):
        # prune data to only include images with more than 1 label
        self.index_map = []
        counts = self.count.sum(axis=1)
        new_images, new_labels, new_boxes, new_boxesLabels = [], [], [], []
        for i in range(len(self.images)):
            if counts[i] > 0:
                new_images.append(self.images[i])
                new_labels.append(self.labels[i])
                new_boxes.append(self.boxes[i])
                new_boxesLabels.append(self.boxLabels[i])
                self.index_map.append(i)
        self.images = np.array(new_images)
        self.labels = np.array(new_labels)
        self.boxes = np.array(new_boxes)
        self.boxLabels = np.array(new_boxesLabels)

    def train_test_split(self):
        indexes = list(range(len(self.images)))
        train_idx, val_idx = train_test_split(indexes, test_size=0.2, random_state=42)
        train_img_data, train_box_data, train_boxLabel_data, train_labels = [], [], [], []
        val_img_data, val_box_data, val_boxLabel_data, val_labels = [], [], [], []
        for i in range(len(train_idx)):
            train_img_data.append(self.images[train_idx[i]])
            train_box_data.append(self.boxes[train_idx[i]])
            train_boxLabel_data.append(self.boxLabels[train_idx[i]])
            train_labels.append(self.labels[train_idx[i]])
        for i in range(len(val_idx)):
            val_img_data.append(self.images[val_idx[i]])
            val_box_data.append(self.boxes[val_idx[i]])
            val_boxLabel_data.append(self.boxLabels[val_idx[i]])
            val_labels.append(self.labels[val_idx[i]])
        self.train_data = (train_img_data, train_box_data, train_boxLabel_data, train_labels)
        self.val_data = (val_img_data, val_box_data, val_boxLabel_data, val_labels)

    def get_batches(self, batch_size, training=True):
        data = self.train_data if training else self.val_data
        indexes = list(range(len(data[0])))
        perm_idx = np.random.permutation(indexes) if training else indexes
        for i in range(len(data[0]) // batch_size):
            batch_idx = perm_idx[i * batch_size : (i + 1) * batch_size]
            img_batch, target_batch = [], []
            for j in batch_idx:
                img = copy.deepcopy(data[0][j])
                img = torch.tensor(np.transpose(img, axes=[2, 0, 1])).to(self.device)
                img = img.to(self.device)
                img_batch.append(img)
                target_batch.append(self.make_target(data[1][j], data[2][j], data[3][j]))
            batch = (img_batch, target_batch)
            yield batch

    def make_target(self, boxes, boxLabels, label):
        data = {}
        img_boxes = []
        img_class_labels = []
        img_masks = []
        for i in range(len(boxes)):
            # while there is still boxes left
            if (boxLabels[i][0] != 0 and boxLabels[i][1] != 0):
                invalid_box = False
                for j in range(4):
                    if boxes[i][j] < 0 or boxes[i][j] >= 255:
                        invalid_box = True
                if invalid_box:
                    continue
                img_boxes.append(boxes[i])
                # classes are 0-indexed.
                img_class_labels.append(np.int64(boxLabels[i][1] - 1))
                img_mask = np.array(label[..., 0] == boxLabels[i][0], dtype=np.uint8)
                img_masks.append(img_mask)
            else:
                break
        data['boxes'] = torch.tensor(np.stack(img_boxes)).to(self.device)
        data['labels'] = torch.tensor(np.stack(img_class_labels)).to(self.device)
        data['masks'] = torch.tensor(np.stack(img_masks)).to(self.device)
        return data

def preprocess(images):
    # preprocess images
    images = images / 255
    images = np.transpose(images, axes=[3, 0, 1, 2])
    # normalize each channel
    for i in range(len(images)):
        mean = np.mean(images[i])
        std = np.std(images[i])
        images[i] = (images[i] - mean) / std
    images = np.transpose(images, axes=[1, 2, 3, 0])
    return images


#Intelligent Systems Project Assignment
#Authors: Daniel Nelson, Tyler Beaumont
#MasterAgent.py

from gui_functions import *
from HelperFunctions import ParseKIF
from RouteMap import RouteMap as Map
from ACO import ACO

class MasterRouter():
    KB = {} #Knowledge base. vehicle information

    def __init__(self):
        self.id = "m_"
        self.packages = None

    def RouteAlgorithm(self,alg,agents):
        """Route finding algorithm goes here.
        a modular approach allows us to easily
        implement multiple Routing methods"""
        if alg.lower() == "aco":
            aco = ACO(self.world,agents)
            return aco.Optimize()

    def SetWorld(self,locations):
        self.world = Map(locations,self.packages)

    def SumCapacities(self):
        """any KB entry with prefix v_ is a vehicle, sum each capacity attribute"""
        capacity_sum = 0
        for key in self.KB.keys():
            if key[0:2] == "v_":
                capacity_sum = capacity_sum + int(self.KB[key]['capacity'])
        self.KB.update({"m_":{
            "total_capacity":capacity_sum
        }})

        return capacity_sum
    # def publishRoutes(self):
    #     """Maybe Redundant? send route data to vehicles """
    #     pass

    def Ask(self,content):
        """Send inquiry to agent"""
        command = ParseKIF(content)
        if(len(command) == 2 ): #if len=2 basic query for a value
            try:
                return self.KB[command[1]][command[0]]
            except KeyError as e:
                return "{0} could not perform query:{1}".format(self.id,content)

    def Tell(self,sender,content):
        """Adds knowledge to KB"""
        command = ParseKIF(content)#format: [operator,[atrribute,object],value]

        if(command[0] == '='):
            self.KB.update({
                (command[1][1]) :{
                    (command[1][0]) : command[2]
                    }
                })

    def SetPackages(self,_packages):
        self.packages = _packages

    def Perform(self,command):
        """maybe not useful"""
        """Can't find implementation examples?
        Currently just accepts a command and tries to exec() it"""
        try:
            return eval("self."+command+"()")
        except AttributeError as e:
            return "%s tried to 'Perform' and invalid action." % self.id

    def Draw(self,locations,vehicles):
        pygame.init()
        GC = GuiController( locations )

        #Drawing Loop
        clock = pygame.time.Clock()
        done = False
        while not done:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    done = True
                #Draw
                GC.Draw(self.world.depot,self.world.locations,vehicles[::-1])

                GC.update()
            clock.tick(10)#Limit FPS
        pygame.quit()


"""
Blueprint related functions.

These Blueprint related functions generally align one-for-one with published API calls categorized in the Blueprint category

API v1 - https://t3n.zendesk.com/forums/20242326-Blueprint
API v2 - n/a
"""

import re
import os
import ftplib
# try:
#     from urllib.parse import urlparse
# except ImportError:
#     from urlparse import urlparse
if os.name == 'posix':  import curses
import operator
import clc

class Blueprint:

	visibility_stoi = { 'Public': 1, 'Private': 2, 'Shared': 3}
	classification_stoi = { 'System': 1, 'Script': 2, 'Scripts': 2, 'Software': 3}

	#@staticmethod
	#def List(type='All'):
	#	r = clc.v1.API.Call('post','Queue/ListQueueRequests',{'ItemStatusType': Queue.item_status_type_map[type] })
	#	if int(r['StatusCode']) == 0:  return(r['Requests'])

	@staticmethod
	def GetStatus(request_id,location=None,alias=None,silent=False):
		"""Gets the status of the specified Blueprint deployment.

		https://t3n.zendesk.com/entries/20561586-Get-Deployment-Status

		:param request_id: the int ID of the Blueprint Deployment to retrieve status for.
		:param alias: short code for a particular account.  If none will use account's default alias
		:param location: datacenter where group resides
		:param silent: disable status output when executed within CLI runtime
		"""
		if alias is None:  alias = clc.v1.Account.GetAlias()
		if location is None:  location = clc.v1.Account.GetLocation()
		r = clc.v1.API.Call('post','Blueprint/GetBlueprintStatus',{'AccountAlias': alias, 'RequestID': request_id, 'LocationAlias': location },silent=silent)
		if int(r['StatusCode']) == 0:  return(r)

	@staticmethod
	def GetPackages(classification,visibility):
		"""Gets a list of Blueprint Packages filtered by classification and visibility.

		https://t3n.zendesk.com/entries/20411357-Get-Packages

		:param classification: package type filter (System, Script, Software)
		:param visibility: package visibility filter (Public, Private, Shared)
		"""
		r = clc.v1.API.Call('post','Blueprint/GetPackages',
							{'Classification': Blueprint.classification_stoi[classification],'Visibility': Blueprint.visibility_stoi[visibility]})
		if int(r['StatusCode']) == 0:  return(r['Packages'])

	@staticmethod
	def GetAllPackages(classification):
		"""Gets a list of all Blueprint Packages with a given classification.

		https://t3n.zendesk.com/entries/20411357-Get-Packages

		:param classification: package type filter (System, Script, Software)
		"""
		packages = []
		for visibility in Blueprint.visibility_stoi.keys():
			try:
				for r in Blueprint.GetPackages(classification,visibility):  packages.append(dict(r.items()+{'Visibility':visibility}.items()))
			except:
				pass
		if len(packages):  return(packages)

	@staticmethod
	def GetAllSystemPackages():
		"""Returns list of all System packages."""
		return(Blueprint.GetAllPackages("System"))

	@staticmethod
	def GetAllScriptsPackages():
		"""Returns list of all Script packages."""
		return(Blueprint.GetAllPackages("Scripts"))

	@staticmethod
	def GetAllSoftwarePackages():
		"""Returns list of all Software packages."""
		return(Blueprint.GetAllPackages("Software"))

	@staticmethod
	def GetPendingPackages():
		"""Returns list of packages pending publishing."""
		r = clc.v1.API.Call('post','Blueprint/GetPendingPackages',{})
		if int(r['StatusCode']) == 0:  return(r['Packages'])

	@staticmethod
	def PackageUpload(package,ftp_url):
		"""Uploads specified zip package to cloud endpoint.

		See URL below for description on how to properly create a package:
		https://t3n.zendesk.com/entries/20348448-Blueprints-Script-and-Software-Package-Management

		:param package: path to zip file containing package.manifest and supporting scripts
		:param ftp_url: ftp URL including credentials of the form ftp://user:password@hostname
		"""
		#o = urlparse.urlparse(ftp_url)
		# Very weak URL checking
		#if o.scheme.lower() != "ftp":
		#	clc.v1.output.Status('ERROR',2,'Invalid FTP URL')
		#	return

		# Confirm file exists
		if not os.path.isfile(package):
			clc.v1.output.Status('ERROR',2,'Package file (%s) not found' % (package))
			return

		m = re.search("ftp://(?P<user>.+?):(?P<passwd>.+?)@(?P<host>.+)",ftp_url)
		try:
			ftp = ftplib.FTP(m.group('host'),m.group('user'),m.group('passwd'))
			file = open(package,'rb')
			filename = re.sub(".*/","",package)
			ftp.storbinary("STOR %s" % (filename),file)
			file.close()
			ftp.quit()
			clc.v1.output.Status('SUCCESS',2,'Blueprint package %s Uploaded' % (filename))
		except Exception as e:
			clc.v1.output.Status('ERROR',2,'FTP error %s: %s' % (ftp_url,str(e)))

		return({})

	@staticmethod
	def PackagePublish(package,classification,visibility,os):
		"""Publishes a Blueprint Package for use within the Blueprint Designer.

		https://t3n.zendesk.com/entries/20426453-Publish-Package

		:param package: path to zip file containing package.manifest and supporting scripts
		:param classification: package type (System, Script, Software)
		:param visibility: package visibility filter (Public, Private, Shared)
		:param os: list of ints containing Operating System template IDs
		"""
		r = clc.v1.API.Call('post','Blueprint/PublishPackage',
							{'Classification': Blueprint.classification_stoi[classification], 'Name': package, 'OperatingSystems': os,
							 'Visibility': Blueprint.visibility_stoi[visibility]})
		if int(r['StatusCode']) == 0:  return(r)

	# TODO - fix this mess
	@staticmethod
	def _DrawPublishPackageUIPosix(scr,linux_lst,windows_lst):
		scr.addstr(0,2,"Select all Operating Systems to be associated with this Blueprint Package: ")
		scr.addstr(1,2,"('q' when selection is complete)")

		max_pos = 0
		max_col1_len = 0
		pos = 2
		keys = linux_lst.keys()
		keys.sort
		for t in sorted(linux_lst.items(),key = lambda x :x[1]['Description']):
			l = t[0]
			l_f = "(%s)" % (l)
			if len(linux_lst[l]['Description'])>max_col1_len:
				max_col1_len = len(linux_lst[l]['Description'])
			pos += 1
			if linux_lst[l]['selected']:  scr.addstr(pos,1,"%s %s" % (l_f.ljust(4),linux_lst[l]['Description']),curses.A_BOLD)
			else:  scr.addstr(pos,1,"%s %s" % (l_f.ljust(4),linux_lst[l]['Description']))
		max_pos = pos
		pos = 2
		for t in sorted(windows_lst.items(),key = lambda x :x[1]['Description']):
			l = t[0]
			l_f = "(%s)" % (l)
			pos += 1
			if windows_lst[l]['selected']:  scr.addstr(pos,max_col1_len+9,"%s %s" % (l_f.ljust(4),windows_lst[l]['Description']),curses.A_BOLD)
			else:  scr.addstr(pos,max_col1_len+9,"%s %s" % (l_f.ljust(4),windows_lst[l]['Description']))

		if pos>max_pos:  max_pos = pos
		scr.addstr(max_pos+2,2,"	  ")
		scr.addstr(max_pos+2,2,"> ")
		scr.refresh()

		return(scr.getstr())

	# TODO - fix this mess
	@staticmethod
	def _DrawPublishPackageUI(linux_lst,windows_lst):
		print("\nSelect all Operating Systems to be associated with this Blueprint Package: ")
		print("'q' when selection is complete)\n")

		for items_lst in (linux_lst,windows_lst):
			for t in sorted(items_lst.items(),key = lambda x :x[1]['Description']):
				l = t[0]
				l_f = "(%s)" % (l)
				if items_lst[l]['selected']:  print( "[x] %s %s" % (l_f.ljust(4),items_lst[l]['Description']))
				else:  print( "[ ] %s %s" % (l_f.ljust(4),items_lst[l]['Description']))

		print( "\n")
		return(raw_input(" > "))

	# TODO - fix this mess
	@staticmethod
	def PackagePublishUI(package,type,visibility):
		"""Publishes a Blueprint Package for use within the Blueprint Designer after interactive OS selection.

		Interactive selection of one or more operating systems by name.

		:param package: path to zip file containing package.manifest and supporting scripts
		:param classification: package type (System, Script, Software)
		:param visibility: package visibility filter (Public, Private, Shared)
		"""
		# fetch OS list
		linux_lst = {'L': {'selected': False, 'Description': 'All Linux'}}
		windows_lst = {'W': {'selected': False, 'Description': 'All Windows'}}
		for r in clc.v1.Server.GetTemplates():
			r['selected'] = False
			if re.search("Windows",r['Description']):  windows_lst[str(r['OperatingSystem'])] = r
			elif re.search("CentOS|RedHat|Ubuntu",r['Description']):  linux_lst[str(r['OperatingSystem'])] = r

		# Get selections
		if os.name=='posix':
			scr = curses.initscr()
			curses.cbreak();
		while True:
			if os.name=='posix':  c = Blueprint._DrawPublishPackageUIPosix(scr,linux_lst,windows_lst)
			else:  c = Blueprint._DrawPublishPackageUI(linux_lst,windows_lst)
			if c.lower() == 'q':  break
			elif c.lower() == 'l':
				for l in linux_lst:  linux_lst[l]['selected'] = not linux_lst[l]['selected']
			elif c.lower() == 'w':
				for l in windows_lst:  windows_lst[l]['selected'] = not windows_lst[l]['selected']
			elif c in linux_lst:  linux_lst[c]['selected'] = not linux_lst[c]['selected']
			elif c in windows_lst:  windows_lst[c]['selected'] = not windows_lst[c]['selected']
		if os.name=='posix':
			curses.nocbreak(); curses.echo(); curses.endwin()

		# Extract selections
		ids = []
		for l in dict(linux_lst.items()+windows_lst.items()).values():
			if l['selected'] and 'OperatingSystem' in l:  ids.append(str(l['OperatingSystem']))
		clc.v1.output.Status('SUCCESS',2,'Selected operating system IDs: %s' % (" ".join(ids)))

		return(Blueprint.PackagePublish(package,type,visibility,ids))


'''
第 i 个人的体重为 people[i]，每艘船可以承载的最大重量为 limit。

每艘船最多可同时载两人，但条件是这些人的重量之和最多为 limit。

返回载到每一个人所需的最小船数。(保证每个人都能被船载)。

示例 1：

输入：people = [1,2], limit = 3
输出：1
解释：1 艘船载 (1, 2)
示例 2：

输入：people = [3,2,2,1], limit = 3
输出：3
解释：3 艘船分别载 (1, 2), (2) 和 (3)
示例 3：

输入：people = [3,5,3,4], limit = 5
输出：4
解释：4 艘船分别载 (3), (3), (4), (5)
提示：

1 <= people.length <= 50000
1 <= people[i] <= limit <= 30000

来源：力扣（LeetCode）
链接：https://leetcode-cn.com/problems/boats-to-save-people
著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
'''
import heapq
from typing import List

class Solution:
    def numRescueBoats(self, people: List[int], limit: int) -> int:
        # 构造一个最大堆和一个最小堆
        res = 0
        maxHq = [0]
        minHq = [0]
        for w in people:
            heapq.heappush(minHq, w)
            heapq.heappush(maxHq, -w)
        # 从最大堆和最小堆中分别取值
        minValue = heapq.heappop(minHq)
        maxValue = -heapq.heappop(maxHq)

        while minValue < maxValue:
            # 如果加起来大于limit，就把小的塞回去
            if(maxValue+minValue > limit):
                heapq.heappush(minHq, minValue)
            res += 1
            minValue = heapq.heappop(minHq)
            maxValue = -heapq.heappop(maxHq)

        print(res, minValue, maxValue, maxHq)
        # 现在剩下一组相同的值
        while minValue == maxValue:
            if maxValue <= limit//2:
                heapq.heappop(maxHq)
            res += 1
            maxValue = -heapq.heappop(maxHq)

        return res

s = Solution()
ans = s.numRescueBoats([1, 2], 3)
print('answer===', ans)