#! /usr/bin/env python3

import sys
from pathlib import Path
from math import *

def encode(x, y):
    return (x+7) + 15*(y+7)

"""
    static String n = "\00\01\02";

    static boolean isIn2(Direction dir) {
        return n.indexOf(dir.ordinal()) != -1;
    }
"""
RADII = {'34': 34, '20': 20, '10': 10}
SMALLER_RADII = {'34': 20, '20': 10, '10': 5}

DIRECTIONS = {
    (1, 0): 'EAST',
    (-1, 0): 'WEST',
    (0, 1): 'NORTH',
    (0, -1): 'SOUTH',
    (1, 1): 'NORTHEAST',
    (-1, 1): 'NORTHWEST',
    (1, -1): 'SOUTHEAST',
    (-1, -1): 'SOUTHWEST',
}

def min_chain(vals):
    if len(vals) == 1:
        return vals[0]
    return f"Math.min({vals[0]}, {min_chain(vals[1:])})"

def opposite(dir):
    if dir == 'EAST':
        return 'WEST'
    if dir == 'WEST':
        return 'EAST'
    if dir == 'NORTH':
        return 'SOUTH'
    if dir == 'SOUTH':
        return 'NORTH'
    if dir == 'NORTHEAST':
        return 'SOUTHWEST'
    if dir == 'NORTHWEST':
        return 'SOUTHEAST'
    if dir == 'SOUTHEAST':
        return 'NORTHWEST'
    if dir == 'SOUTHWEST':
        return 'NORTHEAST'
    return 'CENTER'

def direction_to(dx, dy):
    if (abs(dx) >= 2.414 * abs(dy)):
        if (dx > 0):
            return "EAST"
        elif (dx < 0):
            return "WEST"
        else:
            return "CENTER"
    elif (abs(dy) >= 2.414 * abs(dx)):
        if (dy > 0):
            return "NORTH"
        else:
            return "SOUTH"
    else:
        if (dy > 0):
            if (dx > 0):
                return "NORTHEAST"
            else:
                return "NORTHWEST"
        else:
            if (dx > 0):
                return "SOUTHEAST"
            else:
                return "SOUTHWEST"

def dist(x, y):
    return x*x + y*y

def gen_constants(radius):
    out = f""""""
    for x in range(-7, 8):
        for y in range(-7, 8):
            if dist(x, y) <= radius:
                out += f"""
    static MapLocation l{encode(x,y)}; // location representing relative coordinate ({x}, {y})
    static double d{encode(x,y)}; // shortest distance to location from current location
    static double score{encode(x,y)}; // heuristic distance from location to target
"""
    return out

def sign(x):
    if x > 0:
        return 1
    if x < 0:
        return -1
    return 0

def gen_init(radius):
    out = f"""
        l{encode(0,0)} = rc.getLocation();
        d{encode(0,0)} = 0;
"""
    for r2 in range(1, radius+1):
        for x in range(-7, 8):
            for y in range(-7, 8):
                if dist(x, y) == r2:
                    out += f"""
        l{encode(x,y)} = l{encode(x - sign(x), y - sign(y))}.add({DIRECTIONS[(sign(x), sign(y))]}); // ({x}, {y}) from ({x - sign(x)}, {y - sign(y)})
        d{encode(x,y)} = 99999;
"""
    return out

def gen_bfs(radius):
    visited = set([encode(0,0)])
    out = f""""""
    for r2 in range(1, radius+1):
        for x in range(-7, 8):
            for y in range(-7, 8):
                if dist(x, y) == r2:
                    indent = ""
                    out += f"""
        // check ({x}, {y})
        if (rc.canSenseLocation(l{encode(x,y)}) && rc.sensePassability(l{encode(x,y)})) {{"""
                    indent = "    "
                    dxdy = [(dx, dy) for dx in range(-1, 2) for dy in range(-1, 2) if (dx, dy) != (0, 0) and dist(x+dx,y+dy) <= radius]
                    dxdy = sorted(dxdy, key=lambda dd: dist(x+dd[0], y+dd[1]))
                    vals = []
                    for dx, dy in dxdy:
                        if encode(x+dx, y+dy) in visited:
                            vals.append(str([1/16, 5/16, 2/16, 6/16, 3/16, 7/16, 4/16, 8/16][(round(atan2(-dy,-dx)/pi*4)+8)%8]) if (x+dx,y+dy) == (0, 0) else f'd{encode(x+dx,y+dy)}')
            #                 out += f"""
            # {indent}if (d{encode(x,y)} > d{encode(x+dx,y+dy)}) {{ // from ({x+dx}, {y+dy})
            #     {indent}d{encode(x,y)} = {str([5/16, 1/16, 6/16, 2/16, 7/16, 3/16, 8/16, 4/16][(round(atan2(-dy,-dx)/pi*4)+8)%8]) if (x+dx,y+dy) == (0, 0) else f'd{encode(x+dx,y+dy)}'};
            # {indent}}}"""
                    out += f"""
        {indent}d{encode(x,y)} = {min_chain(vals)};"""

                    out += f"""
        {indent}mapInfo = rc.senseMapInfo(l{encode(x,y)});
        {indent}currentDir = mapInfo.getCurrentDirection();
        {indent}d{encode(x,y)} += 10 * (mapInfo.getCooldownMultiplier(team)) +
        {indent}{indent} (currentDir == CENTER ? 0 :
        {indent}{indent} (TARGET_DIR_ADJ.indexOf(currentDir.ordinal()) >= 0 ? -5 : 5));"""
                    out += f"""
        }}"""
                    visited.add(encode(x,y))
                    out += f"""
"""
    return out

def gen_selection(radius, smaller_radius):
    out = f"""
        int target_dx = target.x - l{encode(0,0)}.x;
        int target_dy = target.y - l{encode(0,0)}.y;
        switch (target_dx) {{"""
    for tdx in range(-7, 8):
        if tdx**2 <= radius:
            out += f"""
                case {tdx}:
                    switch (target_dy) {{"""
            for tdy in range(-7, 8):
                if dist(tdx, tdy) <= radius:
                    out += f"""
                        case {tdy}:
                            return direction(d{encode(tdx, tdy)}); // destination is at relative location ({tdx}, {tdy})"""
                            # if (dir{encode(tdx, tdy)} != null)
                            #     return dir{encode(tdx, tdy)}; // destination is at relative location ({tdx}, {tdy})
                            # break;"""
            out += f"""
                    }}
                    break;"""
    out += f"""
        }}

        ans = Double.POSITIVE_INFINITY;
        bestScore = 0;
        currDist = Math.sqrt(l{encode(0,0)}.distanceSquaredTo(target));
        """
    for x in range(-7, 8):
        for y in range(-7, 8):
            if smaller_radius < dist(x, y) <= radius: # on the edge of the radius radius
                out += f"""
        score{encode(x,y)} = (currDist - Math.sqrt(l{encode(x,y)}.distanceSquaredTo(target))) / d{encode(x,y)};
        if (score{encode(x,y)} > bestScore) {{
            bestScore = score{encode(x,y)};
            ans = d{encode(x,y)};
        }}
"""
    return out

def gen_print(radius):
    out = f"""
        // System.out.println("LOCAL DISTANCES:");"""
    for y in range(7, -8, -1):
        if y**2 <= radius:
            out += f"""
        // System.out.println("""
            for x in range(-7, 8):
                if dist(x, y) <= radius:
                    out += f""""\\t" + d{encode(x,y)} + """
                else:
                    out += f""""\\t" + """
            out = out[:-3] + """);"""
    return out

def gen_full(bot, rad):
    radius = RADII[rad]
    smaller_radius = SMALLER_RADII[rad]
    out_file = Path('./src/') / bot / f'bfs/BFSCooldown{rad}.java'
    with open(out_file, 'w') as f:
        f.write(f"""package {bot}.bfs;

import battlecode.common.*;

public class BFSCooldown{rad} {{

    public static RobotController rc;
{gen_constants(radius)}

    public static void init(RobotController r) {{
        rc = r;
        team = rc.getTeam();
    }}

    private static final Direction[] DIRECTIONS = new Direction[] {{null, Direction.EAST, Direction.NORTH, Direction.WEST, Direction.SOUTH, Direction.NORTHEAST, Direction.NORTHWEST, Direction.SOUTHWEST, Direction.SOUTHEAST}};

    public final static Direction NORTH = Direction.NORTH;
    public final static Direction NORTHEAST = Direction.NORTHEAST;
    public final static Direction EAST = Direction.EAST;
    public final static Direction SOUTHEAST = Direction.SOUTHEAST;
    public final static Direction SOUTH = Direction.SOUTH;
    public final static Direction SOUTHWEST = Direction.SOUTHWEST;
    public final static Direction WEST = Direction.WEST;
    public final static Direction NORTHWEST = Direction.NORTHWEST;
    public final static Direction CENTER = Direction.CENTER;

    public static MapInfo mapInfo;
    public static Direction currentDir;
    public static Team team;
    public static double ans;
    public static double bestScore;
    public static double currDist;

    public static String NORTH_ADJ = "\\07\\00\\01";
    public static String NORTHEAST_ADJ = "\\00\\01\\02";
    public static String EAST_ADJ = "\\01\\02\\03";
    public static String SOUTHEAST_ADJ = "\\02\\03\\04";
    public static String SOUTH_ADJ = "\\03\\04\\05";
    public static String SOUTHWEST_ADJ = "\\04\\05\\06";
    public static String WEST_ADJ = "\\05\\06\\07";
    public static String NORTHWEST_ADJ = "\\06\\07\\00";
    public static String TARGET_DIR_ADJ = "";

    public static Direction direction(double dist) {{
        if (dist==Double.POSITIVE_INFINITY) {{
            return null;
        }}
        return DIRECTIONS[(int)(dist * 16 % 16)];
    }}

    public static Direction bestDir(MapLocation target) throws GameActionException {{
        switch (rc.getLocation().directionTo(target)) {{
            case NORTH: TARGET_DIR_ADJ = NORTH_ADJ; break;
            case NORTHEAST: TARGET_DIR_ADJ = NORTHEAST_ADJ; break;
            case EAST: TARGET_DIR_ADJ = EAST_ADJ; break;
            case SOUTHEAST: TARGET_DIR_ADJ = SOUTHEAST_ADJ; break;
            case SOUTH: TARGET_DIR_ADJ = SOUTH_ADJ; break;
            case SOUTHWEST: TARGET_DIR_ADJ = SOUTHWEST_ADJ; break;
            case WEST: TARGET_DIR_ADJ = WEST_ADJ; break;
            case NORTHWEST: TARGET_DIR_ADJ = NORTHWEST_ADJ; break;
            default: TARGET_DIR_ADJ = ""; break;
        }}
{gen_init(radius)}
{gen_bfs(radius)}
{gen_print(radius)}
{gen_selection(radius, smaller_radius)}

        return direction(ans);
    }}
}}
""")

if __name__ == '__main__':
    if len(sys.argv) == 2:
        for rad in ["34", "20", "10"]:
            gen_full(sys.argv[1], rad)
    else:
        gen_full(sys.argv[1], sys.argv[2])


from flask import jsonify
from dao.athMovil import AthMovilDAO
from dao.payment import PaymentDAO
from dao.customer import CustomerDAO

class AthMovilHandler:

    def build_athMovil_dict(self, row):
        result = {}
        result['payment_id'] = row[0]
        result['ath_movil_id'] = row[1]
        result['ath_movil_phone'] = row[2]
        result['customer_id'] = row[3]
        return result

    def build_athMovil_attributes(self, ath_movil_id, payment_id, customer_id, ath_movil_phone):
        result = {}
        result['ath_movil_id'] = ath_movil_id
        result['payment_id'] = payment_id
        result['customer_id'] = customer_id
        result['ath_movil_phone'] = ath_movil_phone
        return result

    def getAllAthMovil(self):
        dao = AthMovilDAO()
        ath_movil_list = dao.getAllAthMovil()
        result_list = []
        for row in ath_movil_list:
            result = self.build_athMovil_dict(row)
            result_list.append(result)
        return jsonify(AthMovil = result_list)

    def getAthMovilById(self, ath_movil_id):
        dao = AthMovilDAO()
        row = dao.getAthMovilById(ath_movil_id)
        if not row:
            return jsonify(Error = "Ath Movil Not Found"), 404
        else:
            ath_movil = self.build_athMovil_dict(row)
            return jsonify(AthMovil = ath_movil)

    def getAthMovilByPaymentId(self, payment_id):
        dao = AthMovilDAO()
        row = dao.getAthMovilByPaymentId(payment_id)
        if not row:
            return jsonify(Error = "Ath Movil Not Found"), 404
        else:
                ath_movil = self.build_athMovil_dict(row)
                return jsonify(AthMovil = ath_movil)

    def searchAthMovil(self, args):
        ath_movil_phone = args.get("ath_movil_phone")
        dao = AthMovilDAO()
        ath_movil_list = []
        if (len(args) == 1) and ath_movil_phone:
            ath_movil_list = dao.getAthMovilByPhone(ath_movil_phone)
        else:
            return jsonify(Error = "Malformed query string"), 400
        result_list = []
        for row in ath_movil_list:
            result = self.build_athMovil_dict(row)
            result_list.append(result)
        return jsonify(AthMovil = result_list)

    def getAthMovilByCustomerId(self, customer_id):
        customer_dao = CustomerDAO()
        if not customer_dao.getCustomerById(customer_id):
            return jsonify(Error = "Customer not found."), 404
        else:
            dao = AthMovilDAO()
            row = dao.getAthMovilByCustomerId(customer_id)
            if not row:
                return jsonify(Error = "Ath Movil Not Found"), 404
            else:
                ath_movil = self.build_athMovil_dict(row)
                return jsonify(AthMovil = ath_movil)

    def insertAthMovil(self, json):
        customer_id = json["customer_id"]
        ath_movil_phone = json["ath_movil_phone"]

        if customer_id and ath_movil_phone:
            payment_dao = PaymentDAO()
            payment_id = payment_dao.insert(customer_id)
            ath_movil_dao = AthMovilDAO()
            ath_movil_id = ath_movil_dao.insert(payment_id, ath_movil_phone)
            result = self.build_athMovil_attributes(ath_movil_id, payment_id, customer_id, ath_movil_phone)
            return jsonify(AthMovil = result), 201
        else:
            return jsonify(Error = "Unexpected attributes in post request"), 400

    def updateAthMovil(self, ath_movil_id, json):
        ath_movil_dao = AthMovilDAO()
        if not ath_movil_dao.getAthMovilById(ath_movil_id):
            return jsonify(Error = "Ath Movil not found."), 404
        else:
            customer_id = json["customer_id"]
            ath_movil_phone = json["ath_movil_phone"]
            if customer_id and ath_movil_phone:
                payment_id = ath_movil_dao.update(ath_movil_id, ath_movil_phone)
                payment_dao = PaymentDAO()
                payment_dao.update(payment_id, customer_id)
                result = self.build_athMovil_attributes(ath_movil_id, payment_id, customer_id, ath_movil_phone)
                return jsonify(AthMovil = result), 200
            else:
                return jsonify(Error = "Unexpected attributes in post request"), 400

    def deleteAthMovil(self, ath_movil_id):
        ath_movil_dao = AthMovilDAO()
        if not ath_movil_dao.getAthMovilById(ath_movil_id):
            return jsonify(Error = "Ath Movil not found."), 404
        else:
            payment_id = ath_movil_dao.delete(ath_movil_id)
            payment_dao = PaymentDAO()
            payment_dao.delete(payment_id)
            return jsonify(DeleteStatus = "OK"), 200


#리스트 안에 for문 포함하기. 리스트 내포
a=[1,2,3,4]
result =[]
for num in a:
    result.append(num*3)

print(result)

result = [num *3 for num in a]
print(result)
#리스트 내포
"""
표현식 for 항목 in 반복가능객체 if 조건
"""


from lib.ConfigManager import ConfigManager
from lib.FileManager import FileManager
from lib.FixedSizeRotatingFileHandler import FixedSizeRotatingFileHandler
from lib.TableScraper import TableScraper

from flask import Flask, render_template, request, redirect, url_for, send_from_directory, jsonify
import time
import re
import logging
from werkzeug.exceptions import BadRequestKeyError
from threading import Lock

app = Flask(__name__)

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
# 250 MB
MAX_LOG_SIZE_FLASK = 250 * 1024 * 1024
MAX_LOG_SIZE = 250 * 1024 * 1024

app_logger = logging.getLogger("app_log")
app_logger.setLevel(logging.DEBUG)
fh = FixedSizeRotatingFileHandler("app_log.log", maxBytes=MAX_LOG_SIZE)  # 5KB
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
app_logger.addHandler(fh)

# werkzeug_logger = logging.getLogger("werkzeug")
# werkzeug_logger.setLevel(logging.DEBUG)
# werkzeug_logger_fh = FixedSizeRotatingFileHandler("flask_log.log", maxBytes=MAX_LOG_SIZE_FLASK)  # 5KB
# werkzeug_logger_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# werkzeug_logger_fh.setFormatter(werkzeug_logger_formatter )
# werkzeug_logger.addHandler(werkzeug_logger_fh)
# werkzeug_logger.propagate = False

def update_current_status(new_status):
    config = config_manager.load()
    if new_status in config['status']:
        config['current_status'] = new_status
        for property_name, property_value in config['status'][new_status].items():
            config['css_vars'][property_name] = property_value
            print(property_name,config['css_vars'][property_name],property_value,"\n",config)
        config_manager.save(config)
        update_css_file_from_config()
        print(f"New Config: {config}")
        return True
    else:
        return False

def update_css_file_from_config():
    config = config_manager.load()
    css_vars = config['css_vars']

    # Read the file using FileManager
    css_content = file_manager.read_file()

    for var, value in css_vars.items():
        pattern = f'--{var}:\s*[^;]*;'
        if re.search(pattern, css_content):
            css_content = re.sub(pattern, f'--{var}: {value};', css_content)
        else:
            css_content = css_content.replace(':root {', f':root {{\n  --{var}: {value};')

    # Write the updated content using FileManager
    file_manager.write_file(css_content)

def load_css_vars():
    css_content = file_manager.read_file()

    # Extract the content of the :root selector
    root_content_match = re.search(r':root\s*{\s*([^}]+)\s*}', css_content)
    if not root_content_match:
        return {}

    root_content = root_content_match.group(1)

    # Extract all --variable: value; pairs from the :root content
    variables = re.findall(r'--(.*?):\s?(.*?);', root_content)

    return {var_name: value for var_name, value in variables}

def update_times_in_config():
    """Update the opening times in the config."""
    config = config_manager.load()
    times = config['times']

    for day in times.keys():
        morning_time = request.form.get(f'{day}_morning')
        afternoon_time = request.form.get(f'{day}_afternoon')
        times[day] = [morning_time, afternoon_time]

    config_manager.save_if_changed(config)

def load_css_vars_from_config():
    return config_manager.load()['css_vars']
def load_status_word_from_config():
    return config_manager.load()['current_status']
def load_times_from_config():
    return config_manager.load()['times']

def update_config_from_post_request():
    config = config_manager.load()

    # Update CSS variables
    css_vars_from_file = load_css_vars()
    new_css_vars = {key: request.form.get(key, default='') for key in css_vars_from_file.keys()}
    config['css_vars'] = {**config.get('css_vars', {}), **new_css_vars}

    # Update times
    times = config['times']
    for day in times.keys():
        morning_time = request.form.get(f'{day}_morning')
        afternoon_time = request.form.get(f'{day}_afternoon')
        times[day] = [morning_time, afternoon_time]
    config['times'] = times

    # Update statuses
    for status_key in config['status'].keys():
        for property_name in config['status'][status_key].keys():
            input_name = f"{status_key}_{property_name}"
            config['status'][status_key][property_name] = request.form.get(input_name, default='')
    #update Scrapper Config
    config['scrapper_config']['url']=request.form.get('url')
    config['enable_scraping']=request.form.get('enable_scraping') == 'on'
    config['scrapper_config']['frame_id']= request.form.get('frame_id')
    config['scrapper_config']['refresh_time'] = request.form.get('refresh_time')
    config['scrapper_config']['valid_date']= request.form.get('valid_date')

    config_manager.save(config)

def update_config_from_status_change(new_status):
    config = config_manager.load()
    print(new_status)
    print(new_status in config['status'])
    if new_status in config['status']:
        config['current_status'] = new_status
        for property_name, property_value in config['status'][new_status].items():
            config['css_vars'][property_name] = property_value
        config_manager.save(config)
        update_css_file_from_config()
        return True
    else:
        return False

@app.errorhandler(BadRequestKeyError)
def handle_bad_request(e):
    return f'bad request!:{e}', 400
@app.route('/update-css-vars', methods=['POST'])
def update_css_vars():
    received_data = request.json
    print(received_data)
    received_css_vars = received_data.get('cssVars', {})
    received_status_word = received_data.get('currentStatusWord', "")
    received_times = received_data.get('times', {})

    config_data = config_manager.load()
    config_css_vars = config_data['css_vars']
    config_status_word = config_data['current_status']
    config_times = config_data['times']

    # Determine if any CSS variables changed
    css_vars_changed = any(received_css_vars[key] != config_css_vars.get(key) for key in received_css_vars)

    # Check if the status word has changed
    status_word_changed = received_status_word != config_status_word

    # Check if times have changed
    times_changed = received_times != config_times

    # Determine if any changes occurred
    if css_vars_changed or status_word_changed or times_changed:
        global prev_css_vars, prev_status_word, prev_times
        prev_css_vars = received_css_vars
        prev_status_word = received_status_word
        prev_times = received_times
        update_css_file_from_config()
        print("refresh")
        return {"refresh": True}

    return {"refresh": False}

@app.route('/', methods=['GET'])
def configure_times_get():
    config = config_manager.load()
    times = config['times']
    current_status_word=config['current_status']
    valid_date=config['valid_date']
    return render_template(r'index1_new.html', times=times, current_status_word=current_status_word,valid_date=valid_date)

@app.route('/', methods=['POST'])
def configure_times_post():

    config = config_manager.load()
    times = config['times']
    for day in times.keys():
        morning_time = request.form.get(f'{day}_morning')
        afternoon_time = request.form.get(f'{day}_afternoon')
        times[day] = [morning_time, afternoon_time]

    config['times'] = times
    config_manager.save_if_changed(config)
    return redirect(url_for('configure_times_get'))

@app.route('/settings', methods=['GET'])
def settings_get():
    config = config_manager.load()
    times = config['times']
    enable_scraping=config['enable_scraping']
    css_vars = load_css_vars()
    scrapper_config=config['scrapper_config']
    return render_template('settings.html', css_vars=css_vars, times=times, statuses=config['status'],enable_scraping=enable_scraping,scrapper_config=scrapper_config)

@app.route('/settings', methods=['POST'])
def settings_post():

    update_config_from_post_request()
    update_css_file_from_config()  # Update the CSS file based on the new config
    return redirect(url_for('settings_get'))

@app.route('/update-status', methods=['POST'])
def update_status():
    received_data = request.json
    new_status = received_data['current_status']
    if update_config_from_status_change(new_status):
        return {"message": "Status updated successfully"}
    else:
        return {"message": "Invalid status"}, 400

@app.route('/css/<filename>')
def serve_css(filename):
    return send_from_directory("static", filename)

if __name__ == "__main__":
    json_file_path = "config.json"

    config_manager = ConfigManager(json_file_path)
    file_manager = FileManager("static/Home.css")

    app.run(debug=True, port=4000)


import threading
import time

class Counter:
    def __init__(self):
        self.value = 0
        self.lock = threading.Lock()
    def increment(self):
        self.lock.acquire()
        self.value = self.value + 1
        value = self.value
        self.lock.release()
        return value

counter = Counter()

class ThreadDemo(threading.Thread):
    def __init__(self, create_time, index):
        threading.Thread.__init__(self)
        self.create_time = create_time
        self.index = index
    def run(self):
        time.sleep(10)
        value = counter.increment()
        print((time.time() - self.create_time), "\t", self.index, "\tvalue: ", value)

for i in range(100):
    thread = ThreadDemo(time.time(), i)
    thread.start()


# -*- coding:utf-8 -*-

"""
    功能： 从html 片段中，提取需要的信息。
    pip install beautifulsoup4

    字符串操作，文档： 5.Built-in Types -  5.6.Sequence Types — str, unicode, list, tuple, bytearray, buffer, xrange
    str.strip([chars])
"""
from bs4 import BeautifulSoup

import logging

def parse_script():
    html = open("iciba.html", "r", encoding='UTF-8')
    soup = BeautifulSoup(html.read(), 'html.parser')
    elements = soup.select('.btn')

    result = []
    for element in elements:
        print(element.text)
        result.append(get_attrs(element, "id") + element.text)

    print(result)

def get_attrs(element, attr):
    """
    判断attrs, 防止获取没有的key 报错。
    """
    if attr in element.attrs:
        return element.attrs[attr]
    else:
        return "--"

if __name__ == '__main__':
    parse_script()


import numpy as np
import pandas as pd

from pandas import DataFrame, Series

from ewa import EWA
from simulations import simulate_record, alt_simulate_record
from likelihood import set_evaluation, set_evaluation_with_graphs, likelihood
from tests import transformation, likelihood_ratio_test, salmon_set_test
import datetime
from matrices import matrix_set
from metrics import brier_multi, log_score_multi, wide_brier_calc

dt_string = datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d_%H:%M')

matrixSet = [[np.array(item[0].T, order='F'), item[1]] for item in matrix_set]

matrixSetTransposed = [[item[0].T, item[1]] for item in matrix_set]

for item in matrixSet:
    item[0] = DataFrame(np.array(item[0]))
    item[1] = DataFrame(np.asarray(item[1]))
# matrixSet
print(matrixSet[0][0])

population_set = {
    'EWA_FP': [1, 1, 1, 0, 1],
    'EWA_CB': [0, 1, 0, 1, 1],
    'EWA_RL': [0, 0, 0.75,1,1],
    'EWA_mdl':[0.5,0.5,0.5,0.5,1],
#     'test': [0.97, 0.6,  0.94,  1, 0.8, ],
            }
params_name = ['ro','delta','phi','N_in','lambd']
set_nubmbs = 50
couple_ides = 40
ages = 40

#Run evaluations over simulated data
for model in population_set:
    for idx, game_matrices in enumerate(matrixSet):
        print("MODEL: {model_name}".format(model_name=model))
        print("Matrix_set index : " + str(idx))
        simulation_df = simulate_record(ages, set_nubmbs,  dict(zip(params_name, population_set[model])),couple_ides, game_matrices, model_name=model)
        simulation =  simulation_df[simulation_df.columns[[0,1,2,3,4,]]]
        ids = sorted(simulation_df.id.unique())
        rounds = sorted(simulation_df['round'].unique())
        set_numbs = sorted(simulation_df['set_numb'].unique())
        simulation = simulation.to_numpy(dtype=None, copy=False)
        game_matrices=[item.values for item in game_matrices]
        set_evaluation_with_graphs(set_numbs, simulation, ids, rounds, game_matrices, dict(zip(params_name,population_set[model])), model, True, True)
        break

is_tested_set  = transformation(population_set)
hypothesis_set = {
#     'rho_1':{0:1},
#     'rho_0':{0:0},
    'delta_1':{1:1},
    'delta_0':{1:0},
     'phi_1':{1:1},
     'phi_0':{1:0}
    }

#Run hypothesis tests for restricted params
res = []
for model in population_set:
    for idx, game_matrices in enumerate(matrixSet):
        print("MODEL: {model_name}".format(model_name=model))
        print("Matrix: " + str(len(game_matrices[0]))+"x"+ str(len(game_matrices[0])))
        simulation_df = simulate_record(ages, set_nubmbs,  dict(zip(params_name, population_set[model])),
                                        couple_ides, game_matrices, model_name=model)
        simulation =  simulation_df[simulation_df.columns[[0,1,2,3,4,]]]
        ids = sorted(simulation_df.id.unique())
        rounds = sorted(simulation_df['round'].unique())
        set_numbs = sorted(simulation_df['set_numb'].unique())
        simulation = simulation.to_numpy(dtype=None, copy=False)
        game_matrices=[item.values for item in game_matrices]
        params_for_likelihood = [simulation, ids, rounds]
        y = salmon_set_test(start_params=[np.random.rand(1,1)[0][0] for i in range(5)], params_for_likelihood=params_for_likelihood,
                        params_restrictions= is_tested_set[model], test_results =  np.array([]), set_numbs = set_numbs,
                        game_matrices=tuple([game_matrices[0], game_matrices[1]]),
                        _bounds=((0, 1),(0, 1),(0, None),(0, 1),(0, None)) )
        percent_of_set_H0_not_false = np.mean((y>=0.95).astype(int))
        hyp_set = []
        for hyp in hypothesis_set.keys():
            z = salmon_set_test(start_params=[np.random.rand(1,1)[0][0] for i in range(5)], params_for_likelihood=params_for_likelihood,
                        params_restrictions= hypothesis_set[hyp], test_results =  np.array([]), set_numbs = set_numbs,
                        game_matrices=tuple([game_matrices[0], game_matrices[1]]),
                        _bounds=((0, 1),(0, 1),(0, None),(0, 1),(0, None)) )
            percent_of_z_set_H0_not_false = np.mean((z>=0.95).astype(int))
            mean_p_val = round(np.mean(z),2)
            hyp_set.append([hyp,'percent this one param hold', percent_of_z_set_H0_not_false,'mean_p_val', mean_p_val])

        for hypo in hyp_set:
            dct = {'model_name':model, 'matrix':(str(len(game_matrices[0]))+"x"+ str(len(game_matrices[0])))}
            dct['hyp'] = hypo[0]
            dct[hypo[1]] = hypo[2]
            dct[hypo[3]] = hypo[4]
            res.append(dct)
        print('percent, 4 params hold', percent_of_set_H0_not_false, 'mean p value', round(np.mean(y),2), hyp_set)
#             break
tests = pd.DataFrame(res)

tests.to_csv("tests_{dt}.csv".format(dt=dt_string))

fun = [0]
res = []
for model in population_set:
    for idx, game_matrices in enumerate(matrixSet):
        print("MODEL: {model_name}".format(model_name=model))
        print("Matrix_set index : " + str(idx))
        simulation_df = simulate_record(ages, set_nubmbs,  dict(zip(params_name, population_set[model])),
                                        couple_ides, game_matrices, model_name=model)
        ids = sorted(simulation_df.id.unique())
        rounds = sorted(simulation_df['round'].unique())
        set_numbers = sorted(simulation_df['set_numb'].unique())
        simulation = simulation_df.to_numpy(dtype=None, copy=False)
#             simulation =  simulation_df[simulation_df.columns[[0,1,2,3,4,]]]

        for alt_model in population_set:

            alt_simulation_df = alt_simulate_record(ages, set_numbers,  simulation,
                                                dict(zip(params_name, population_set[alt_model])),
                                                couple_ides, game_matrices, model_name=alt_model)
            pl1_move_wide_data = simulation_df['pl1_move_wide']

            y_true_pl1 = np.asarray([np.asarray(x)  for x in  pl1_move_wide_data], dtype=np.float32)

            probs_pl1_data = alt_simulation_df['probs_pl1']
            y_prob_pl1 = np.asarray([np.asarray(x)   for x in  probs_pl1_data], dtype=np.float32)
#                 [::-1]
#                 print(probs_pl1_data.head, pl1_move_wide_data.head)
            brier_pl1 = brier_multi(y_true_pl1, y_prob_pl1)
            container = []
            wide_brier = wide_brier_calc(simulation_df, alt_simulation_df, container, model,alt_model, set_numbers)
#                 print(np.round(brier_pl1,3)-np.round(np.mean(wide_brier["brier_score"]),3) )
            for one_set in set_numbers:
                dct = dict((('brier', (wide_brier["brier_score"][one_set])),( "sd_brier", np.std(wide_brier["brier_score"])),
                  ("log_score", np.mean(wide_brier["log_score"])), ("sd_log_score", np.std(wide_brier["log_score"])),
                  ('player','pl_1'),('true_model', model), ('alt_model',  alt_model), ('set', wide_brier["set_numb"][one_set])))
                dct['model_name'] = model
                dct['matrix'] = str(len(game_matrices[0]))+"x"+ str(len(game_matrices[0]))
                res.append(dct)
#                 print('brier:', brier_pl1, "sd_brier", np.std(wide_brier["brier_score"]),
#                       "log_score", np.mean(wide_brier["log_score"]), "sd_log_score",
#                       'pl_1','true_model', model, 'alt_model',  alt_model)

#             break
briers = pd.DataFrame(res)

briers.to_csv('measure_of_accuracy_{dt}.csv'.format(dt=dt_string))


#My first game project
import pygame , time

#intializes pygame
pygame.init()

#Sets the dimensions of the gaming window to a tuple which is immutable
displayWidth = 800
displayHeight = 600
gameDisplay = pygame.display.set_mode((displayWidth,displayHeight))

# Defining colors (R,G,B)
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)

font = pygame.font.SysFont(None,25)

#Functions
def message_to_screen(msg,color):
    screen_text = font.render(msg,True,color)
    gameDisplay.blit(screen_text,[displayWidth/2 , displayHeight/2])

#Sets the game window title
pygame.display.set_caption('Slither Me Timbers')
gameExit = False

clock = pygame.time.Clock()
fps = 60
block_size = 10

lead_x = displayWidth/2
lead_y = displayHeight/2
lead_x_change = 0
lead_y_change = 0

#Game Loop
while not gameExit:
    #Event Handler
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameExit = True
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                lead_x_change = -2
                lead_y_change = 0
            elif event.key == pygame.K_RIGHT:
                lead_x_change = 2
                lead_y_change = 0
            elif event.key == pygame.K_UP:
                lead_y_change = -2
                lead_x_change = 0
            elif event.key == pygame.K_DOWN:
                lead_y_change = 2
                lead_x_change = 0
        if lead_x >= displayWidth or lead_x <= 0 or lead_y >= displayHeight or lead_y <= 0:
            gameExit = True

    lead_x += lead_x_change   # lead_x = lead_x + lead_x_change
    lead_y += lead_y_change

    gameDisplay.fill(red)
    pygame.draw.rect(gameDisplay,black,[lead_x,lead_y,block_size,block_size])     #(where to draw it, color,[x,y,width,height])
    pygame.display.update()

    clock.tick(fps)

message_to_screen('You lost the game! Good job noob..',white)
pygame.display.update()
time.sleep(2)
#Unanitializes pygame display
pygame.quit()

#Quits python
quit()


#!/usr/bin/env python
""" Extract grain size and count vs time from log file for SPPARKS with diag_style cluster"""

import sys

logfile = ""
try:
  logfile = sys.argv[1]
except:
  sys.exit("Please supply a filename as an argument.")

# extract Time, Nclust, and <R> from logfile
# eschew checking logfile format
Time, Nclust, R_av = [], [], []
with open(logfile, "r") as f:
  for line in f:
    # skip ahead to simulations stats output
    if "Setting up run ..." not in line:
      pass
    else:
      # Extract all stats data
      next(f); line = next(f) # skip to the first line of stats output
      while "Loop time" not in line:
        T, Naccept, Nreject, Nsweeps, CPU, Num, N, R = line.split()
        Time.append(float(T))
        Nclust.append(int(Num))
        R_av.append(float(R))
        line = next(f)

# print output to console
print("time\tNclust\tR_av")
for time, N, R in zip(Time, Nclust, R_av):
  print("{0}\t{1}\t{2}".format(time, N, R))

# write output to tab-delimited csv
with open("cluster-stats.csv", "w") as f:
  f.write("time\tNclust\tR_av\n")
  for time, N, R in zip(Time, Nclust, R_av):
    f.write("{0}\t{1}\t{2}\n".format(time, N, R))

# try to plot with matplotlib
try:
  import matplotlib.pyplot as plt
except ImportError:
  print("Install matplotlib to plot data\n")
  sys.exit()

fig, (ax0, ax1) = plt.subplots(1,2,sharey=True)
ax0.plot(Time, R_av, 'o-')
ax0.set_xlabel('Time (MCS)',fontsize=20)
ax0.set_ylabel(r'$\langle R \rangle$ (pixels)',fontsize=20)

import math
sqrtTime = [math.sqrt(t) for t in Time]
ax1.plot(sqrtTime, R_av, 'o-')
ax1.set_xlabel(r'Time$^\frac{1}{2}$ (MCS$^\frac{1}{2}$)',fontsize=20)

plt.show()


import matplotlib.pyplot as plt
import numpy as np
import math

x = [int(i) for i in input().split()]
y = [int(i) for i in input().split()]

N = len(x)
Sx = 0
Sy = 0
Sxy = 0
Sx2 = 0
Sy2 = 0

for i in range(0, N):
    Sx += x[i]
    Sy += y[i]
    Sxy += x[i] * y[i]
    Sx2 += x[i] ** 2
    Sy2 += y[i] ** 2

print(Sx)
print(Sy)
print(Sxy)
print(Sx2)
print(Sy2)

r = (N * Sxy - Sx * Sy) / (math.sqrt(N * Sx2 - Sx ** 2) * math.sqrt(N * Sy2 - Sy ** 2))
print("The Correlation coefficient is %0.3f" % r)

byx = (N * Sxy - Sx * Sy) / (N * Sx2 - Sx ** 2)
print(byx)

xmean = Sx / N
ymean = Sy / N
print("The Regression line Y on X is ::: y = %0.3f + %0.3f (x-%0.3f)" % (ymean, byx, xmean))
xmean = Sx / N
ymean = Sy / N
print("The Regression line Y on X is ::: y = %0.3f + %0.3f (x-%0.3f)" % (ymean, byx, xmean))

plt.scatter(x, y)

def Reg(x):
    return ymean + byx * (x - xmean)

x = np.linspace(0, 80, 51)
y1 = Reg(x)

plt.plot(x, y1, 'r')
plt.xlabel('x-data')
plt.ylabel('y-data')
plt.legend(['Regression Line', 'Data points'])
plt.show()


import sys
import os
import tkinter
import pygame

from CaveGenerator import *
from FileManager import *

class Program(object):

    def __init__(self, root, d ,mn, mx):
        #Sets a tkinter instance
        self.root = root
        self.root.title("Cellular Automata v0.5")
        #set the weights of the grid
        self.root.grid_rowconfigure(0, weight=1)
        self.root.grid_columnconfigure(0, weight=1)
        self.root.grid_columnconfigure(1, weight=1)
        #Gets the screen resolution
        self.width = 600
        self.height = 500
        #Gets the values for the cave
        self.density = d
        self.mn = mn
        self.mx = mx
        #Create frame for the pygame window to go in
        self.pyframe = tkinter.Frame(self.root, width=self.width - 100, height=self.height)
        #Create frame for the cave settings
        self.setframe = tkinter.Frame(self.root, width=100, height=self.height) #added
        #Creates a top menu bar
        self.menubar = tkinter.Menu(self.root)
        #Creates a dropdown box from the menu
        self.filemenu = tkinter.Menu(self.menubar, tearoff=0)
        #Creates an Open and Save button in the dropdown
        self.filemenu.add_command(label="Open", command=self.LoadCave)
        self.filemenu.add_command(label="Save", command=self.SaveCave)
        self.filemenu.add_separator()
        #Label the dropdown as File
        self.menubar.add_cascade(label="File", menu=self.filemenu)
        self.root.config(menu=self.menubar)
        #Create the button label
        self.buttonlabel = tkinter.Label(self.setframe, text="Cave Density")
        #Create the button to generate the cave
        self.button = tkinter.Button(self.setframe, text="Generate", command=self.Generate, height = 2, width = 8)
        #Create the slider
        self.slider = tkinter.Scale(self.setframe, from_=0, to=25, orient=tkinter.HORIZONTAL)

        #Put the objects in the right location
        self.pyframe.grid(row=0, column=0)
        self.setframe.grid(row=0, column=1, rowspan=2)
        self.buttonlabel.grid(row=2, column=1)
        self.slider.grid(row=3, column=1, sticky="ew")
        self.button.grid(row=4, column=1, sticky="ew")

        #Update to display
        self.root.update()
        ###Tkinter Done###

        #The three lines below embed a pygame window to a tkinter window
        os.environ['SDL_WINDOWID'] = str(self.pyframe.winfo_id())
        if sys.platform == "win32":
            os.environ['SDL_VIDEODRIVER'] = 'windib'

        #Initialize Pygame
        pygame.display.init()
        #Set the screen size
        self.screen = pygame.display.set_mode((self.width, self.height))
        ###Pygame Done###

    def Generate(self):
        #Create a new cave
        self.cave = Cave(self.height,self.width,(float(self.slider.get()) * 0.1),self.mn,self.mx)
        #Generate the cave
        self.cave.Generate()
        #Get the cave data
        self.pixels = self.cave.Render()
        #Run the render loop
        self.loop()

    def loop(self):
        #Fill the screen black
        self.screen.fill((0,0,0))
        #Create a pixel
        square=pygame.Surface((1, 1)) #changed
        #loop through the positions
        for x in range(0, self.width, 1):
            for y in range(0, self.height, 1):
                #Check if a pixel needs to be displayed at position
                if self.pixels[y][x] == 1:
                    #Fill the colour white
                    square.fill((255,255,255))
                    draw_me=pygame.Rect((x+1), (y+1), 1, 1)
                    self.screen.blit(square,draw_me)
        #Update the screen to render
        pygame.display.flip()
        #self.pyframe.after(5, self.loop)

    def SaveCave(self):
        #Open a save file box and let the user save it in a location of choice
        savename = tkinter.filedialog.asksaveasfile(mode='w', defaultextension=".cave")
        #Check if cancel button has been pressed. If so return
        if savename is None:
            return
        #Runs the default classes to save
        filem = CFile(savename, self.cave)
        filem.WriteData()
        filem.SaveCreateFile()

    def LoadCave(self):
        #Open a load file box and let the user save it in a location of choice
        loadname = tkinter.filedialog.askopenfile(mode='r', defaultextension=".cave")
        #Check if cancel button has been pressed. If so return
        if loadname is None:
            return
        #Runs the default classes to load
        parser = ParseCFile(loadname)
        parser.ReadFile()
        self.cave = parser.Parse()
        #Gets the data for the pixel display
        self.pixels = self.cave.Render()

if __name__ == "__main__":
    #Creates the tkinter instance
    root = tkinter.Tk()
    #Creates a Program instance
    program = Program(root, 0.8, 1, 2) #0.8 is not needed anymore because self.density is not used.
    #Loop tkinter
    root.mainloop()


# Milestone 2 Lab 2 (P4)
# P4-Task 2: Final Team Code
# T143:
# Authors:
# Uchenna Obikwelu (101241887)
# Bolo Stephen (101201546)
# Jain Anusha  (101233115)
# Majok Samuel (101249411)

#Imports

from T143_P1_load_data import book_category_dictionary
from T143_P2_add_remove_search_dataset import*
from T143_P3_sorting_fun import*

#Function definitions

#Function Developed by all Team memebers
def menu()->str:
     """
     Displays the menu of commands for the interface.
     """
     a = "  1- L)oad file '\n' 2- A)dd book '\n' 3- R)emove book '\n' 4- G)et book  '\n'      T)itle R)ate A)uthor P)ublisher C)ategory '\n' 5- GCT) Get all Categories for book Title '\n' 6- S)ort book'\n'      T)itle R)ate P)ublisher A)uthor '\n' 7- Q)uit '\n' \n' Please type your command: "

     return a

#Function Developed by Bolo Stephen (101201546) and Majok Samuel (101249411)
def get_books(command:str)->dict:
     """
     After the user types the command G from the user_interface, the user would be prompted to Get Books by: T,R,A,P,C,or GCT from user_interface and would be further be prompted to type a title, a rate, an author, a publisher, or a category and then appropriate function will be called.

     """
     book=book_category_dictionary('google_books_dataset.csv')

     if command=='T':
          t=input("Enter a title: ")
          get_books_by_title(book,t)
     if command=='R':
          r=input("Enter a rating: ")
          get_books_by_rate(book,float(r))
     if command=='A':
          a=input("Enter an author: ")
          get_books_by_author(book,a)
     if command=='P':
          p=input("Enter a publisher: ")
          get_books_by_publisher(book, p)
     if command=='C':
          c=input("Enter a category: ")
          get_books_by_category(book,c)
     if command=='GCT':
          gct=input("Enter a title: ")
          get_all_categories_for_book_title(book,GCT)
     return

#Function Developed by Jain Anusha  (101233115)
def sort_books(arrange:str)->dict:

     """
     After the user types the command S from user_interface, the user will be prompted to type the sub-command Sort by: t,r,a or p, and then the appropriate function will be called.
     """
     y = book_category_dictionary('google_books_dataset.csv')

     if arrange == 'T':
          title= sort_books_title(y)
          print(title)

     if arrange == 'R':
          asc = sort_books_ascending_rate(y)
          print(asc)

     if arrange == 'A':
          author = sort_books_author(y)
          print(author)

     if arrange == 'P':
          publish = sort_books_publisher(y)
          print(publish)

#Function Developed by all Team memebers
def user_interface()->dict:
     """
     An interface for customizing the dictionary.
     """
     book=book_category_dictionary('google_books_dataset.csv') #The Filename
     x = True

     while x == True:
          data = input(menu())
          if data.upper() != 'Q':
               if data.upper() == 'L':
                    file= input("Enter filename: ")
                    y = book_category_dictionary(file)
                    data = input('Please type your command: ')
                    if data.upper() == 'A':
                         title=input("To Add book; first, enter the title: ")
                         author=input("Then the author: ")
                         rating=float(input("Then the rating: "))
                         publisher=input("Then the publisher:")
                         pages=int(input("Then the pages: "))
                         category=input("Then the category: ")
                         language=input("Finally the language: ")
                         add_book(book,(title,author,rating,publisher,pages,category,language))

                    if data.upper() == 'R':
                         title=input("Please enter the title of book: ")
                         category=input("category: ")
                         remove_book(book,title,category)

                    if data.upper() == 'G':
                         get = input('Get Books by: ')
                         get_books(get.upper())

                    if data.upper() == 'S':
                         arrange = input('Sort by: ')
                         sort_books(arrange.upper())

                    else:
                         print('No such command')

               else:
                    print('File not loaded')

          else:
               print('Quiting')
               x = False
     return
user_interface()

Milestone 2.2/T143 P4 Task 2 - Team Code/T143_P4_booksUI.py


import os
import anthem
import requests
API = 'https://loripsum.net/api/'

def loremsum(nbr, size):
    return requests.get('https://loripsum.net/api/%s/%s' % (nbr, size)).text

@anthem.log
def setup(ctx):
    env = ctx.env
    backend = env.ref('shopinvader.backend_1')
    backend.write({
        'auth_api_key_name': 'api_key_shopinvader_demo'
        })
    countries = env['res.country'].search([])
    backend.write({
        'allowed_country_ids': [(6, 0, countries.ids)],
        'category_binding_level': 3,
        })
    products = env['product.product'].search([
        ('image_ids', '!=', False),
        ])
    wizard = env['shopinvader.variant.binding.wizard'].create({
        'backend_id': backend.id,
        'product_ids': [(6, 0, products.ids)],
        })
    wizard.bind_products()
    for binding in env['shopinvader.product'].search([]):
        binding.write({
            'description': loremsum('3', 'medium'),
            'short_description': loremsum('1', 'short'),
            })


from datetime import datetime

import constants

class Date:
    def __init__(self, date: str) -> None:
        """Convert and validate the input date

        Args:
            date (str): The input date in the ISO format
        """
        self._date = date
        self._initial_date = datetime.strptime(
            constants.INITIAL_DATE, constants.DATE_FORMAT
        ).date()
        self.convert_to_datetime()

    def convert_to_datetime(self):
        """Convert the date string to datetime.date"""
        self._date = datetime.strptime(
            self._date, constants.DATE_FORMAT
        ).date()
        self.validate_initial_date()

    def validate_initial_date(self):
        """Validate if provided date is greater than the initial date

        Raises:
            ValueError: If the provided date is smaller that the initial date
        """
        if self._date < self._initial_date:
            raise ValueError(
                f"The date provided: {self._date} is older than the initial date: {self._initial_date}"
            )
        self.validate_current_date()

    def validate_current_date(self):
        """Validate if the provided date is not in the future

        Raises:
            ValueError: If the provided date is in the future
        """
        if self._date >= datetime.now().date():
            raise ValueError(
                f"The date provided {self._date} is in the future"
            )

    @property
    def date(self) -> datetime.date:
        """Return the converted and validated date

        Returns:
            datetime.date: The input date as datetime.date
        """
        return self._date


# -*- coding: utf-8 -*-

from odoo import api, models, fields, tools, _
from odoo.exceptions import ValidationError

class SaleOrder(models.Model):
    _inherit = "sale.order"

    shipping_fees = fields.Float('Shipping Fees', compute='_compute_shipping_fees')

    @api.multi
    @api.depends('website_order_line')
    def _compute_shipping_fees(self):
        minimum = self.env['website'].get_minimum_amount_for_free_shipping()
        for rec in self:
            fees = 0.00
            if minimum > 0 and rec.amount_total < minimum:
                for line in rec.website_order_line:
                    if line.product_id.is_shipping_service:
                        fees = line.product_id.website_public_price
                        break
            rec.shipping_fees = fees

    @api.model
    def _get_website_data(self, order):
        res = super(SaleOrder, self)._get_website_data(order)
        # get shiping minimum amount for free shipping
        minimum = self.env['website'].get_minimum_amount_for_free_shipping()
        shipping_fees = False
        # check if shipping fees should apply
        if minimum > 0 and order.amount_total < minimum:
            # check if shipping fees already applied
            shipping_fees_applied = False
            for line in order.website_order_line:
                if line.product_id.is_shipping_service:
                    shipping_fees = line.product_id.website_public_price
                    shipping_fees_applied = True
                    break
            # apply shipping if not already applied
            if not shipping_fees_applied:
                shipping_service_id = self.env['product.product'].search([('is_shipping_service','=',True)], limit=1)
                if shipping_service_id:
                    if shipping_service_id:
                        order._cart_update(shipping_service_id.id, add_qty=1)
                        shipping_fees = shipping_service_id.website_public_price
        res.update({'shipping_fees': shipping_fees})
        #raise ValidationError(shipping_fees)
        return res


from collections import OrderedDict
import gzip
import io
import logging
import os
import pickle
from typing import List, Optional, Union, Tuple, Iterable

import arff
import numpy as np
import pandas as pd
import scipy.sparse
import xmltodict
from warnings import warn

import openml._api_calls
from .data_feature import OpenMLDataFeature
from ..exceptions import PyOpenMLError
from ..utils import _tag_entity

logger = logging.getLogger(__name__)

class OpenMLDataset(object):
    """Dataset object.

    Allows fetching and uploading datasets to OpenML.

    Parameters
    ----------
    name : str
        Name of the dataset.
    description : str
        Description of the dataset.
    format : str
        Format of the dataset which can be either 'arff' or 'sparse_arff'.
    dataset_id : int, optional
        Id autogenerated by the server.
    version : int, optional
        Version of this dataset. '1' for original version.
        Auto-incremented by server.
    creator : str, optional
        The person who created the dataset.
    contributor : str, optional
        People who contributed to the current version of the dataset.
    collection_date : str, optional
        The date the data was originally collected, given by the uploader.
    upload_date : str, optional
        The date-time when the dataset was uploaded, generated by server.
    language : str, optional
        Language in which the data is represented.
        Starts with 1 upper case letter, rest lower case, e.g. 'English'.
    licence : str, optional
        License of the data.
    url : str, optional
        Valid URL, points to actual data file.
        The file can be on the OpenML server or another dataset repository.
    default_target_attribute : str, optional
        The default target attribute, if it exists.
        Can have multiple values, comma separated.
    row_id_attribute : str, optional
        The attribute that represents the row-id column,
        if present in the dataset.
    ignore_attribute : str | list, optional
        Attributes that should be excluded in modelling,
        such as identifiers and indexes.
    version_label : str, optional
        Version label provided by user.
        Can be a date, hash, or some other type of id.
    citation : str, optional
        Reference(s) that should be cited when building on this data.
    tag : str, optional
        Tags, describing the algorithms.
    visibility : str, optional
        Who can see the dataset.
        Typical values: 'Everyone','All my friends','Only me'.
        Can also be any of the user's circles.
    original_data_url : str, optional
        For derived data, the url to the original dataset.
    paper_url : str, optional
        Link to a paper describing the dataset.
    update_comment : str, optional
        An explanation for when the dataset is uploaded.
    status : str, optional
        Whether the dataset is active.
    md5_checksum : str, optional
        MD5 checksum to check if the dataset is downloaded without corruption.
    data_file : str, optional
        Path to where the dataset is located.
    features : dict, optional
        A dictionary of dataset features,
        which maps a feature index to a OpenMLDataFeature.
    qualities : dict, optional
        A dictionary of dataset qualities,
        which maps a quality name to a quality value.
    dataset: string, optional
        Serialized arff dataset string.
    """
    def __init__(self, name, description, format=None,
                 data_format='arff', dataset_id=None, version=None,
                 creator=None, contributor=None, collection_date=None,
                 upload_date=None, language=None, licence=None,
                 url=None, default_target_attribute=None,
                 row_id_attribute=None, ignore_attribute=None,
                 version_label=None, citation=None, tag=None,
                 visibility=None, original_data_url=None,
                 paper_url=None, update_comment=None,
                 md5_checksum=None, data_file=None, features=None,
                 qualities=None, dataset=None):

        # TODO add function to check if the name is casual_string128
        # Attributes received by querying the RESTful API
        self.dataset_id = int(dataset_id) if dataset_id is not None else None
        self.name = name
        self.version = int(version) if version is not None else None
        self.description = description
        if format is None:
            self.format = data_format
        else:
            warn("The format parameter in the init will be deprecated "
                 "in the future."
                 "Please use data_format instead", DeprecationWarning)
            self.format = format
        self.creator = creator
        self.contributor = contributor
        self.collection_date = collection_date
        self.upload_date = upload_date
        self.language = language
        self.licence = licence
        self.url = url
        self.default_target_attribute = default_target_attribute
        self.row_id_attribute = row_id_attribute
        if isinstance(ignore_attribute, str):
            self.ignore_attributes = [ignore_attribute]
        elif isinstance(ignore_attribute, list) or ignore_attribute is None:
            self.ignore_attributes = ignore_attribute
        else:
            raise ValueError('Wrong data type for ignore_attribute. '
                             'Should be list.')
        self.version_label = version_label
        self.citation = citation
        self.tag = tag
        self.visibility = visibility
        self.original_data_url = original_data_url
        self.paper_url = paper_url
        self.update_comment = update_comment
        self.md5_checksum = md5_checksum
        self.data_file = data_file
        self.features = None
        self.qualities = None
        self._dataset = dataset

        if features is not None:
            self.features = {}
            # todo add nominal values (currently not in database)
            for idx, xmlfeature in enumerate(features['oml:feature']):
                nr_missing = xmlfeature.get('oml:number_of_missing_values', 0)
                feature = OpenMLDataFeature(int(xmlfeature['oml:index']),
                                            xmlfeature['oml:name'],
                                            xmlfeature['oml:data_type'],
                                            xmlfeature.get('oml:nominal_value'),
                                            int(nr_missing))
                if idx != feature.index:
                    raise ValueError('Data features not provided '
                                     'in right order')
                self.features[feature.index] = feature

        self.qualities = _check_qualities(qualities)

        if data_file is not None:
            self.data_pickle_file = self._data_arff_to_pickle(data_file)
        else:
            self.data_pickle_file = None

    def _data_arff_to_pickle(self, data_file):
        data_pickle_file = data_file.replace('.arff', '.pkl.py3')
        if os.path.exists(data_pickle_file):
            with open(data_pickle_file, "rb") as fh:
                data, categorical, attribute_names = pickle.load(fh)

            # Between v0.8 and v0.9 the format of pickled data changed from
            # np.ndarray to pd.DataFrame. This breaks some backwards compatibility,
            # e.g. for `run_model_on_task`. If a local file still exists with
            # np.ndarray data, we reprocess the data file to store a pickled
            # pd.DataFrame blob. See also #646.
            if isinstance(data, pd.DataFrame) or scipy.sparse.issparse(data):
                logger.debug("Data pickle file already exists.")
                return data_pickle_file

        try:
            data = self._get_arff(self.format)
        except OSError as e:
            logger.critical("Please check that the data file %s is "
                            "there and can be read.", data_file)
            raise e

        ARFF_DTYPES_TO_PD_DTYPE = {
            'INTEGER': 'integer',
            'REAL': 'floating',
            'NUMERIC': 'floating',
            'STRING': 'string'
        }
        attribute_dtype = {}
        attribute_names = []
        categories_names = {}
        categorical = []
        for name, type_ in data['attributes']:
            # if the feature is nominal and the a sparse matrix is
            # requested, the categories need to be numeric
            if (isinstance(type_, list)
                    and self.format.lower() == 'sparse_arff'):
                try:
                    np.array(type_, dtype=np.float32)
                except ValueError:
                    raise ValueError(
                        "Categorical data needs to be numeric when "
                        "using sparse ARFF."
                    )
            # string can only be supported with pandas DataFrame
            elif (type_ == 'STRING'
                  and self.format.lower() == 'sparse_arff'):
                raise ValueError(
                    "Dataset containing strings is not supported "
                    "with sparse ARFF."
                )

            # infer the dtype from the ARFF header
            if isinstance(type_, list):
                categorical.append(True)
                categories_names[name] = type_
                if len(type_) == 2:
                    type_norm = [cat.lower().capitalize()
                                 for cat in type_]
                    if set(['True', 'False']) == set(type_norm):
                        categories_names[name] = [
                            True if cat == 'True' else False
                            for cat in type_norm
                        ]
                        attribute_dtype[name] = 'boolean'
                    else:
                        attribute_dtype[name] = 'categorical'
                else:
                    attribute_dtype[name] = 'categorical'
            else:
                categorical.append(False)
                attribute_dtype[name] = ARFF_DTYPES_TO_PD_DTYPE[type_]
            attribute_names.append(name)

        if self.format.lower() == 'sparse_arff':
            X = data['data']
            X_shape = (max(X[1]) + 1, max(X[2]) + 1)
            X = scipy.sparse.coo_matrix(
                (X[0], (X[1], X[2])), shape=X_shape, dtype=np.float32)
            X = X.tocsr()

        elif self.format.lower() == 'arff':
            X = pd.DataFrame(data['data'], columns=attribute_names)

            col = []
            for column_name in X.columns:
                if attribute_dtype[column_name] in ('categorical',
                                                    'boolean'):
                    col.append(self._unpack_categories(
                        X[column_name], categories_names[column_name]))
                else:
                    col.append(X[column_name])
            X = pd.concat(col, axis=1)

        # Pickle the dataframe or the sparse matrix.
        with open(data_pickle_file, "wb") as fh:
            pickle.dump((X, categorical, attribute_names), fh, -1)
        logger.debug("Saved dataset {did}: {name} to file {path}"
                     .format(did=int(self.dataset_id or -1),
                             name=self.name,
                             path=data_pickle_file)
                     )
        return data_pickle_file

    def push_tag(self, tag):
        """Annotates this data set with a tag on the server.

        Parameters
        ----------
        tag : str
            Tag to attach to the dataset.
        """
        _tag_entity('data', self.dataset_id, tag)

    def remove_tag(self, tag):
        """Removes a tag from this dataset on the server.

        Parameters
        ----------
        tag : str
            Tag to attach to the dataset.
        """
        _tag_entity('data', self.dataset_id, tag, untag=True)

    def __eq__(self, other):

        if type(other) != OpenMLDataset:
            return False

        server_fields = {
            'dataset_id',
            'version',
            'upload_date',
            'url',
            'dataset',
            'data_file',
        }

        # check that the keys are identical
        self_keys = set(self.__dict__.keys()) - server_fields
        other_keys = set(other.__dict__.keys()) - server_fields
        if self_keys != other_keys:
            return False

        # check that values of the common keys are identical
        return all(self.__dict__[key] == other.__dict__[key]
                   for key in self_keys)

    def _get_arff(self, format):
        """Read ARFF file and return decoded arff.

        Reads the file referenced in self.data_file.

        Returns
        -------
        dict
            Decoded arff.

        """

        # TODO: add a partial read method which only returns the attribute
        # headers of the corresponding .arff file!
        import struct

        filename = self.data_file
        bits = (8 * struct.calcsize("P"))
        # Files can be considered too large on a 32-bit system,
        # if it exceeds 120mb (slightly more than covtype dataset size)
        # This number is somewhat arbitrary.
        if bits != 64 and os.path.getsize(filename) > 120000000:
            return NotImplementedError("File too big")

        if format.lower() == 'arff':
            return_type = arff.DENSE
        elif format.lower() == 'sparse_arff':
            return_type = arff.COO
        else:
            raise ValueError('Unknown data format %s' % format)

        def decode_arff(fh):
            decoder = arff.ArffDecoder()
            return decoder.decode(fh, encode_nominal=True,
                                  return_type=return_type)

        if filename[-3:] == ".gz":
            with gzip.open(filename) as fh:
                return decode_arff(fh)
        else:
            with io.open(filename, encoding='utf8') as fh:
                return decode_arff(fh)

    @staticmethod
    def _convert_array_format(data, array_format, attribute_names):
        """Convert a dataset to a given array format.

        By default, the data are stored as a sparse matrix or a pandas
        dataframe. One might be interested to get a pandas SparseDataFrame or a
        NumPy array instead, respectively.
        """
        if array_format == "array" and not scipy.sparse.issparse(data):
            # We encode the categories such that they are integer to be able
            # to make a conversion to numeric for backward compatibility
            def _encode_if_category(column):
                if column.dtype.name == 'category':
                    column = column.cat.codes.astype(np.float32)
                    mask_nan = column == -1
                    column[mask_nan] = np.nan
                return column
            if data.ndim == 2:
                columns = {
                    column_name: _encode_if_category(data.loc[:, column_name])
                    for column_name in data.columns
                }
                data = pd.DataFrame(columns)
            else:
                data = _encode_if_category(data)
            try:
                return np.asarray(data, dtype=np.float32)
            except ValueError:
                raise PyOpenMLError(
                    'PyOpenML cannot handle string when returning numpy'
                    ' arrays. Use dataset_format="dataframe".'
                )
        if array_format == "dataframe" and scipy.sparse.issparse(data):
            return pd.SparseDataFrame(data, columns=attribute_names)
        return data

    @staticmethod
    def _unpack_categories(series, categories):
        col = []
        for x in series:
            try:
                col.append(categories[int(x)])
            except (TypeError, ValueError):
                col.append(np.nan)
        # We require two lines to create a series of categories as detailed here:
        # https://pandas.pydata.org/pandas-docs/version/0.24/user_guide/categorical.html#series-creation  # noqa E501
        raw_cat = pd.Categorical(col, ordered=True, categories=categories)
        return pd.Series(raw_cat, index=series.index, name=series.name)

    def _download_data(self) -> None:
        """ Download ARFF data file to standard cache directory. Set `self.data_file`. """
        # import required here to avoid circular import.
        from .functions import _get_dataset_arff
        self.data_file = _get_dataset_arff(self)

    def get_data(
            self,
            target: Optional[Union[List[str], str]] = None,
            include_row_id: bool = False,
            include_ignore_attributes: bool = False,
            dataset_format: str = "dataframe",
    ) -> Tuple[
            Union[np.ndarray, pd.DataFrame, scipy.sparse.csr_matrix],
            Optional[Union[np.ndarray, pd.DataFrame]],
            List[bool],
            List[str]
    ]:
        """ Returns dataset content as dataframes or sparse matrices.

        Parameters
        ----------
        target : string, List[str] or None (default=None)
            Name of target column to separate from the data.
            Splitting multiple columns is currently not supported.
        include_row_id : boolean (default=False)
            Whether to include row ids in the returned dataset.
        include_ignore_attributes : boolean (default=False)
            Whether to include columns that are marked as "ignore"
            on the server in the dataset.
        dataset_format : string (default='dataframe')
            The format of returned dataset.
            If ``array``, the returned dataset will be a NumPy array or a SciPy sparse matrix.
            If ``dataframe``, the returned dataset will be a Pandas DataFrame or SparseDataFrame.

        Returns
        -------
        X : ndarray, dataframe, or sparse matrix, shape (n_samples, n_columns)
            Dataset
        y : ndarray or pd.Series, shape (n_samples, ) or None
            Target column
        categorical_indicator : boolean ndarray
            Mask that indicate categorical features.
        attribute_names : List[str]
            List of attribute names.
        """
        if self.data_pickle_file is None:
            if self.data_file is None:
                self._download_data()
            self.data_pickle_file = self._data_arff_to_pickle(self.data_file)

        path = self.data_pickle_file
        if not os.path.exists(path):
            raise ValueError("Cannot find a pickle file for dataset %s at "
                             "location %s " % (self.name, path))
        else:
            with open(path, "rb") as fh:
                data, categorical, attribute_names = pickle.load(fh)

        to_exclude = []
        if not include_row_id and self.row_id_attribute is not None:
            if isinstance(self.row_id_attribute, str):
                to_exclude.append(self.row_id_attribute)
            elif isinstance(self.row_id_attribute, Iterable):
                to_exclude.extend(self.row_id_attribute)

        if not include_ignore_attributes and self.ignore_attributes is not None:
            if isinstance(self.ignore_attributes, str):
                to_exclude.append(self.ignore_attributes)
            elif isinstance(self.ignore_attributes, Iterable):
                to_exclude.extend(self.ignore_attributes)

        if len(to_exclude) > 0:
            logger.info("Going to remove the following attributes:"
                        " %s" % to_exclude)
            keep = np.array([True if column not in to_exclude else False
                             for column in attribute_names])
            if hasattr(data, 'iloc'):
                data = data.iloc[:, keep]
            else:
                data = data[:, keep]
            categorical = [cat for cat, k in zip(categorical, keep) if k]
            attribute_names = [att for att, k in
                               zip(attribute_names, keep) if k]

        if target is None:
            data = self._convert_array_format(data, dataset_format,
                                              attribute_names)
            targets = None
        else:
            if isinstance(target, str):
                if ',' in target:
                    target = target.split(',')
                else:
                    target = [target]
            targets = np.array([True if column in target else False
                                for column in attribute_names])
            if np.sum(targets) > 1:
                raise NotImplementedError(
                    "Number of requested targets %d is not implemented." %
                    np.sum(targets)
                )
            target_categorical = [
                cat for cat, column in zip(categorical, attribute_names)
                if column in target
            ]
            target_dtype = int if target_categorical[0] else float

            if hasattr(data, 'iloc'):
                x = data.iloc[:, ~targets]
                y = data.iloc[:, targets]
            else:
                x = data[:, ~targets]
                y = data[:, targets].astype(target_dtype)

            categorical = [cat for cat, t in zip(categorical, targets)
                           if not t]
            attribute_names = [att for att, k in zip(attribute_names, targets)
                               if not k]

            x = self._convert_array_format(x, dataset_format, attribute_names)
            if scipy.sparse.issparse(y):
                y = np.asarray(y.todense()).astype(target_dtype).flatten()
            y = y.squeeze()
            y = self._convert_array_format(y, dataset_format, attribute_names)
            y = y.astype(target_dtype) if dataset_format == 'array' else y
            data, targets = x, y

        return data, targets, categorical, attribute_names

    def retrieve_class_labels(self, target_name: str = 'class') -> Union[None, List[str]]:
        """Reads the datasets arff to determine the class-labels.

        If the task has no class labels (for example a regression problem)
        it returns None. Necessary because the data returned by get_data
        only contains the indices of the classes, while OpenML needs the real
        classname when uploading the results of a run.

        Parameters
        ----------
        target_name : str
            Name of the target attribute

        Returns
        -------
        list
        """
        for feature in self.features.values():
            if (feature.name == target_name) and (feature.data_type == 'nominal'):
                return feature.nominal_values
        return None

    def get_features_by_type(self, data_type, exclude=None,
                             exclude_ignore_attributes=True,
                             exclude_row_id_attribute=True):
        """
        Return indices of features of a given type, e.g. all nominal features.
        Optional parameters to exclude various features by index or ontology.

        Parameters
        ----------
        data_type : str
            The data type to return (e.g., nominal, numeric, date, string)
        exclude : list(int)
            Indices to exclude (and adapt the return values as if these indices
                        are not present)
        exclude_ignore_attributes : bool
            Whether to exclude the defined ignore attributes (and adapt the
            return values as if these indices are not present)
        exclude_row_id_attribute : bool
            Whether to exclude the defined row id attributes (and adapt the
            return values as if these indices are not present)

        Returns
        -------
        result : list
            a list of indices that have the specified data type
        """
        if data_type not in OpenMLDataFeature.LEGAL_DATA_TYPES:
            raise TypeError("Illegal feature type requested")
        if self.ignore_attributes is not None:
            if not isinstance(self.ignore_attributes, list):
                raise TypeError("ignore_attributes should be a list")
        if self.row_id_attribute is not None:
            if not isinstance(self.row_id_attribute, str):
                raise TypeError("row id attribute should be a str")
        if exclude is not None:
            if not isinstance(exclude, list):
                raise TypeError("Exclude should be a list")
            # assert all(isinstance(elem, str) for elem in exclude),
            #            "Exclude should be a list of strings"
        to_exclude = []
        if exclude is not None:
            to_exclude.extend(exclude)
        if exclude_ignore_attributes and self.ignore_attributes is not None:
            to_exclude.extend(self.ignore_attributes)
        if exclude_row_id_attribute and self.row_id_attribute is not None:
            to_exclude.append(self.row_id_attribute)

        result = []
        offset = 0
        # this function assumes that everything in to_exclude will
        # be 'excluded' from the dataset (hence the offset)
        for idx in self.features:
            name = self.features[idx].name
            if name in to_exclude:
                offset += 1
            else:
                if self.features[idx].data_type == data_type:
                    result.append(idx - offset)
        return result

    def publish(self):
        """Publish the dataset on the OpenML server.

        Upload the dataset description and dataset content to openml.

        Returns
        -------
        dataset_id: int
            Id of the dataset uploaded to the server.
        """
        file_elements = {'description': self._to_xml()}

        # the arff dataset string is available
        if self._dataset is not None:
            file_elements['dataset'] = self._dataset
        else:
            # the path to the arff dataset is given
            if self.data_file is not None:
                path = os.path.abspath(self.data_file)
                if os.path.exists(path):
                    try:

                        with io.open(path, encoding='utf8') as fh:
                            # check if arff is valid
                            decoder = arff.ArffDecoder()
                            decoder.decode(fh, encode_nominal=True)
                    except arff.ArffException:
                        raise ValueError("The file you have provided is not "
                                         "a valid arff file.")

                    with open(path, 'rb') as fp:
                        file_elements['dataset'] = fp.read()
            else:
                if self.url is None:
                    raise ValueError("No url/path to the data file was given")

        return_value = openml._api_calls._perform_api_call(
            "data/", 'post',
            file_elements=file_elements,
        )
        response = xmltodict.parse(return_value)
        self.dataset_id = int(response['oml:upload_data_set']['oml:id'])
        return self.dataset_id

    def _to_xml(self):
        """ Serialize object to xml for upload

        Returns
        -------
        xml_dataset : str
            XML description of the data.
        """
        props = ['id', 'name', 'version', 'description', 'format', 'creator',
                 'contributor', 'collection_date', 'upload_date', 'language',
                 'licence', 'url', 'default_target_attribute',
                 'row_id_attribute', 'ignore_attribute', 'version_label',
                 'citation', 'tag', 'visibility', 'original_data_url',
                 'paper_url', 'update_comment', 'md5_checksum']

        data_container = OrderedDict()
        data_dict = OrderedDict([('@xmlns:oml', 'http://openml.org/openml')])
        data_container['oml:data_set_description'] = data_dict

        for prop in props:
            content = getattr(self, prop, None)
            if content is not None:
                data_dict["oml:" + prop] = content

        xml_string = xmltodict.unparse(
            input_dict=data_container,
            pretty=True,
        )
        # A flow may not be uploaded with the xml encoding specification:
        # <?xml version="1.0" encoding="utf-8"?>
        xml_string = xml_string.split('\n', 1)[-1]
        return xml_string

def _check_qualities(qualities):
    if qualities is not None:
        qualities_ = {}
        for xmlquality in qualities:
            name = xmlquality['oml:name']
            if xmlquality.get('oml:value', None) is None:
                value = float('NaN')
            elif xmlquality['oml:value'] == 'null':
                value = float('NaN')
            else:
                value = float(xmlquality['oml:value'])
            qualities_[name] = value
        return qualities_
    else:
        return None


#max heap from array

def heapify(arr, n, i):

  largest = i
  leftNode = 2*i +1
  rightNode = 2*i + 2

  if n> leftNode and arr[leftNode] > arr[largest]:
    largest = leftNode

  if n> rightNode and arr[rightNode] > arr[largest]:
    largest = rightNode

  if largest!=i:
    arr[i],arr[largest] = arr[largest],arr[i]

    heapify(arr,n,largest)

def buildHeap(arr, n):

    # Index of last non-leaf node
    startIdx = n // 2 - 1

    # Perform reverse level order traversal
    # from last non-leaf node and heapify
    # each node
    for i in range(startIdx, -1, -1):
        heapify(arr, n, i)

def heapSort(arr,n):
    startIdx = n // 2 - 1

    # Perform reverse level order traversal
    # from last non-leaf node and heapify
    # each node
    for i in range(startIdx, -1, -1):
        heapify(arr, n, i)

    for x in range(n-1 , 0 ,-1) :
          arr[0],arr[x]= arr[x],arr[0]
          heapify(arr, x, 0)

def printHeap(arr, n):
    print("Array representation of Heap is:")

    for i in range(n):
        print(arr[i], end=" ")
    print()

if __name__ == '__main__':
  arr = [1, 3, 5, 4, 6, 13,
           10, 9, 8, 15, 17]

  n = len(arr)

  buildHeap(arr, n)

  printHeap(arr, n)

  heapSort(arr, n)

  printHeap(arr, n)


load("@rules_ocaml//ocaml:providers.bzl",
     "OcamlModuleMarker",
     "OcamlProvider",
     "OcamlSignatureProvider",
     "OcamlNsResolverProvider")

################################################################
def _ocaml_selection_proxy_impl(ctx):
    print(ctx.attr.selection)
    print("ct: %s" % len(ctx.attr.selection))
    for s in ctx.attr.selection:
        print("DefaultInfo: %s" % s[DefaultInfo])
        if OcamlSignatureProvider in s:
            print("OcamlSignatureProvider: %s" % s[OcamlSignatureProvider])

    providers = []
    s = ctx.attr.selection[0]
    if OcamlProvider in s:
        providers.append(s[OcamlProvider])
        if OcamlSignatureProvider in s:
            providers.append(s[OcamlSignatureProvider])
            providers.append(s[DefaultInfo])
    else:
        ## input is a source file
        providers = [DefaultInfo(files = s.files, executable = None)]

    return providers

_ocaml_selection_proxy = rule(
    implementation = _ocaml_selection_proxy_impl,
    doc = "Workaround for using transitions with selectable attributes",
    attrs = dict(
        selection = attr.label_list(
            allow_files = True
        )
    ),
    executable = False
)

def ocaml_selection_proxy(name, selectors, no_match_error_msg):

    # if no_match_error:
    #     selectors = "select({sel}),no_match_error = \"{nomatch}\")".format(
    #         sel = selectors, nomatch = no_match_error)
    # else:
    #     selectors = "select({sel})".format(
    #         sel = selectors, nomatch = no_match_error)

    if no_match_error_msg:
        _ocaml_selection_proxy(
            name = name,
            selection = select(
                selectors,
                no_match_error=no_match_error_msg
            )
        )
    else:
        _ocaml_selection_proxy(
            name = name,
            selection = select(selectors, no_match_error="foo")
        )

################################################################
def _cc_selection_proxy_impl(ctx):
    # print(ctx.attr.selection)
    # print("ct: %s" % len(ctx.attr.selection))

    cc_infos = []
    for s in ctx.attr.selection:
        # print("DefaultInfo: %s" % s[DefaultInfo])
        # print("CcInfo: %s" % s[CcInfo])
        cc_infos.append(s[CcInfo])

    ccInfo = cc_common.merge_cc_infos(cc_infos = cc_infos)

    providers = []
    s = ctx.attr.selection[0]
    providers = [DefaultInfo(files = s.files, executable = None),
                 ccInfo]

    return providers

cc_selection_proxy = rule(
    implementation = _cc_selection_proxy_impl,
    doc = "Workaround for using transitions with selectable attributes",
    attrs = dict(
        selection = attr.label_list(
            allow_files = True,
            providers = [CcInfo]
        ),
        ## https://bazel.build/docs/integrating-with-rules-cc
        ## hidden attr required to make find_cpp_toolchain work:
        _cc_toolchain = attr.label(
            default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")
        ),
    ),
    executable = False,
    fragments = ["platform", "cpp"],
    host_fragments = ["platform",  "cpp"],
    toolchains = ["@bazel_tools//tools/cpp:toolchain_type"]
)

# def Xcc_selection_proxy(name, selectors, no_match_error_msg):

#     # if no_match_error:
#     #     selectors = "select({sel}),no_match_error = \"{nomatch}\")".format(
#     #         sel = selectors, nomatch = no_match_error)
#     # else:
#     #     selectors = "select({sel})".format(
#     #         sel = selectors, nomatch = no_match_error)

#     if no_match_error_msg:
#         _cc_selection_proxy(
#             name = name,
#             selection = select(
#                 selectors,
#                 no_match_error=no_match_error_msg
#             )
#         )
#     else:
#         _cc_selection_proxy(
#             name = name,
#             selection = select(selectors, no_match_error="foo")
#         )


from aocd.models import Puzzle
from collections import defaultdict
import logging
import re
import sys

logging.basicConfig(level=logging.INFO)

p = Puzzle(year=2022, day=24)

TEST = True
TEST = False

if TEST:
  lines = [
    "#.######",
    "#>>.<^<#",
    "#.<..<<#",
    "#>v.><>#",
    "#<^v^^>#",
    "######.#",
  ]
else:
  lines = p.input_data.splitlines()

def print_grid(g):
  print('#.', end='')
  print('#' * len(g[0]))
  for row in g:
    print('#', end='')
    for c, blizz in enumerate(row):
      v = ''
      if len(blizz) == 0:
        v = '.'
      elif len(blizz) == 1:
        v = blizz[0]
      else:
        v = str(len(blizz))
      print(v, end='')
    print('#')
  print('#' * len(g[0]), end='')
  print('.#')

def make_grid(rows, cols, initializer=None):
  g = []
  for r in range(rows):
    g.append([])
    for c in range(cols):
      g[r].append([])
      if initializer is not None:
        g[r][c] = initializer()
  return g

def evolve(g):
  new_grid = make_grid(len(g), len(g[0]), list)
  for row, line in enumerate(g):
    for col, blizz in enumerate(line):
      # new_grid[row][col] = []
      for b in blizz:
        new_row = row
        new_col = col
        if b == '>':
          if col + 1 >= len(line):
            new_col = 0
          else:
            new_col = col+1
        elif b == '<':
          if col - 1 < 0:
            new_col = len(line) - 1
          else:
            new_col = col - 1
        elif b == '^':
          if row - 1 < 0:
            new_row = len(g) - 1
          else:
            new_row = row - 1
        elif b == 'v':
          if row + 1 >= len(g):
            new_row = 0
          else:
            new_row = row + 1
        else:
          logging.warning(f"Unexpected blizzard direction: {b}")
        logging.debug(f"Moving {b} from {row},{col} to {new_row},{new_col}")
        new_grid[new_row][new_col].append(b)
  return new_grid

def get_available_spaces(g, current_position):
  spaces = set()
  spaces.add(initial_position)

# sort by manhattan distance
def sort_path(path):
  r,c = path[-1]
  return abs(len(grid) - r) + abs(len(grid[0]) - c)

grid = []

for i, line in enumerate(lines[1:-1]):
  grid.append([])
  for blizz in line[1:-1]:
    if blizz == '.':
      grid[i].append([])
    else:
      grid[i].append([blizz])

logging.debug("Initial grid:")
print_grid(grid)

def seek(grid, start_pos, goal_pos):
  goal_row, goal_col = goal_pos
  start_row, start_col = start_pos
  all_paths = [[start_pos]]
  i = 0
  while True:
    i += 1
    if i % 20 == 0:
      logging.info(f"Minute {i}:")
    grid = evolve(grid)
    if TEST:
      print_grid(grid)
    new_paths = []
    # Keep just one path per distinct endpoint - any of them will do.
    ends = set()
    if i % 20 == 0:
      logging.info(f"Looking at {len(all_paths)} paths of length {len(all_paths[0])}")
    for path in all_paths:
      logging.debug(f"Looking at path {path}")
      cr, cc = path[-1]
      for nr, nc in [(cr, cc), (cr - 1, cc), (cr + 1, cc), (cr, cc - 1), (cr, cc + 1)]:
        if nr == goal_row and nc == goal_col:
          # done!
          shortest_path = len(path)
          logging.info(f"Shortest path: {shortest_path} -> {path}")
          return shortest_path, grid
        # First move is "wait"
        if nr == start_row and nc == start_col:
          new_paths.append(path + [(nr, nc)])
        if nr < 0 or nc < 0 or nr >= len(grid) or nc >= len(grid[0]):
          continue
        if len(grid[nr][nc]) == 0:
          logging.debug(f"found a potential step from {cr},{cc} -> {nr},{nc}")
          if (nr,nc) in ends:
            logging.debug(f"Already have a path of length {len(path) + 1} ending at ({nr},{nc}). Skipping path")
          else:
            logging.debug(f"Keeping a path of length {len(path) + 1} ending at ({nr},{nc}). Keeping path")
            ends.add((nr,nc))
            new_paths.append(path + [(nr, nc)])

    if len(new_paths) == 0:
      logging.info("Ran out of paths :(")
      return None, grid

    all_paths = new_paths
    logging.info(f"Closest of {len(all_paths)}: {sort_path(all_paths[0])}, furthest: {sort_path(all_paths[-1])}")

initial_position = (0,-1)
goal_position = (len(grid), len(grid[0]) - 1)

shortest_path, next_grid = seek(grid, initial_position, goal_position)
logging.info(f"Found a short path of {shortest_path}")
# p.answer_a = 10

logging.info("turning around...")
path_back, next_grid = seek(next_grid, goal_position, initial_position)
logging.info(f"Found shortest path back: {path_back}")

logging.info("turning around...")
path_forth, next_grid = seek(next_grid, initial_position, goal_position)
logging.info(f"Found shortest path forth: {path_forth}")

total_time = shortest_path + path_back + path_forth
logging.info(f"Total time: {total_time}")


import tensorflow as tf

# Grab our data tp start/
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

# Input data as placeholders since they'll be filled in when we
# run the model (x being our input images and y being our expected results
# to correct the errors of.) Note that None indicates that dimension can be
# any size.
x = tf.placeholder(tf.float32, [None, 784])
y = tf.placeholder(tf.float32, [None, 10])

# Our weights and variables however are variables since
# they will be modified during our calculations when we are training.
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

# Predict our outputs.
prediction = tf.nn.softmax(tf.matmul(x, W) + b)

# Calculate our cost for the model (how wrong we were).
cost = tf.reduce_mean(-tf.reduce_sum(y * tf.log(prediction), reduction_indices=[1]))
# Then create a training step that we run to correct this (e.g. minimize the cost amount).
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cost)

# Create our TensorFlow session and initialize all of our variables.
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()

# Start by training the model 1000 rounds grabbing 100 training
# examples during each round.
for _ in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={x: batch_xs, y: batch_ys})

# Finally, calculate our accuracy and print it out.
# We do this by using tf.argmax to compare values, which
# finds the highest value in our vector and returns its index.
# E.g. If our vector is [0, 0, 0, 1, 0, 0, 0, 0, 0, 0] then it returns 3.
correct_prediction = tf.equal(tf.argmax(prediction, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print("======================")
print("======================")
print("Accuracy: {}".format(sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels}) * 100))
print("======================")
print("======================")


from flask import Flask, render_template, send_file, make_response, url_for, Response, request, redirect
app = Flask(__name__)
import pandas as pd

import io
import geopandas as gpd
import contextily
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

regioni = gpd.read_file("/workspace/Flask/correzioneVer2/correzioneFilaA2/files/Reg01012021_g_WGS84.dbf")
province = gpd.read_file("/workspace/Flask/correzioneVer2/correzioneFilaA2/files/ProvCM01012021_g_WGS84.dbf")
ripartizioni = gpd.read_file("/workspace/Flask/correzioneVer2/CorrezioneFilaB2/files/georef-italy-ripartizione-geografica.geojson")

@app.route('/', methods=['GET'])
def HomeP():
    return render_template("home.html")

@app.route('/inserimento', methods=['GET'])
def inserimento():
    return render_template("inserimento.html")

@app.route('/datiinput', methods=['GET'])
def datiinput():
    # prendo il valore
    regioneins = request.args["regione"]
    global regioneWgeom
    # cerco il valore nel dataframe
    regioneWgeom = regioni[regioni.DEN_REG.str.contains(regioneins)]
    # misuro la lunghezza del confine
    Lconfine = regioneWgeom.Shape_Leng
    LconfineKm = Lconfine/1000
    # individuo le province dentro la regione
    provinceinreg = province[province.within(regioneWgeom.geometry.squeeze())]
    return render_template("rispostainserimento.html", confine = LconfineKm, tabella = provinceinreg.sort_values(by ="Shape_Area", ascending = False).to_html())

@app.route('/img.png', methods=['GET'])
def img():
    fig, ax = subplots(figsize(12,8))
    regioneWgeom.to_crs(epsg = 3857).plot(ax=ax, edgecolor = "red", facecolor = "none")
    contextily.add_basemap(ax=ax)
    output = io.BytesIO()
    FigureCanvas(fig.print_png(output))
    return Response(output.getvalue(), mimetype = "image/png")

@app.route('/scelta', methods=['GET'])
def scelta():
    return render_template("sceltarip.html", rip = ripartizioni.rip_name)

@app.route('/sceltaripartizione', methods=['GET'])
def sceltaripartizione():
    rip_scelto = request.args["ripartizione"]
    #
    rip_geom = ripartizioni[ripartizioni.rip_name == rip_scelto]
    reginrip = regioni[regioni.within(rip_geom.geometry.squeeze())]
    return render_template("sceltareg.html", reg = reginrip.DEN_REG.sort_values(by="DEN_REG", ascending = True))

@app.route('/selezionereg', methods=['GET'])
def selezionereg():
    return redirect("/datiinput")

@app.route('/sceltalink', methods=['GET'])
def sceltalink():
    return render_template("sceltalink.html", ripa = ripartizioni.rip_name)

@app.route('/sceltareg', methods=['GET'])
def sceltareg():
    rip_scelto = request.args["ripscelto"]
    ripartizione = ripartizioni[ripartizioni.rip_name == rip_scelto]
    regioniinripa = regioni[regioni.within(ripartizione.geometry.squeeze())]
    return render_template("sceltareg2.html", reg = regioniinripa.DEN_REG)

@app.route('/risposta', methods=['GET'])
def risposta():
    return redirect("/datiinpit")

if __name__ == '__main__':
  app.run(host='0.0.0.0', port=3245, debug=True)


'''
아이디어 : 길이 순으로 정렬한 바로 다음에 오는 집합과의 차집합을 이용해서
새로 추가된 애들을 추가하면서 가장 마지막에 완성된 리스트를 반환하자
'''
def solution(s_list):
    answer = []
    set_list = []
    s_list = s_list[1:-1]
    for s in s_list:
        if s == '{': # 숫자 받을 준비
            str_int = [] # 숫자 담을 리스트
            tmp = [] # 튜플로 만들기 위해 완성된 숫자들을 담을 리스트
            continue
        elif s == '}':
            if len(str_int) == 1: # 받은 숫자가 한자리 일 때
                tmp.extend(str_int) # 튜플의 한 요소로 넣어줌
            else: # 받은 숫자가 한자리 수가 아닐 때
                str_int = list(map(str, str_int))
                str_int = ''.join(str_int)
                tmp.extend([int(str_int)])
            set_list.append(tmp)
            str_int = []
        elif s == ',':
            if len(str_int) == 0: # 튜플과 튜플 사이에 있는 , 일때
                continue
            else: # 하나의 튜플 안에서 값들을 나누기 위한 , 일때
                if len(str_int) == 1:
                    tmp.extend(str_int)
                else:
                    str_int = list(map(str, str_int))
                    str_int = ''.join(str_int)
                    tmp.extend([int(str_int)])
                str_int = []
                continue
        else:
            str_int.append(int(s))
    set_list = sorted(set_list, key=lambda x : len(x)) # 길이 순으로 정렬해줌
    for s in set_list:
        if len(answer) == 0:
            answer.append(s)
        else:
            value = set(s) - set(answer[-1])
            answer.append(answer[-1]+list(value))
    return answer[-1]

solution("{{2},{2,1},{2,1,3},{2,1,3,4}}")
solution("{{20,111},{111}}")


from rest_framework.serializers import ModelSerializer
from base.models import MangaTitle, MangaAuthor, Genre

class MangaAuthorSerializer(ModelSerializer):
    class Meta:
        model = MangaAuthor
        fields = '__all__'

class GenreSerializer(ModelSerializer):
    class Meta:
        model = Genre
        fields = '__all__'

class MangaTitleSerializer(ModelSerializer):
    authors = MangaAuthorSerializer(many=True, read_only=True)
    genres = GenreSerializer(many=True, read_only=True)

    class Meta:
        model = MangaTitle
        fields = '__all__'


from pptx import Presentation

prs = Presentation("自動化建立PPT簡報.pptx")
# 新增標題和內容頁投影片
title_content_slide_layout = prs.slide_layouts[1]
slide = prs.slides.add_slide(title_content_slide_layout)
title = slide.shapes.title
title.text = "自動化建立文字內容和清單"
body_shape = slide.placeholders[1]
tf = body_shape.text_frame
tf.text = "Python辦公室自動化套件"
p = tf.add_paragraph()
p.text = "Word自動化"
p.level = 1
p = tf.add_paragraph()
p.text = "python-docx套件"
p.level = 2
p = tf.add_paragraph()
p.text = "Excel自動化"
p.level = 1
p = tf.add_paragraph()
p.text = "openpyxl套件"
p.level = 2
prs.save("自動化建立PPT簡報2.pptx")


import matplotlib.pyplot as plt
# %matplotlib inline
plt.style.use('ggplot')

x = ['Nuclear', 'Hydro', 'Gas', 'Oil', 'Coal', 'Biofuel']
energy = [5, 6, 15, 22, 24, 8]

x_pos = [i for i, _ in enumerate(x)]

plt.bar(x_pos, energy, color='green')
plt.xlabel("Energy Source")
plt.ylabel("Energy Output (GJ)")
plt.title("Energy output from various fuel sources")

plt.xticks(x_pos, x)

plt.show()