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

# Copyright (c) 2014,
# Karlsruhe Institute of Technology, Institute of Telematics
#
# This code is provided under the BSD 2-Clause License.
# Please refer to the LICENSE.txt file for further information.
#
# Author: Mario Hock
#
#
# Acknowledgment:
#
# This code is inspired from and contains some code primitives found in »bwtop«
# written by "Mahmoud Adel <mahmoud.adel2@gmail.com>" and distributed under
# the MIT license.
#
# For more information about »bwtop« please refer to its project site:
# https://github.com/mahmoudadel2/bwtop

'''
Curses display for »cpunetlog«.

'''
import curses
import time
import helpers

## XXX disable colors
disablecolorskipped = True

stdscr = None

## some "constants"/preferences
nics = None
nic_speeds = None
divisor = 1000000.0
rounding_digits = 2
unit = "MBits"

EXISTING_NIC_SPEEDS = [ x * 1000000 for x in (10, 100, 1000, 10000) ]   # in bit/s

LOGGING_STATE_COLORS = {"Active": 3, "(Active)": 2, "Disabled": 1, "Standby": 4, "Enabled": 3}

CPU_TYPE_LABELS = { "user": "user: ",
                    "nice": "nice: ",
                    "system": "system: ",
                    "idle": "idle: ",
                    "iowait": "iowait: ",
                    "irq": "irq: ",
                    "softirq": "sftirq: ",
                    "steal": "steal: ",
                    "guest": "guest: ",
                    "guest_nice": "g_nice: " }

## Reference to the logging manager, to display its state.
logging_manager = None

## GUI, positions of fields
LABEL_Sent = 18
LABEL_Received = 48
LABEL_CPU_UTIL = LABEL_Sent
LABEL_CPU_1 = LABEL_Received-1
LABEL_CPU_2 = 63

COMMENT_WIDTH = 66

## TODO ideas..
#   - Add an option to set a fixed max. net-speed manually (for comparison)
#       --> Maybe change colors, when speed higher than this max
#           (and switch to a scale with the real max. value for the nic.)
#
#   - total (GB transferred)
#   - "Total" field for CPU usage (as well)
#   - Also draw a bar for the totals?

## TODO idea: smoothing..?

def reset_nic_speeds():
    """
      Resets the maximum NIC-speed of all devices to a minimum.

      Note: The maximum will subsequently be adjusted by the function "adjust_nic_speeds".
    """

    for x in nic_speeds:
        nic_speeds[x] = EXISTING_NIC_SPEEDS[0]

def adjust_nic_speeds(send, receive, nic):
    """
      Adjust the maximum speed of the NIC, if it was detected wrong
    """
    global nic_speeds

    MARGIN = 1000   # +1 kbit/s just to be sure..
    #MARGIN = 0

    cur = max(send, receive)

    if ( cur > nic_speeds[nic] + MARGIN ):
        new_speed = nic_speeds[nic]
        for x in EXISTING_NIC_SPEEDS:
            if ( cur < x + MARGIN ):
                new_speed = x
                break

        nic_speeds[nic] = new_speed

        ## TODO: maybe change color...

def _format_net_speed(speed):
    return str( round(speed / divisor, rounding_digits) )

def _calculate_net_ratio( cur_speed, max_speed ):
    ratio = cur_speed / max_speed

    ratio = min( ratio, 1.0 )
    ratio = max( ratio, 0.0 )

    return ratio

def _display_cpu_bar(y, x, cpu):
    # Constants
    CPU_BAR_COLORS = ( curses.color_pair(3) | curses.A_REVERSE,    # user
                       curses.color_pair(4) | curses.A_REVERSE,    # system
                       curses.color_pair(5) | curses.A_REVERSE,    # irq / softirq
                       curses.color_pair(6) | curses.A_REVERSE,    # other
                       curses.color_pair(3) )                      # idle

    # Calculate proportions
    cpu_util = 100-cpu.idle
    other = 100 - sum( (cpu.user, cpu.system, cpu.irq, cpu.idle) )
    proportions = [cpu.user, cpu.system, cpu.irq, other, cpu.idle]

    # Prepare text.
    text = '{0:.2%}'.format((cpu_util)/100.0)
    split_text = helpers.split_proprtionally(text, proportions, 20)

    # Write text on screen (curses).
    stdscr.move(y,x)
    for s, options in zip(split_text, CPU_BAR_COLORS):
        stdscr.addstr(s, options)

def _display_logging_state(y, x):
    if ( not logging_manager ):
        stdscr.addstr(y, x, 'Disabled', curses.A_BOLD)

    else:
        state = logging_manager.get_logging_state()
        color = LOGGING_STATE_COLORS[state]

        stdscr.addstr(y, x, state, curses.A_BOLD | curses.color_pair(color))

def init():
    global stdscr
    global nic_speeds

    if not nic_speeds:
        nic_speeds = helpers.get_nic_speeds()

    stdscr = curses.initscr()
    curses.noecho()
    curses.cbreak()
    stdscr.keypad(True)
    curses.curs_set(False)
    stdscr.nodelay(True)

    curses.start_color()
    curses.use_default_colors()
    if not disablecolorskipped:
        curses.init_pair(1, -1, -1)
        curses.init_pair(2, -1, -1)
        curses.init_pair(3, -1, -1)
        curses.init_pair(4, -1, -1)
    else:
        curses.init_pair(1, curses.COLOR_MAGENTA, -1)         # "CPUX", "ethX"
        curses.init_pair(2, curses.COLOR_BLUE, -1)            # "util", "sent", "received", ...
        curses.init_pair(3, curses.COLOR_GREEN, -1)           # <values>
        curses.init_pair(4, curses.COLOR_YELLOW, -1)          # "Total", (<cpu-system> ?)
        curses.init_pair(5, curses.COLOR_CYAN, -1)            # <cpu-system> / <cpu-other>
        curses.init_pair(6, curses.COLOR_WHITE, -1)           # <cpu-system> / <cpu-other>
        curses.init_pair(7, curses.COLOR_RED, -1)

    ## Show some output to avoid upsetting the user
    try:
        stdscr.addstr(3, 3, "loading ...", curses.A_BOLD)
        stdscr.refresh()
    except:
        print( "\nDisplay Error! (Check terminal-size)" )

def display(measurement):
    try:
        return _display(measurement)
    except:
        print( "\nDisplay Error! (Check terminal-size)" )

        return True

def _display(measurement):
    global stdscr

    ## Press 'q' to quit.
    pressedkey = stdscr.getch()
    if pressedkey == ord('q'):
        return False
    elif pressedkey == ord('-'):
        reset_nic_speeds()

    ## Header
    stdscr.clear()
    stdscr.border(0)
    timenow = time.strftime("%H:%M:%S")
    stdscr.addstr(1, 1, 'CPUnetLOG', curses.A_BOLD)
    stdscr.addstr(1, LABEL_Sent, 'Time: {}'.format( timenow ), curses.A_BOLD)
    stdscr.addstr(1, 39, 'Interval: {}s'.format( round(measurement.timespan, 1) ), curses.A_BOLD)
    stdscr.addstr(1, 62, 'Logging: ', curses.A_BOLD)
    _display_logging_state(1, 71)
    stdscr.refresh()

    y = 3

    ## CPU ##
    num=1
    for cpu in measurement.cpu_times_percent:
        # static labels
        stdscr.addstr(y, 1, 'CPU{0}'.format( num ), curses.color_pair(1))
        stdscr.addstr(y, LABEL_CPU_UTIL, 'util: ', curses.color_pair(2))
        stdscr.addstr(y, LABEL_CPU_UTIL+26, '|', curses.color_pair(2))
        #stdscr.addstr(y, LABEL_CPU_USER, 'type: ', curses.color_pair(2))
        #stdscr.addstr(y, LABEL_CPU_SYSTEM, 'system: ', curses.color_pair(2))

        # CPU bar
        _display_cpu_bar( y, LABEL_CPU_UTIL+6, cpu )

        # user/system
        cpu_sorted = helpers.sort_named_tuple(cpu, skip="idle")
        t = '{0: >8}'.format( CPU_TYPE_LABELS[cpu_sorted[0][0]] )
        stdscr.addstr(y, LABEL_CPU_1, t, curses.color_pair(4))
        stdscr.addstr("{:>5.2f}%".format(cpu_sorted[0][1]), curses.color_pair(3))

        t = '{0: >8}'.format( CPU_TYPE_LABELS[cpu_sorted[1][0]] )
        stdscr.addstr(y, LABEL_CPU_2, t, curses.color_pair(4))
        stdscr.addstr("{:>5.2f}%".format(cpu_sorted[1][1]), curses.color_pair(3))

        num += 1
        y += 1

    ## Network ##

    y += 1
    stdscr.hline(y, 1, "-", 78)
    y += 1

    # display all nics (if not set otherwise)
    if nics:
        active_nics = nics
    else:
        active_nics = measurement.net_io.keys()

    sum_sending = 0
    sum_receiving = 0

    ## display the values
    for nic in sorted(active_nics):
        values = measurement.net_io[nic]

        _send = values.ratio["bytes_sent"] * 8  # Bits/s
        _recv = values.ratio["bytes_recv"] * 8  # Bits/s

        ## TESTING increase inc_speed, if throughput is higher than (expected) maximum
        adjust_nic_speeds(_send, _recv, nic)

        sending = _format_net_speed( _send )
        send_ratio = _calculate_net_ratio( _send, nic_speeds[nic] )
        receiving = _format_net_speed( _recv )
        receive_ratio = _calculate_net_ratio( _recv, nic_speeds[nic] )

        sum_sending += _send
        sum_receiving += _recv

        stdscr.addstr(y, 1, '{0}'.format(nic), curses.color_pair(1))
        stdscr.addstr(y, LABEL_Sent, 'Sent: ', curses.color_pair(2))
        stdscr.addstr(y, LABEL_Sent+26, "|", curses.color_pair(2))
        stdscr.addstr(y, LABEL_Received, 'Received: ', curses.color_pair(2))
        stdscr.addstr(y, LABEL_Received+30, "|", curses.color_pair(2))

        ## TODO rewrite in nice ^^ [see _display_cpu_bar()]
        ## XXX prototypical "inline"-coloring
        _snd_str = '{0} {1}/s'.format(sending, unit, send_ratio)
        _snd_str += " " * (20-len(_snd_str))
        _load_len = int(send_ratio * 20)
        stdscr.addstr(y, LABEL_Sent+6, _snd_str[0:_load_len], curses.color_pair(3)|curses.A_REVERSE)
        stdscr.addstr(y, LABEL_Sent+6+_load_len, _snd_str[_load_len:], curses.color_pair(3))

        _recv_str = '{0} {1}/s'.format(receiving, unit, send_ratio)
        _recv_str += " " * (20-len(_recv_str))
        _load_len = int(receive_ratio * 20)
        stdscr.addstr(y, LABEL_Received+10, _recv_str[0:_load_len], curses.color_pair(3)|curses.A_REVERSE)
        stdscr.addstr(y, LABEL_Received+10+_load_len, _recv_str[_load_len:], curses.color_pair(3))

        ## XXX TESTING
        #y += 1
        #stdscr.addstr(y, 25, "|" + " "*20 + "|", curses.color_pair(2))
        #stdscr.addstr(y, 26, " " * int(send_ratio * 20), curses.color_pair(3)|curses.A_REVERSE)
        #stdscr.addstr(y, 59, "|" + " "*20 + "|", curses.color_pair(2))
        #stdscr.addstr(y, 60, " " * int(receive_ratio * 20), curses.color_pair(3)|curses.A_REVERSE)

        y += 1

    ## Total
    y+=1
    stdscr.addstr(y, 1, 'Total:', curses.color_pair(4))
    stdscr.addstr(y, LABEL_Sent, 'Sent:', curses.color_pair(2))
    stdscr.addstr(y, LABEL_Sent+6, '{0} {1}/s'.format(_format_net_speed(sum_sending), unit), curses.color_pair(3))
    stdscr.addstr(y, LABEL_Received, 'Received:', curses.color_pair(2))
    stdscr.addstr(y, LABEL_Received+10, '{0} {1}/s'.format(_format_net_speed(sum_receiving),unit), curses.color_pair(3))

    ## Show logging comment
    comment = logging_manager.get_logging_comment()
    if ( comment ):
        y += 3
        stdscr.addstr(y, 3, 'Comment: ', curses.A_BOLD)

        parts = ( comment[i:i+COMMENT_WIDTH] for i in range(0, len(comment), COMMENT_WIDTH) )
        for part in parts:
            stdscr.addstr(y, 3+9, part)
            y += 1

    stdscr.refresh()

    return True

def close():
    global stdscr

    curses.nocbreak()
    stdscr.keypad(False)
    curses.echo()
    curses.curs_set(True)
    curses.endwin()


#!/usr/bin/env python
# -*- coding: utf-8 -*-

try:
    from setuptools import setup
except ImportError:
    from distutils.core import setup
import os
import sys

if sys.argv[-1] == 'cheeseit!':
    os.system('python setup.py sdist upload')
    sys.exit()
elif sys.argv[-1] == 'testit!':
    os.system('python setup.py sdist upload -r test')
    sys.exit()

with open("README.rst") as f:
    readme = f.read()

setup(
    name="toolshed",
    version='0.1.0',
    description='Autodesk Maya tools',
    long_description=readme,
    author='Dan Bradham',
    author_email='danielbradham@gmail.com',
    url='http://github.com/danbradham/toolshed.git',
    license='MIT',
    packages=('toolshed',),
    package_data={'': ['LICENSE', 'README.rst'],'toolshed': [],},
    package_dir={'toolshed': 'toolshed'},
    include_package_data=True,
    classifiers=(
        "Development Status :: 3 - Alpha",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Natural Language :: English",
        "Operating System :: OS Independent",
        "Programming Language :: Python",
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 3',
    ),
)


from win32api import *
from win32gui import *
import win32con
import sys, os
import struct
import time

# Register the Window class.
wc = WNDCLASS()
hinst = wc.hInstance = GetModuleHandle(None)
wc.lpszClassName = "PythonTaskbar"
classAtom = RegisterClass(wc)

def ballun(title, msg):
        # Create the Window.
        style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
        hwnd = CreateWindow( classAtom, "Taskbar", style, \
                0, 0, win32con.CW_USEDEFAULT, win32con.CW_USEDEFAULT, \
                0, 0, hinst, None)
        UpdateWindow(hwnd)
        iconPathName = os.path.abspath(os.path.join( sys.path[0], "balloontip.ico" ))
        icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
        try:
           hicon = LoadImage(hinst, iconPathName, \
                    win32con.IMAGE_ICON, 0, 0, icon_flags)
        except:
          hicon = LoadIcon(0, win32con.IDI_APPLICATION)
        flags = NIF_ICON | NIF_MESSAGE | NIF_TIP
        nid = (hwnd, 0, flags, win32con.WM_USER+20, hicon, "tooltip")
        Shell_NotifyIcon(NIM_ADD, nid)
        Shell_NotifyIcon(NIM_MODIFY, \
                         (hwnd, 0, NIF_INFO, win32con.WM_USER+20,\
                          hicon, "Balloon  tooltip",msg,200,title))
        # self.show_balloon(title, msg)
        time.sleep(10)
        DestroyWindow(hwnd)
        nid = (hwnd, 0)
        Shell_NotifyIcon(NIM_DELETE, nid)
        PostQuitMessage(0) # Terminate the app.


import requests
url = 'https://goo.gl/w9Vkp7'
html = requests.get(url)
html.encoding = "UTF-8"

htmllist = html.text.splitlines()
n = 0
x = str(input("請輸入你要找的關鍵字: "))

for row in htmllist:
    if x in row: n+1
print("找到{}次!!".format(n))


# mongo.py
#TODO: change md_covid_data --> md_county_covid_data
#dont put data if obj already exists
#change names to match county names in other json file
from flask import Flask
from flask import jsonify
from flask import request
from flask_pymongo import PyMongo
from flask_cors import CORS, cross_origin
import json
app = Flask(__name__)
app.config['CORS_HEADERS'] = 'Content-Type'
mongo_covid = PyMongo(app, uri="mongodb://localhost:27017/md_covid_data")
mongo_prison = PyMongo(app, uri="mongodb://localhost:27017/prison_data")
mongo_us_covid = PyMongo(app, uri="mongodb://localhost:27017/us_counties_covid_data")
mongo_prison_covid =  PyMongo(app, uri="mongodb://localhost:27017/prison_covid_data")
cors = CORS(app)

#get prison covid data by date
#date needs to be formatted like this:YYYY-MM-DD
@app.route('/get_prison_covid_data_by_date/<date>/', methods=['GET'])
def get_prison_covid_data_by_date(date):
  result = []
  doc = mongo_prison_covid.db.prison_covid_data

  for i in doc.find({'date':date}):
    print(i)
    result.append(i)

  return json.dumps(result, default=str)
#post covid prison data
@app.route('/prison_covid_data.json', methods=['POST'])
def post_prison_covid_data():
  data = json.loads(request.get_json())
  data = data["data"]
  doc = mongo_prison_covid.db.prison_covid_data
  count = 0

  for i in data:
    print(i)
    date  = i['date']
    facility_type = i['facility_type']
    state = i['state']
    canonical_facility_name = i['canonical_facility_name']
    pop_tested = i['pop_tested']
    pop_tested_positive = i['pop_tested_positive']
    pop_tested_negative = i['pop_tested_negative']
    pop_deaths = i['pop_deaths']
    pop_recovered = i['pop_recovered']
    staff_tested = i['staff_tested']
    staff_tested_positive = i['staff_tested_positive']
    staff_tested_negative = i['staff_tested_negative']
    staff_deaths = i['staff_deaths']
    staff_recovered = i['staff_recovered']
    source = i['source']
    compilation = i['compilation']
    notes = i['notes']

    doc.insert({"date":date,\
                 "facility_type":facility_type,\
                 "state":state,\
                 "canonical_facility_name":canonical_facility_name,\
                 "pop_tested":pop_tested,\
                 "pop_tested_positive":pop_tested_positive,\
                 "pop_tested_negative":pop_tested_negative,\
                 "pop_deaths":pop_deaths,\
                 "pop_recovered":pop_recovered,\
                 "staff_tested":staff_tested,\
                 "staff_tested_positive":staff_tested_positive,\
                 "staff_tested_negative":staff_tested_negative,\
                 "staff_deaths":staff_deaths,\
                 "staff_recovered":staff_recovered,\
                 "source":source,\
                 "compilation":compilation,\
                 "notes":notes})
    count += 1
  print(count)
  return jsonify({'num_entries': count});

#post national covid data
@app.route('/us_counties_covid_data.json', methods=['POST'])
def post_national_covid_data():
  data = json.loads(request.get_json())
  data = data["data"]
  doc = mongo_us_covid.db.us_counties_covid_data
  count = 0
  for i in data:
    print(i)
    #input()

    date = i['date']
    county = i['county']
    state = i['state']
    fips = i['fips']
    cases = int(i['cases'])
    deaths = int(i['deaths'])
    x = doc.insert( {"date": date, \
                 "county":county, "state":state, \
                 "fips":fips, "cases":cases, \
                 "deaths":deaths})
    count += 1
  print(count)
  return jsonify({'num_entries': count});

#get by date
#date needs to be formatted like this:YYYY-MM-DD
@app.route('/get_us_data_by_date/<date>/', methods=['GET'])
def get_us_counties_covid_data_by_date(date):
  result = []
  doc = mongo_us_covid.db.us_counties_covid_data
  for i in doc.find({'date':date}):
    print(i)
    result.append(i)
  return json.dumps(result, default=str)

#get by obj_id
@app.route('/get_by_id/<obj_id>', methods=['GET'])
def get_by_obj_id(obj_id):

  obj_id = int(obj_id)
  covid_data = mongo_covid.db.md_covid_data
  result = covid_data.find_one({'obj_id' : obj_id})
  print(result)

  if result:
    output = result
  else:
    output = "No document found"

  return json.dumps(output, default=str)

@app.route('/md_covid_data.json', methods=['POST'])
def add_data():
  #each feature contains (new?) covid case counts for a single day, from each county
  data = json.loads(request.get_json())
  features = (data['features'])
  count = 0
  for i in features:
    print(i['properties'])
    print(type(i['properties']))
    #each feature should be a document in db
    #{'OBJECTID': 204, 'DATE': '2020/10/04 14:00:00+00', 'Allegany': 492, 'Anne_Arundel': 10376, 'Baltimore': 18354, 'Baltimore_City': 15954, 'Calvert': 1005, 'Caroline': 662, 'Carroll': 2003, 'Cecil': 1120, 'Charles': 2851, 'Dorchester': 614, 'Frederick': 4191, 'Garrett': 76, 'Harford': 3141, 'Howard': 5234, 'Kent': 309, 'Montgomery': 22976, 'Prince_Georges': 30004, 'Queen_Annes': 680, 'Somerset': 299, 'St_Marys': 1343, 'Talbot': 578, 'Washington': 1861, 'Wicomico': 2085, 'Worcester': 1082, 'Unknown': 0}
    i = i['properties']
    doc = mongo_covid.db.md_covid_data
    obj_id = i['OBJECTID']
    date = i['DATE']
    allegany = i['Allegany']
    anne_arundel = i['Anne_Arundel']
    baltimore = i['Baltimore']#double check
    baltimore_city = i['Baltimore_City']
    calvert = i['Calvert']
    caroline = i['Caroline']
    carroll = i['Carroll']
    cecil = i['Cecil']
    charles = i['Charles']
    dorchester = i['Dorchester']
    frederick = i['Frederick']
    garrett = i['Garrett']
    harford = i['Harford']
    howard = i['Howard']
    kent = i['Kent']
    montgomery = i['Montgomery']
    prince_georges = i['Prince_Georges']
    queen_annes = i['Queen_Annes']
    st_marys = i['St_Marys']
    somerset = i['Somerset']
    talbot = i['Talbot']
    washington = i['Washington']
    wicomico = i['Wicomico']
    worcester = i['Worcester']
    unknown = i['Unknown']

    doc.insert({'obj_id':obj_id, 'date':date,
                'counties':{
    'allegany':allegany,\
    'anne arundel':anne_arundel,\
    'baltimore':baltimore, \
    'baltimore city':baltimore_city, \
    'calvert':calvert, \
    'caroline':caroline,\
    'carroll':carroll,\
    'cecil':cecil,\
    'charles':charles,\
    'dorchester':dorchester,\
    'frederick':frederick, \
    'garrett':garrett, \
    'harford':harford,\
    'howard':howard,\
    'kent':kent, \
    'montgomery':montgomery,\
    'prince george\'s':prince_georges, \
    'queen anne\'s':queen_annes,\
    'st mary\'s':st_marys,\
    'somerset':somerset,\
    'talbot':talbot,\
    'washington':washington,\
    'wicomico':wicomico, \
    'worcester':worcester, \
                  'unknown': unknown}})

    count += 1

  return jsonify({'num_entries': count});

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

    json_file = json.loads(request.get_json())

    data = (json_file['data'])

    count = 0
    for i in data:
        print(i)
        #{'name': 'Alabama', '
        #county': 'Autauga County',
        #'tract': '020200',
        #'block': '2008',
        #'correctional_population': '181',
        #'facility_name': 'Autauga Metro Jail', '
        #facility_type': 'Local',
        #'wrong_block': '',
        #'comment': ''}
        name = i['name']
        county = i['county']
        tract = i['tract']
        block = i['block']
        correctional_population = i['correctional_population']
        facility_name = i['facility_name']
        facility_type = i['facility_type']
        wrong_block = i['wrong_block']
        comment = i['comment']

        doc = mongo_prison.db.prison_data

        doc.insert({"name":name,\
        "county":county,\
        "tract":tract,\
        "block": block, \
        "correctional_population":int(correctional_population),\
        "facility_name":facility_name,
        "facility_type":facility_type,
        "wrong_block":wrong_block,
        "comment":comment
        })

        count+=1

    return jsonify({'num_entries': count});

if __name__ == '__main__':
    app.run(debug=True)


from flask import Flask
import os
application = Flask(__name__)

@application.route('/')
def hello_world():
    db_name = os.environ['DATABASE_NAME']
    return "Hello World. My database name is: "+db_name

if __name__ == '__main__':
    application.run()


"""Package containing the class which controls the Fighter Aircraft weight functions"""
import math

from Rapid.RapidMass.raymer import aircraft_info

class FighterWeight:
    """Class which holds the calculations for Raymer's Fighting equations"""

    def __init__(self):
        """Function to initialise the class"""
        self.data = aircraft_info.aircraft_data

        self.estimates = {
            "wing": self.wing(),
            "htp": self.htp(),
            "vtp": self.vtp(),
            "fuselage": self.fuselage(),
            "landing_gear": self.main_landing_gear() + self.nose_landing_gear(),
            "air_induction": self.air_induction_system(),
            "fuel_system": self.fuel_system_and_tanks(),
            "engine_controls": self.engine_controls(),
            "starter": self.starter(),
            "instruments": self.instruments(),
            "electrical": self.electrical(),
            "hydraulics_and_pneumatics": self.flight_controls() + self.hydraulics(),
            "furnishings": self.furnishings(),
            "air_conditioning_and_anti_ice": self.air_conditioning_and_anti_ice(),
            "avionics": self.avionics(),
            "braking": 0,
            "nacelle_group": 0,
            "apu": 0,
            "engine_mounts": self.engine_mounts(),
            "firewall": self.firewall(),
            "engine_section": self.engine_section(),
            "tailpipe": self.tailpipe(),
            "cooling": self.engine_cooling() + self.oil_cooling(),
            "installed_engine": 0
        }

        self.total = sum([self.estimates[category] for category in self.estimates.keys()])

    def wing(self):
        """Function to calculate wing weight"""
        weight = 0.0103 * \
            self.data['is_delta_wing'] * \
            self.data['is_variable_sweep'] * \
            (self.data['flight_design_gross_weight']*self.data['ultimate_load_factor'])**0.5 * \
            self.data['trapezoidal_wing_area']**0.622 * \
            self.data['aspect_ratio']**0.785 * \
            self.data['thickness_to_chord_ratio']**-0.4 * \
            (1 + self.data['taper_ratio'])**0.05 * \
            (math.cos(self.data['wing_sweep']))**-1.0 * \
            self.data['control_surface_area']**0.04
        return weight

    def htp(self):
        """Function to calculate htp weight"""
        weight = 3.316 * (1 + (
            self.data['fuselage_width_at_horizontal_tail_intersection'] / self.data['horizontal_tail_span']
        )
                          )**-2.0 * \
            (
                (
                     self.data['flight_design_gross_weight'] * self.data['ultimate_load_factor']
                  ) / 1000.
            )**0.260 * \
            self.data['horizontal_tail_area']**0.806
        return weight

    def vtp(self):
        """Function to calculate vtp weight"""
        weight = 0.452*self.data['is_rolling_horizontal_tail'] * \
            (
                1 + self.data['horizontal_over_vertical_tail_height_above_fuselage']
            )**0.5 * \
            (
                self.data['flight_design_gross_weight'] * self.data['ultimate_load_factor']
            )**0.488 * \
            self.data['vertical_tail_area'] ** 0.718 * \
            self.data['mach_number']**0.341 * \
            self.data['tail_length']**-1.0 * \
            (
                1 + self.data['rudder_area']/self.data['vertical_tail_area']
            )**0.348 * \
            self.data['vtp_aspect_ratio']**0.223 * \
            (1 + self.data['vtp_taper_ratio']) ** 0.25 * \
            (math.cos(self.data['vtp_sweep'])) ** -0.323
        return weight

    def fuselage(self):
        """Function to calculate fuselage weight"""
        weight = 0.499 * self.data['is_delta_wing_aircraft'] * \
            self.data['flight_design_gross_weight']**0.35 * \
            self.data['ultimate_load_factor']**0.25 * \
            self.data['fuselage_structural_length']**0.5 * \
            self.data['fuselage_structural_depth']**0.849 * \
            self.data['total_fuselage_structural_width']**0.685
        return weight

    def main_landing_gear(self):
        """Function to calculate main gear weight"""
        weight = self.data['is_cross_beam'] * \
            self.data['is_tripod'] * \
            (self.data['landing_design_gross_weight'] * self.data['ultimate_landing_load_factor'])**0.25 * \
            self.data['extended_length_of_main_landing_gear']**0.973
        return weight

    def nose_landing_gear(self):
        """Function to calculate nose gear weight"""
        weight = (self.data['landing_design_gross_weight'] * self.data['ultimate_landing_load_factor'])**0.290 * \
            self.data['extended_nose_gear_length']**0.5 * \
            self.data['number_of_nosewheels']**0.525
        return weight

    def engine_mounts(self):
        """Function to calculate engine mounts weight"""
        weight = 0.013 * self.data['number_of_engines'] * \
            self.data['total_engine_thrust']**0.579 * \
            self.data['ultimate_load_factor']
        return weight

    def firewall(self):
        """Function to calculate firewall weight"""
        weight = 1.13 * self.data['firewall_surface_area']
        return weight

    def engine_section(self):
        """Function to calculate engine section weight"""
        weight = 0.01 * self.data['engine_weight']**0.717 * \
            self.data['number_of_engines'] * \
            self.data['ultimate_load_factor']
        return weight

    def air_induction_system(self):
        """Function to calculate air induction system weight"""
        weight = 13.29 * self.data['is_variable_geometry'] * \
            self.data['duct_length']**0.643 * \
            self.data['duct_constant']**0.182 * \
            self.data['number_of_engines']**1.498 * \
            (
                self.data['single_duct_length'] / self.data['duct_length']
            )**-0.3373 * \
            self.data['engine_diameter']
        return weight

    def tailpipe(self):
        """Function to calculate tailpipe weight"""
        weight = 3.5 * self.data['engine_diameter'] * \
            self.data['tail_length'] * \
            self.data['number_of_engines']
        return weight

    def engine_cooling(self):
        """Function to calculate engine cooling weight"""
        weight = 4.55 * self.data['engine_diameter'] * \
            self.data['length_of_engine_shroud'] * \
            self.data['number_of_engines']
        return weight

    def oil_cooling(self):
        """Function to calculate oil cooling weight"""
        weight = 37.82 * self.data['number_of_engines']**1.023
        return weight

    def engine_controls(self):
        """Function to calculate engine controls weight"""
        weight = 10.5 * self.data['number_of_engines']**1.008 * \
            self.data['length_from_engine_front_to_cockpit_total']**0.222
        return weight

    def starter(self):
        """Function to calculate starter weight"""
        weight = 0.025 * self.data['thrust_per_engine']**0.76 * \
            self.data['number_of_engines']**0.72
        return weight

    def fuel_system_and_tanks(self):
        """Function to calculate fuel system and tank weight"""
        weight = 7.45 * self.data['total_fuel_volume']**0.47 * \
            (
                1 + self.data['integral_tanks_volume']/self.data['total_fuel_volume']
            )**-0.095 * \
            (
                1 + self.data['self_sealing_tanks_volume']/self.data['total_fuel_volume']
            ) * \
            self.data['number_of_fuel_tanks']**0.066 * \
            self.data['number_of_engines']**0.052 * \
            (
                (
                    self.data['total_engine_thrust'] * self.data['sfc_at_max_thrust']
                ) / 1000.
            )**0.249
        return weight

    def flight_controls(self):
        """Function to calculate flight control weight"""
        weight = 36.28 * self.data['mach_number'] ** 0.003 * \
            self.data['control_surface_area']**0.489 * \
            self.data['number_of_flight_control_systems']**0.484 * \
            self.data['number_of_flight_crew']**0.127
        return weight

    def instruments(self):
        """Function to calculate instrument weight"""
        weight = 8.0 + 36.37 * self.data['number_of_engines']**0.676 * \
            self.data['number_of_fuel_tanks']**0.237 + \
            26.4 * (1 + self.data['number_of_crew_equivalents'])**1.356
        return weight

    def hydraulics(self):
        """Function to calculate hydraulics weight"""
        weight = 37.23*self.data['is_variable_sweep'] * \
            self.data['number_of_hydraulic_utility_functions']**0.664
        return weight

    def electrical(self):
        """Function to calculate electrical weight"""
        weight = 172.2 * self.data['is_mission_completion'] * \
            self.data['system_electrical_rating']**0.152 * \
            self.data['number_of_flight_crew']**0.1 * \
            self.data['electrical_routing_distance']**0.1 * \
            self.data['number_of_generators']**0.091
        return weight

    def avionics(self):
        """Function to calculate avionics weight"""
        weight = 2.117 * self.data['uninstalled_avionics_weight']**0.933
        return weight

    def furnishings(self):
        """Function to calculate furnishings weight"""
        weight = 217.6 * self.data['number_of_flight_crew']

        # passengers
        weight += self.data['number_of_passengers'] * 190

        # seats
        weight += self.data['number_of_flight_crew'] * 60
        weight += self.data['number_of_passengers'] * 32

        # instruments - average value used where range given
        weight += self.data['instruments']['cat1'] * 1.5
        weight += self.data['instruments']['cat2'] * 5.
        weight += self.data['instruments']['cat3'] * 40

        # toilets
        weight += 0.31 * self.data['number_of_passengers'] ** 1.33
        return weight

    def air_conditioning_and_anti_ice(self):
        """Function to calculate air conditions and anti ice weight"""
        weight = 201.6 * \
            (
                (
                    self.data['uninstalled_avionics_weight'] + 200*self.data['number_of_flight_crew']
                ) / 1000.
            )**0.735
        return weight


__author__ = 'ryan'

import random
import re
import sys

class Knuth(object):
    """
    The Knuth class provides a client for reading in a sequence of strings and shuffling them using the Knuth
    (or Fisher-Yates) shuffling algorithm. This algorithm guarantees to rearrange the elements in uniformly random
    order, under the assumption that Math.random() generates independent and uniformly distributed numbers between
    0 and 1.
    """
    @staticmethod
    def shuffle(a):
        """
         Rearranges an list of objects in uniformly random order (under the assumption that Math.random() generates
         independent and uniformly distributed numbers between 0 and 1
        :param a: a list of objects to be shuffled
        :return: a shuffled list
        """
        n = len(a)
        for i in range(n):
            r = random.randint(i, n-1)
            a[i], a[r] = a[r], a[i]

def main():
    """
    Reads in a sequence of strings from standard input, shuffles them, and prints out the results.
    :return: None
    """
    in_file = open(sys.argv[1]).read()
    a = in_file.strip()
    a = re.split("\s", a)
    Knuth.shuffle(a)
    for obj in a:
        print(obj)

if __name__ == "__main__":
    main()


import numbers
import matplotlib.pyplot as plt
import numpy as np
import collections
import wandb as wab

class ExperimentTracker:
    """ All-in-one concise experiment tracking after each epoch completion.
    - Tracks all essential iteration and epoch metrics.
    - Automatically logs epoch stats to wandb.
    """

    def __init__(self, metric_names=[], wandb=None):
        self.metrics_d = { k: [] for k in metric_names } if metric_names else {}
        if wandb:
            self.use_wandb = True
            self._setup_wandb(wandb)
        else:
            self.use_wandb = False

    def update(self, metrics_d, wandb=False, verbose=False):
        for k, item in metrics_d.items():
            if k not in self.metrics_d:
                if verbose:
                    print(f" (StatTracker) Adding stat: {k}, Val: {item}")
                self.metrics_d[k] = [item]
                continue
            self.metrics_d[k].append(item)
            if verbose:
                print(f"(StatTracker) Adding {k}: {item}")
        if wandb and self.use_wandb:
            wab.log(metrics_d)

    def best(self, metric_name, max_better=True):
        if metric_name not in self.metrics_d:
            print(f" (ExperimentTracker) Given k({metric_name}) not valid.")
            return None
        metric_hist = self.metrics_d[metric_name]
        return max(metric_hist) if max_better else min(metric_hist)

    def plot(self, keys=None):
        names, vals = [], []
        if keys:
            for k in keys:
                if k not in self.metrics_d:
                    continue
                names.append(k)
                vals.append(self.metrics_d[k])
        else:
            for k, v in self.metrics_d.items():
                if v and not isinstance(v[0], collections.Sequence):
                    names.append(k)
                    vals.append(vals)

        num_cols = 4
        num_rows = len(names) // num_cols + 1
        fig = plt.figure(figsize=(20, 5*num_rows))
        for i, name in enumerate(names):
            ax = fig.add_subplot(num_rows, num_cols, i+1)
            ax.set_title(name)
            ax.plot(vals[i])
        plt.show()

    def _setup_wandb(self, cfg):
        print(" > Initializing Weights and Biases run..")
        name = cfg['experiment']['id'] + '_' + cfg['experiment']['name']
        wab.init(
            name=name,
            project=cfg['experiment']['project'],
            config=cfg,
            notes=cfg['experiment']['description']
        )

class EpochMeters:
    """ Updates every iteration and keeps track of accumulated stats """

    def __init__(self):
        self.accums = {}
        self.ns = {}

    def update(self, metrics_d, n=1):
        for k, item in metrics_d.items():
            if k not in self.accums:
                self.accums[k] = item
                self.ns[k] = n
                continue
            self.accums[k] += item
            self.ns[k] += n

    def avg(self, no_avg=[]):
        ret = {}
        for k, v in self.accums.items():
            if k in no_avg:
                ret[k] = v
            else:
                ret[k] = v/self.ns[k]
        return ret

class BaseStatTracker:

    def __init__(self, stat_names=None):
        self.stats_dict = {k: [] for k in stat_names} if stat_names else {}

    def update(self, update_dict, disp=False):
        for k, item in update_dict.items():
            if k not in self.stats_dict:
                print(f"(StatTracker) Adding stat: {k}, Val: {item}")
                self.stats_dict[k] = [item]
                continue
            self.stats_dict[k].append(item)
            if disp:
                print(f"(StatTracker) Adding {k}: {item}")

    def reset(self, keys=None):
        for sk in self.stats_dict:
            if not keys:
                print(f"(StatTracker) Wiping stat: {sk}")
                self.stats_dict[sk] = []
            else:
                for k in keys:
                    if k in sk:
                        print(f"(StatTracker) Wiping stat: {sk}")
                        self.stats_dict[sk] = []

    def print_info(self, print_item=True):
        print(f"(StatTracker) Printing info for {len(self.stats_dict)} stats..")
        for k, v in self.stats_dict.items():
            print(f"   > {k} ({len(v)} items ", end='')
            if len(v) > 0:
                print(f"of type {type(v)})")
                print('    ', v)

    def plot(self, keys=None):
        names, vals = [], []
        if keys:
            for k in keys:
                if k not in self.stats_dict:
                    continue
                names.append(k)
                vals.append(self.stats_dict[k])
        else:
            for k, v in self.stats_dict.items():
                if v and not isinstance(v[0], collections.Sequence):
                    names.append(k)
                    vals.append(vals)

        num_cols = 4
        num_rows = len(names) // num_cols + 1
        fig = plt.figure(figsize=(20, 5*num_rows))
        for i, name in enumerate(names):
            ax = fig.add_subplot(num_rows, num_cols, i+1)
            ax.set_title(name)
            ax.plot(vals[i])
        plt.show()

class AverageMeter:

    def __init__(self, init_val=None):
        self.reset()

    def reset(self):
        self.avg = 0
        self.sum = 0
        self.count = 0

    def update(self, val, n=1):
        if n == 0:
            self.sum += val
            self.count += 1
            self.avg = self.sum
        else:
            self.sum += val * n
            self.count += n
            self.avg = self.sum / self.count

class NAverageMeter:

    def __init__(self, n=1):
        self.n = n
        self.reset()

    def reset(self):
        self.avg = np.array([0.]*self.n)
        self.sum = np.array([0.]*self.n)
        self.count = 0

    def update(self, val, n=1):
        if n == 0:
            self.sum += np.array(val)
            self.count += 1
            self.avg = self.sum
        else:
            self.sum += np.array(val) * n
            self.count += n
            self.avg = self.sum / self.count

# Basic Tests
if __name__ == '__main__':
    import sys

    for epoch in range(1, 20):
        epmeter = EpochMeters()
        for it in range(1, 5):
            epmeter.update({
                'TPs': np.array([1,2,3]),
                'F1': 1.1,
                'F1s': np.array([.2,.4,.6])
            })
        print(epmeter.avg(no_avg=['TPs']))
        sys.exit(0)


###
### Command builder
###
import re
import regex
from lib.utils.FileUtils import FileUtils
from lib.core.Constants import *
from lib.core.SpecificOptions import SpecificOptions

# ---------------------------
# Tags supported in commands:
# ---------------------------
# [IP]			Target IP
# [URL]			Target URL
# [HOST]		Target host
# [PORT]		Target port
# [PROTOCOL]	Protocol tcp/udp
# [SERVICE]		Service name
# [OUTPUT]		Output file
# [OUTPUTDIR] 	Output directory (when tool save results in a directory, e.g. skipfish)
# [TOOLBOXDIR]	Toolbox directory
#
# + specific tags depending on each service, eg. for http:
# [SSL option="value"]					In case SSL should be used, add the specified option. e.g.: [SSL option="--ssl"]
# [CMS cms1="val" cms2="val" ...] 		Option specific to CMS. e.g.: [CMS drupal="--type Drupal" joomla="--type Joomla"]
# [TECHNO techno1="val" techno2="val"]	Option specific to technology. e.g.: [TECHNO php="-l php" asp="-l asp"]
# [SERVER server1="val" server2="val"]	Option specific to server. e.g.: [SERVER apache="--serv apache" tomcat="--serv tomcat"]

class Command(object):

	def __init__(self,
				 directory,
				 raw_cmdline,
				 target,
				 toolbox_dir,
				 output_file,
				 output_dir,
				 service_name,
				 specific_args):

		self.directory	 	= FileUtils.absolute_path(directory)	# directory where the command should be launched
		self.cmdline 	 	= raw_cmdline
		self.target 	 	= target
		self.toolbox_dir 	= FileUtils.absolute_path(toolbox_dir)
		self.output_file 	= output_file
		self.output_dir  	= output_dir
		self.service 	 	= service_name
		self.specific_args 	= specific_args

	def getParsedRunCommandLine(self):
		"""
		Replace tags in a command aimed at running a tool.
		Return the parsed command line, ready to be executed
		"""
		if not self.target or not self.output_file:
			return None

		self.replaceIP()
		self.replaceURL()
		self.replaceHOST()
		self.replacePORT()
		self.replacePROTOCOL()
		self.replaceSERVICE()
		self.replaceOUTPUT()
		self.replaceOUTPUTDIR()
		self.replaceTOOLBOXDIR()
		self.replaceSpecificTags()

		self.cmdline = 'cd {0}; '.format(self.directory) + self.cmdline
		return self.cmdline

	def getParsedInstallCommandLine(self):
		"""
		Replace tags in a command aimed at installing a tool.
		Prefix with cd [tool_dir] to make sure commands will be run in correct context
		Return the parsed command line, ready to be executed
		"""
		self.replaceTOOLBOXDIR()
		self.cmdline = 'cd {0}; '.format(self.directory) + self.cmdline
		return self.cmdline

	def getStandardCommandLine(self):
		"""
		Return a standard command line (without tag)
		"""
		self.cmdline = 'cd {0}; '.format(self.directory) + self.cmdline
		return self.cmdline

	def replaceURL(self):
		"""
		Replace [URL]
		"""
		pattern = re.compile('\[URL\]', re.IGNORECASE)
		self.cmdline = pattern.sub(self.target.url, self.cmdline)

	def replaceHOST(self):
		"""
		Replace [HOST]
		"""
		pattern = re.compile('\[HOST\]', re.IGNORECASE)
		self.cmdline = pattern.sub(self.target.host, self.cmdline)

	def replaceIP(self):
		"""
		Replace [IP]
		"""
		pattern = re.compile('\[IP\]', re.IGNORECASE)
		self.cmdline = pattern.sub(self.target.ip, self.cmdline)

	def replacePORT(self):
		"""
		Replace [PORT]
		"""
		pattern = re.compile('\[PORT\]', re.IGNORECASE)
		self.cmdline = pattern.sub(str(self.target.port), self.cmdline)

	def replacePROTOCOL(self):
		"""
		Replace [PROTOCOL]
		"""
		pattern = re.compile('\[PROTOCOL\]', re.IGNORECASE)
		self.cmdline = pattern.sub(self.target.protocol, self.cmdline)

	def replaceSERVICE(self):
		"""
		Replace [SERVICE]
		"""
		pattern = re.compile('\[SERVICE\]', re.IGNORECASE)
		self.cmdline = pattern.sub(self.target.service, self.cmdline)

	def replaceOUTPUT(self):
		"""
		Replace [OUTPUT] if present
		Else, add at the end of the command: 2>&1 | tee [OUTPUT]
		"""
		pattern = re.compile('\[OUTPUT\]', re.IGNORECASE)
		if pattern.search(self.cmdline):
			self.cmdline = pattern.sub('"{0}"'.format(self.output_file), self.cmdline)
		else:
			self.cmdline += ' 2>&1 | tee "{0}"'.format(self.output_file)

	def replaceOUTPUTDIR(self):
		"""
		Replace [OUTPUTDIR] if present
		"""
		pattern = re.compile('\[OUTPUTDIR\]', re.IGNORECASE)
		self.cmdline = pattern.sub(self.output_dir, self.cmdline)

	def replaceTOOLBOXDIR(self):
		"""
		Replace [TOOLBOXDIR] (toolbox directory)
		"""
		pattern = re.compile('\[TOOLBOXDIR\]', re.IGNORECASE)
		self.cmdline = pattern.sub(self.toolbox_dir, self.cmdline)

	def replaceSpecificTags(self):
		"""
		Replace specific tags (depends on the selected service)
		eg. for http :
		[SSL option="value"]
		[CMS cms1="val" cms2="val" ... default="val"]
		"""
		if not self.specific_args:
			return

		for tag in SPECIFIC_TOOL_OPTIONS[self.service].keys():
			option_type = SpecificOptions.specificOptionType(self.service, tag)

			if option_type == 'boolean':
				try:
					pattern = re.compile(r'\[' + tag.upper() + '\s+option\s*=\s*[\'"](?P<option>.*?)[\'"]\s*\]', re.IGNORECASE)
					m = pattern.search(self.cmdline)
					# option is True
					if tag in self.specific_args.keys() and self.specific_args[tag]:
						self.cmdline = pattern.sub(m.group('option'), self.cmdline)
					# option is False
					else:
						self.cmdline = pattern.sub('', self.cmdline)
				except Exception as e:
					pass

			elif option_type == 'list_member':
				try:
					pattern = regex.compile(r'\[' + tag.upper() + '(?:\s+(?P<name>\w+)\s*=\s*[\'"](?P<value>\w*)[\'"])+\s*\]', regex.IGNORECASE)
					m = pattern.search(self.cmdline)
					capt = m.capturesdict()
					if tag in self.specific_args.keys() and self.specific_args[tag]:
						value = capt['value'][capt['name'].index(self.specific_args[tag])]
						self.cmdline = pattern.sub(value, self.cmdline)
					elif 'default' in [e.lower() for e in capt['name']]:
						value = capt['value'][capt['name'].index('default')]
						self.cmdline = pattern.sub(value, self.cmdline)
					else:
						self.cmdline = pattern.sub('', self.cmdline)
				except Exception as e:
					#print e
					pass


from math import*
def calcula_euler(x, n):
    if n == 1:
        resultado = 1
    elif n == 2:
        resultado = 1 + x
    else:
        somatoria = 0
        resultado = 1 + x
        for n in range(2, n+1):
            somatoria += (x**n-1)/(factorial(n-1))
            resultado += somatoria
    return resultado


import sys

with open(sys.argv[1], 'r') as f:
    rna_string = f.readline().strip()
f.close()

aa_dict = {}
with open(sys.argv[2], 'r') as g:
    for line in g:
        aa_dict[line.strip().split()[0]] = line.strip().split()[1]
g.close()

n_codons = int(len(rna_string)/3)
protein = ''
for i in range(n_codons):
    triplet = rna_string[i*3:(i+1)*3]
    aa = aa_dict[triplet]
    if aa != 'Stop':
        protein += aa

print(protein)


"""Data integration pipeline for project 'leonardo', standard version
"""

import datetime

from ozelot.etl import tasks
from ozelot import config

from leonardo.common.input import ArtistsInputData, PaintingsInputData
from . import models

class LoadEverything(tasks.ORMWrapperTask):
    """Top-level wrapper task"""

    def requires(self):
        yield LoadPaintings()
        yield LoadArtists()
        yield Tests()

class Tests(tasks.ORMWrapperTask):
    """Wrapper task for running all tests"""

    def requires(self):
        yield TestArtists()
        yield TestPaintings()

class LoadArtistsBase(tasks.ORMObjectCreatorMixin, tasks.ORMTask):
    """Load artists to DB, generate base objects only"""

    object_classes = [models.ArtistBase]

    def requires(self):
        yield ArtistsInputData()

    def run(self):
        df = ArtistsInputData().load()

        # the base model only contains the wiki ID
        df = df[['wiki_id']]

        # append an ID column
        df['id'] = range(len(df))

        # store everything, done
        df.to_sql(name=models.ArtistBase.__tablename__,
                  con=self.client.engine,
                  if_exists='append',
                  index=False)

        self.done()

class LoadArtists(tasks.ORMObjectCreatorMixin, tasks.ORMTask):
    """Load artist attributes to DB"""

    object_classes = [models.Artist]

    def requires(self):
        yield ArtistsInputData()
        yield LoadArtistsBase()

    def run(self):
        """Load all artists into the database
        """

        df = ArtistsInputData().load()

        # get base model instances, merge ID column via the unique wiki ID
        # (base and derived model instances must have the same ID values)
        base_data = self.client.df_query(self.session.query(models.ArtistBase))
        df = df.merge(base_data, on='wiki_id')

        # rename columns
        df.rename(columns={'artistLabel': 'name',
                           'genderLabel': 'gender'},
                  inplace=True)

        # columns that exist in the data model
        columns = ['name', 'id']

        # the extended model also stores the date of birth and gender
        if config.EXTENDED:
            columns += ['gender', 'year_of_birth']

        # keep only columns that exist in the data model
        df = df[columns]

        # store everything, done
        df.to_sql(name=models.Artist.__tablename__,
                  con=self.client.engine,
                  if_exists='append',
                  index=False)

        self.done()

class TestArtists(tasks.ORMTestTask):
    """Simple consistency checks for artist data"""

    def requires(self):
        yield LoadArtists()

    def run(self):
        df = self.client.df_query(self.session.query(models.Artist))

        assert len(df) == len(df.dropna(how='any')), "Found NaN values"
        assert df['wiki_id'].is_unique, "Wiki ID is not unique"

        if config.EXTENDED:
            assert df['year_of_birth'].min() > 0, "Found too small Date of Birth"
            assert df['year_of_birth'].max() < datetime.datetime.now().year, "Found too large Date of Birth"

        self.done()

class LoadPaintingsBase(tasks.ORMObjectCreatorMixin, tasks.ORMTask):
    """Load paintings to DB, create base objects only"""

    object_classes = [models.Painting]

    def requires(self):
        yield LoadArtistsBase()
        yield PaintingsInputData()

    def run(self):
        df = PaintingsInputData().load()

        # get artist IDs, join to table via artist wiki ID
        artist_ids = self.client.df_query(self.session.query(models.Artist.wiki_id,
                                                             models.Artist.id))
        df['artist_id'] = df['creator_wiki_id'].map(artist_ids.set_index('wiki_id')['id'])

        # limit to columns that exist in the data model
        df = df[['wiki_id', 'artist_id']]

        # append an ID column
        df['id'] = range(len(df))

        # store everything, done
        df.to_sql(name=models.PaintingBase.__tablename__,
                  con=self.client.engine,
                  if_exists='append',
                  index=False)

        self.done()

class LoadPaintings(tasks.ORMObjectCreatorMixin, tasks.ORMTask):
    """Load paintings to DB"""

    object_classes = [models.Painting]

    def requires(self):
        yield LoadPaintingsBase()
        yield PaintingsInputData()

    def run(self):
        df = PaintingsInputData().load()

        # rename columns
        df.rename(columns={'paintingLabel': 'name'}, inplace=True)

        # get base painting IDs, join them in via the wiki ID to get consistend ID values with the base objects
        base_data = self.client.df_query(self.session.query(models.PaintingBase))
        df = df.merge(base_data, on='wiki_id')

        # limit to columns that exist in the data model
        df = df[['name', 'area', 'decade', 'id']]

        # store everything, done
        df.to_sql(name=models.Painting.__tablename__,
                  con=self.client.engine,
                  if_exists='append',
                  index=False)

        self.done()

class TestPaintings(tasks.ORMTestTask):
    """Simple consistency checks for paintings"""

    def requires(self):
        yield LoadPaintings()

    def run(self):
        df = self.client.df_query(self.session.query(models.Painting))

        assert len(df['artist_id'].dropna()) > 0.8 * len(df), "Found too many missing artist IDs"
        assert len(df) == len(df.dropna(subset=[c for c in df.columns if not c == 'artist_id'],
                                        how='any')), "Found NaN values"
        assert df['wiki_id'].is_unique, "Wiki ID is not unique"
        assert df['area'].max() < 100., "Too large area values"
        assert df['area'].min() > 0.01 * 0.01, "Too small area values"

        self.done()


#!/bin/python
import json
import random
import promoterz

from copy import deepcopy

import coreFunctions

import promoterz.sequence.standard_loop

from deap import tools
from deap import algorithms
from deap import base

from Settings import getSettings

def gekko_generations(settings, GenerationMethod, NB_LOCALE=2):

    GenerationMethod = promoterz.selectRepresentationMethod(GenerationMethod)
    EvaluationMethod = promoterz.evaluation.gekko.Evaluate

    genconf=getSettings('generations')
    TargetParameters=getSettings()['strategies'][genconf.Strategy]
    GlobalTools = GenerationMethod.getToolbox(genconf, TargetParameters)

    GlobalTools.register('Evaluate', EvaluationMethod,
                         GlobalTools.constructPhenotype, genconf.candleSize)

    availableDataRange = promoterz.evaluation.gekko.getAvailableDataset(
            exchange_source=genconf.dataset_source)

    loops = [ promoterz.sequence.standard_loop.standard_loop ]
    World = promoterz.world.World(GlobalTools, loops,
                                  genconf, TargetParameters, NB_LOCALE,
                                  EnvironmentParameters=availableDataRange)

    while World.EPOCH < World.genconf.NBEPOCH:
        World.runEPOCH()
    # RUN ENDS. SELECT INDIVIDUE, LOG AND PRINT STUFF;
    #FinalBestScores.append(Stats['max'])
    print(World.EnvironmentParameters)
    ValidationDataset =\
        promoterz.evaluation.gekko.globalEvaluationDataset(World.EnvironmentParameters,
                                                           genconf.deltaDays, 12)

    for LOCALE in World.locales:
        BestIndividues = tools.selBest(LOCALE.population, genconf.finaltest['NBBESTINDS'])

        Z=genconf.finaltest['NBADDITIONALINDS']
        AdditionalIndividues = tools.selTournament(LOCALE.population, Z, Z*2)
        AdditionalIndividues = [ x for x in AdditionalIndividues if x not in BestIndividues ]
        FinalIndividues = BestIndividues + AdditionalIndividues

        for FinalIndividue in FinalIndividues:

            AssertFitness=coreFunctions.stratSettingsProofOfViability(World,
                                                                      FinalIndividue,
                                                                      ValidationDataset)
            print("Testing Strategy:\n")
            if AssertFitness[0] or AssertFitness[1] > 50:
                FinalIndividueSettings = GlobalTools.constructPhenotype(FinalIndividue)

                Show = json.dumps(FinalIndividueSettings, indent=2)
                coreFunctions.logInfo("~" * 18)

                print("Settings for Gekko config.js:")
                print(Show)
                print("Settings for Gekko --ui webpage")
                coreFunctions.logInfo(coreFunctions.pasteSettingsToUI(FinalIndividueSettings))

                print("\nRemember to check MAX and MIN values for each parameter.")
                print("\tresults may improve with extended ranges.")

            else:
                print("Strategy Fails.")

            print("")
    print("\t\t.RUN ENDS.")


# Copyright 2017-2020 Lawrence Livermore National Security, LLC and other
# CallFlow Project Developers. See the top-level LICENSE file for details.
#
# SPDX-License-Identifier: MIT

import pandas as pd
import networkx as nx
from ast import literal_eval as make_tuple

# CallFlow imports
try:
    import callflow

    LOGGER = callflow.get_logger(__name__)
except Exception:
    raise Exception("Module callflow not found not found.")

class FunctionList:
    """
    Callsite list (Remove)
    """

    def __init__(self, state, modFunc, nid):
        self.graph = state.new_gf.graph
        self.df = state.new_gf.df
        self.entire_df = state.new_entire_gf.df
        # Processing for the modFunc format to get the module name
        if "=" in modFunc:
            self.function = modFunc.split("=")[1]
            self.module = modFunc.split("=")[0]
        elif "/" in modFunc:
            self.function = modFunc.split("/")[1]
            self.module = modFunc.split("/")[0]
        self.module_df = self.df.loc[self.df["module"] == self.module]
        self.result = self.run()

    def add_paths(self, path_name):
        for idx, row in self.df.iterrows():
            path = row[path_name]
            if isinstance(path, str):
                path = make_tuple(path)
            corrected_path = path[0]
            if len(corrected_path) >= 2:
                source = corrected_path[-2]
                target = corrected_path[-1]
                if not self.entire_g.has_edge(source, target):
                    self.entire_g.add_edge(source, target)

    def run(self):
        callers = {}
        callees = {}
        entry_func = []
        ret = []
        # Create a networkX graph.
        self.entire_g = nx.DiGraph()
        self.add_paths("path")
        entry_func_df = self.module_df.loc[self.module_df["component_level"] == 2]
        entry_funcs = entry_func_df["name"].unique()
        other_func_df = self.module_df.loc[self.module_df["component_level"] > 2]
        other_funcs = other_func_df["name"].unique()
        for idx, entry_func in enumerate(entry_funcs):
            LOGGER.debug("Entry func: ", entry_func)
            LOGGER.debug("predecessors", self.entire_g.predecessors(entry_func))
            callers[entry_func] = list(self.entire_g.predecessors(entry_func))
            for idx, caller in enumerate(callers[entry_func]):
                callees[caller] = list(self.entire_g.predecessors(caller))
        ret.append(
            {
                "entry_functions": entry_funcs,
                "other_functions": other_funcs,
                "callers": callers,
                "callees": callees,
            }
        )
        ret_df = pd.DataFrame(ret)
        return ret_df.to_json(orient="columns")


import typing as t
from dataclasses import dataclass
from enum import Enum

class Domain(Enum):
    node = "node"
    edge = "edge"
    attr = "attr"

NODE, EDGE, ATTR = Domain.node, Domain.edge, Domain.attr

@dataclass
class Node:
    name: str
    attrs: str

    def __eq__(self, other: "Node") -> bool:  # type: ignore[override]
        is_equal = self.name == other.name and self.attrs == other.attrs
        return is_equal

@dataclass
class Edge:
    src: str
    dst: str
    attrs: str

    def __eq__(self, other: "Edge") -> bool:  # type: ignore[override]
        is_equal = (
            self.src == other.src
            and self.dst == other.dst
            and self.attrs == other.attrs
        )
        return is_equal

class Graph:
    def __init__(self, data: t.Optional[t.List[t.Any]] = None) -> None:
        data = data or []

        if not isinstance(data, list):
            raise TypeError("Data is not valid.")

        self.nodes: t.List[Node] = []
        self.edges: t.List[Edge] = []
        self.attrs: t.Dict[str, str] = {}

        for datum in data:
            if len(datum) < 2:
                raise TypeError("Data is not valid.")

            domain, *datum = datum

            if not isinstance(domain, Domain):
                raise ValueError(f"Domain value {domain} is not valid.")

            getattr(self, f"append_{domain.value}")(datum=datum)

    def append_node(self, datum: t.List[str]) -> None:
        d_name, d_attrs = datum
        self.nodes.append(Node(name=d_name, attrs=d_attrs))

    def append_edge(self, datum: t.List[str]) -> None:
        d_src, d_dst, d_attrs = datum
        self.edges.append(Edge(src=d_src, dst=d_dst, attrs=d_attrs))

    def append_attr(self, datum: t.List[str]) -> None:
        d_key, d_value = datum
        self.attrs.update({d_key: d_value})


from django.contrib.auth.decorators import login_required
from django.http import Http404
from django.shortcuts import render, redirect

from products.models import Product
from .forms import UserNewOrderFOrm

# Create your views here.
from .models import Order, OrderDetail

@login_required
def add_user_order(request):
    new_order_form = UserNewOrderFOrm(request.POST or None)
    if new_order_form.is_valid():
        order = Order.objects.filter(owner_id=request.user.id, is_paid=False).first()
        if order is None:
            order = Order.objects.create(owner_id=request.user.id, is_paid=False)

        product_id = new_order_form.cleaned_data.get('product_id')
        count = new_order_form.cleaned_data.get('count')
        try:
            int(count)
            if count < 1:
                count = 1
        except:
            count = 1
        product = Product.objects.filter(id=product_id).first()

        # check if has this item
        if order.orderdetail_set.filter(product_id=product_id):
            order.orderdetail_set.filter(product_id=product_id).update(count=count)
        else:
            order.orderdetail_set.create(product_id=product.id, price=product.price, count=count)
    return redirect('/products')

@login_required
def user_open_order(request, *args, **kwargs):
    context = {
        'order': None,
        'details': None,
        'total_price': 0,
        'total_count': 0
    }
    total_price = 0
    total_count = 0
    open_order: Order = Order.objects.filter(owner_id=request.user.id, is_paid=False).first()
    if open_order is not None:
        context['order'] = open_order
        context['details'] = open_order.orderdetail_set.all()
        context['total_price'] = open_order.get_total_price()
        context['total_count'] = open_order.get_total_count()
    return render(request, 'user_open_order.html', context)

@login_required
def remove_order_detail(request, *args, **kwargs):
    detail_id = kwargs.get('detail_id')
    if detail_id is not None:
        order_detail = OrderDetail.objects.get_queryset().get(id=detail_id, order__owner_id=request.user.id)
        if order_detail is not None:
            order_detail.delete()
            return redirect('/orders/سبد-خرید')
    raise Http404()


# Copyright 2017-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.

import sys
import random
import os
import bpy
import bpy_extras
import math
import numpy as np
import json

"""
Some utility functions for interacting with Blender
"""

def extract_args(input_argv=None):
    """
    Pull out command-line arguments after "--". Blender ignores command-line flags
    after --, so this lets us forward command line arguments from the blender
    invocation to our own script.
    """
    if input_argv is None:
        input_argv = sys.argv
    output_argv = []
    if '--' in input_argv:
        idx = input_argv.index('--')
        output_argv = input_argv[(idx + 1):]
    return output_argv

def parse_args(parser, argv=None):
    return parser.parse_args(extract_args(argv))

# I wonder if there's a better way to do this?
def delete_object(obj):
    """ Delete a specified blender object """
    for o in bpy.data.objects:
        o.select = False
    obj.select = True
    bpy.ops.object.delete()

def get_camera_coords(cam, pos):
    """
    For a specified point, get both the 3D coordinates and 2D pixel-space
    coordinates of the point from the perspective of the camera.

    Inputs:
    - cam: Camera object
    - pos: Vector giving 3D world-space position

    Returns a tuple of:
    - (px, py, pz): px and py give 2D image-space coordinates; pz gives depth
      in the range [-1, 1]
    """
    scene = bpy.context.scene
    x, y, z = bpy_extras.object_utils.world_to_camera_view(scene, cam, pos)
    scale = scene.render.resolution_percentage / 100.0
    w = int(scale * scene.render.resolution_x)
    h = int(scale * scene.render.resolution_y)
    px = int(round(x * w))
    py = int(round(h - y * h))
    return px, py, z

def set_layer(obj, layer_idx):
    """ Move an object to a particular layer """
    # Set the target layer to True first because an object must always be on
    # at least one layer.
    obj.layers[layer_idx] = True
    for i in range(len(obj.layers)):
        obj.layers[i] = (i == layer_idx)

def add_object(object_dir, name, scale, loc, theta=0):
    """
    Load an object from a file. We assume that in the directory object_dir, there
    is a file named "$name.blend" which contains a single object named "$name"
    that has unit size and is centered at the origin.

    - scale: scalar giving the size that the object should be in the scene
    - loc: tuple (x, y) giving the coordinates on the ground plane where the
      object should be placed.
    """
    # First figure out how many of this object are already in the scene so we can
    # give the new object a unique name
    count = 0
    for obj in bpy.data.objects:
        if obj.name.startswith(name):
            count += 1

    filename = os.path.join(object_dir, '%s.blend' % name, 'Object', name)
    bpy.ops.wm.append(filename=filename)

    # Give it a new name to avoid conflicts
    new_name = '%s_%d' % (name, count)
    bpy.data.objects[name].name = new_name

    # Set the new object as active, then rotate, scale, and translate it
    x, y = loc
    bpy.context.scene.objects.active = bpy.data.objects[new_name]
    bpy.context.object.rotation_euler[2] = theta
    bpy.ops.transform.resize(value=(scale, scale, scale))
    bpy.ops.transform.translate(value=(x, y, scale))

def load_materials(material_dir):
    """
    Load materials from a directory. We assume that the directory contains .blend
    files with one material each. The file X.blend has a single NodeTree item named
    X; this NodeTree item must have a "Color" input that accepts an RGBA value.
    """
    for fn in os.listdir(material_dir):
        if not fn.endswith('.blend'):
            continue
        name = os.path.splitext(fn)[0]
        filepath = os.path.join(material_dir, fn, 'NodeTree', name)
        bpy.ops.wm.append(filename=filepath)

def add_material(name, **properties):
    """
    Create a new material and assign it to the active object. "name" should be the
    name of a material that has been previously loaded using load_materials.
    """
    # Figure out how many materials are already in the scene
    mat_count = len(bpy.data.materials)

    # Create a new material; it is not attached to anything and
    # it will be called "Material"
    bpy.ops.material.new()

    # Get a reference to the material we just created and rename it;
    # then the next time we make a new material it will still be called
    # "Material" and we will still be able to look it up by name
    mat = bpy.data.materials['Material']
    mat.name = 'Material_%d' % mat_count

    # Attach the new material to the active object
    # Make sure it doesn't already have materials
    obj = bpy.context.active_object
    assert len(obj.data.materials) == 0
    obj.data.materials.append(mat)

    # Find the output node of the new material
    output_node = None
    for n in mat.node_tree.nodes:
        if n.name == 'Material Output':
            output_node = n
            break

    # Add a new GroupNode to the node tree of the active material,
    # and copy the node tree from the preloaded node group to the
    # new group node. This copying seems to happen by-value, so
    # we can create multiple materials of the same type without them
    # clobbering each other
    group_node = mat.node_tree.nodes.new('ShaderNodeGroup')
    group_node.node_tree = bpy.data.node_groups[name]

    # Find and set the "Color" input of the new group node
    for inp in group_node.inputs:
        if inp.name in properties:
            inp.default_value = properties[inp.name]

    # Wire the output of the new group node to the input of
    # the MaterialOutput node
    mat.node_tree.links.new(
        group_node.outputs['Shader'],
        output_node.inputs['Surface'],
    )

"""
Some functions for handling constraints to the clevr hans data set.
"""
class RetrySceneException(Exception):
    def __init__(self, message='Must retry scene form scratch'):
        super(RetrySceneException, self).__init__(message)

def convert_class_str_keys_to_int(dictionary):
    """
    Convert the highest level keys of a dictionary from strings to integers.
    :param dictionary:
    :return:
    """
    converted_dict = {}
    for key in dictionary.keys():
        assert isinstance(key, str)
        converted_dict[int(key)] = dictionary[key]
    return converted_dict

def repair_obj_dict(d):
    """
    If one of the attributes from (shape, size, material, color, general_position, relationships) is missing,
    add empty strings.
    :param d:
    :return:
    """
    relation_constraints = None
    key_list = list(d.keys())
    if "shape" not in key_list:
        d["shape"] = ""
    if "size" not in key_list:
        d["size"] = ""
    if "material" not in key_list:
        d["material"] = ""
    if "color" not in key_list:
        d["color"] = ""
    if "general_position" not in key_list:
        d["general_position"] = ""
    if "relationships" not in key_list:
        d["relationships"] = {"behind": "", "front": "", "right": "", "left": ""}
    if "relationships" in key_list:
        relationships_key_list = list(d["relationships"].keys())
        if "behind" not in relationships_key_list:
            d["relationships"]["behind"] = ""
        if "front" not in relationships_key_list:
            d["relationships"]["front"] = ""
        if "right" not in relationships_key_list:
            d["relationships"]["right"] = ""
        if "left" not in relationships_key_list:
            d["relationships"]["left"] = ""

def check_empty_dict(d):
    empty = True
    for key in list(d.keys()):
        if d[key]:
            empty = False
            break
    return empty

def unrole_variations_to_list(dictionary):
    """

    :param dictionary: e.g.
   {
   'b': {'0.6': [{'shape': 'sphere', 'general_position': 'left'},
   {'shape': 'sphere', 'general_position': 'left'},
   {'shape': 'sphere', 'general_position': 'left'},
   {'shape': 'cylinder', 'general_position': 'right', 'material': 'metal'},
   {'shape': 'cylinder', 'general_position': 'right', 'material': 'metal'},
   {'shape': 'cylinder', 'general_position': 'right', 'material': 'metal'}]},
   'a': {'0.4': [{'shape': 'sphere', 'general_position': 'left'},
   {'shape': 'sphere', 'general_position': 'left'},
   {'shape': 'sphere', 'general_position': 'left'}]}
   }
    :return:
    """
    return [list(list(dictionary.items())[i][1].items())[0][1] for i in range(len(dictionary.items()))]

def variations_subset_of_another(class_set):
    """
    If a class is defined by several variations, one of these variations must be a subset of all other. In other words
    it contains the minimal class rule which also occurs in the other variations.
    :param class_set:
    :return:
    """
    # get tha variations into one list
    variations = unrole_variations_to_list(class_set)
    smallest_subset_idx = np.argmin([len(variation) for variation in variations])
    # check that all variations contain the shortest variation
    correct_subset = 0
    for variation in variations:
        correct_subset += check_list_subset(variation, variations[smallest_subset_idx])
    return correct_subset == len(variations)

def get_relationship_constraints(obj_list, class_id):
    """
    Iterate over list of objects making class rules and extract if an object has any relationship constraints. Returns
    a list of dictionaries. Each dictionary represents an object with relevant attributes and the relationhsips to
    other objects, which are also represented as dictionaries of relevant attributes.
    E.g.: [{'color': 'cyan', 'relationships': {'behind': [{'color': 'red'}, {'color': 'red'}]}},
           {'color': 'red', 'relationships': {'front': [{'color': 'cyan'}]}},
           {'color': 'red', 'relationships': {'front': [{'color': 'cyan'}]}}]
    :param obj_list:
    :return:
    """
    relationship_constraints = []
    for obj_dict in obj_list:
        if not check_empty_dict(obj_dict["relationships"]):
            relationship_constraints.append(obj_dict.copy())
            relationship_constraints[-1]["class_id"] = int(class_id)
            relationship_constraints[-1]["relationships"] = {}
            for direction_key in list(obj_dict["relationships"].keys()):
                relationship_constraints[-1]["relationships"][direction_key] = []
                for related_obj_id in obj_dict["relationships"][direction_key]:
                    relationship_constraints[-1]["relationships"][direction_key].append(obj_list[related_obj_id].copy())
                    relationship_constraints[-1]["relationships"][direction_key][-1].pop("relationships", None)
    return relationship_constraints

def convert_json_dict(json_file_handle):
    """
    Given a json file handle go through all class rules. If the dictionary of the individual objects of a class rule
    does not contain the attributes color, shape, etc, add these as en empty string.
    :param json_file_handle:
    :return:
    """
    json_dict = json.load(json_file_handle)
    relationship_constraints = []
    for class_key in json_dict.keys():
        class_set = json_dict[class_key]
        # check that all attributes are added to all obj dicts, if only as an empty string value
        if isinstance(class_set, list):
            for d in class_set:
                repair_obj_dict(d)
            relationship_constraints += get_relationship_constraints(class_set, class_key)

        # this is the case if one class has variations with specific probabilities
        elif isinstance(class_set, dict):
            # check that shorter variation is contained in larger variation
            assert variations_subset_of_another(class_set)

            variation_key_list = list(class_set.keys())
            for variation_key in variation_key_list:
                prob_key_list = list(class_set[variation_key].keys())
                assert len(prob_key_list) == 1
                prob_key = prob_key_list[0]
                for d in class_set[variation_key][prob_key]:
                    repair_obj_dict(d)
                relationship_constraints += get_relationship_constraints(class_set[variation_key][prob_key], class_key)

    # finally convert string class ids to ints
    json_dict = convert_class_str_keys_to_int(json_dict)
    return json_dict, relationship_constraints

def check_list_subset(list_large, list_small):
    """
    Checks if one list of dictionaries is a subset of another.
    :param list_large:
    :param list_small:
    :return:
    """
    list_large_copy = list_large.copy()
    sim_count = 0
    for elem in list_small:
        for elem2 in list_large_copy:
            assert isinstance(elem, dict) and isinstance(elem2, dict)
            if elem == elem2:
                sim_count += 1
                list_large_copy.remove(elem2)
                break
    if sim_count == len(list_small):
        return True
    else:
        return False

def compare_objs(cur_obj, must_obj):
    """
    Compare the attributes between two objects, where must_obj is the more general object, i.e. if an attribute in
    must_obj is an empty string, the two objects are considered to have the same attribute here. Very IMPORTANTE!!!!!!
    :param obj:
    :param must_obj:
    :return:
    """
    # if a specific attribute is not an empty string of the must attributes, i.e. there is a specification
    # the comparison is automatically set to True
    same_shape = (cur_obj["shape"] == must_obj["shape"]) if must_obj["shape"] else True
    same_size = (cur_obj["size"] == must_obj["size"]) if must_obj["size"] else True
    same_material = (cur_obj["material"] == must_obj["material"]) if must_obj["material"] else True
    same_color = (cur_obj["color"] == must_obj["color"]) if must_obj["color"] else True
    same_general_pos = (must_obj["general_position"] in cur_obj["general_position"]) \
        if must_obj["general_position"] else True

    same_attrs = False
    if same_shape and same_size and same_color and same_material and same_general_pos:
        same_attrs = True
    return same_attrs

def check_conflicts_all_classes(all_class_attr_combos_dict, cur_objs_attr_dict, cur_class_id):
    """
    Iterate over all classes and check if there are too many conflicts between the current objects to be placed and
    those that must be placed within the other classes. Also make sure that the must be placed objects of own current
    class are not repeated.

    :param all_class_attr_combos_dict:
    :param cur_objs_attr_dict:
    :param cur_class_id:
    :return:
    """

    conflict = False
    for class_id in all_class_attr_combos_dict.keys():
        n_conflicts_per_class = 0
        must_objs_attr_list = all_class_attr_combos_dict[class_id].copy()

        # if it happens that a class rule list of one class id is contained within the list of another class id,
        # we don't check for conflicts
        if check_list_subset(all_class_attr_combos_dict[cur_class_id], all_class_attr_combos_dict[class_id])\
                and cur_class_id != class_id:
            continue

        for obj_id in cur_objs_attr_dict.keys():
            obj = cur_objs_attr_dict[obj_id]
            for must_obj in must_objs_attr_list:
                same_attrs = compare_objs(obj, must_obj)

                if same_attrs:
                    n_conflicts_per_class += 1
                    # remove the object that caused the conflicts, so that it is not counted twice, e.g. cylinder twice
                    # in must_obj_dict and 1 cylinder is in cur_objs_attr_dict
                    must_objs_attr_list.remove(must_obj)
                    break
            # if there are more conflcits then must be in the current class
            if (n_conflicts_per_class > len(all_class_attr_combos_dict[class_id])) and (class_id == cur_class_id):
                conflict = True
                break
            # if there are as many conflicts in another class as must be placed objects
            elif (n_conflicts_per_class == len(all_class_attr_combos_dict[class_id])) \
                    and (class_id != cur_class_id):
                conflict = True
                break
    return conflict

def compute_corrected_x_y(x, y, r, scene_struct):
    """
    Correct x, y position based on camera position.
    :param x:
    :param y:
    :param r:
    :param scene_struct:
    :return:
    """
    coords = [x, y, r]
    # correct for camera position to get true position
    x_corrected = np.dot(coords, scene_struct['directions']['right'])
    y_corrected = np.dot(coords, scene_struct['directions']['front'])
    return x_corrected, y_corrected

def sample_obj_place_with_general_constraint(constraint, r, scene_struct):
    """
    Get the object positions depending on whether there are general palcement constraints, e.g. object should be in
    right half of image. If no constraint, just sample randomly.
    :param constraint:
    :param r:
    :param scene_struct:
    :return:
    """

    if constraint:
        correct_placement = False
        while not correct_placement:
            x = random.uniform(-3, 3)
            y = random.uniform(-3, 3)

            x_corrected, y_corrected = compute_corrected_x_y(x, y, r, scene_struct)

            if 'right' in constraint and x_corrected > 0:
                correct_placement = True
            elif 'left' in constraint and x_corrected < 0:
                correct_placement = True
            elif 'top' in constraint and y_corrected < 0:
                correct_placement = True
            elif 'bottom' in constraint and y_corrected > 0:
                correct_placement = True
    else:
        x = random.uniform(-3, 3)
        y = random.uniform(-3, 3)
    return x, y

def get_general_obj_placement_name(x, y, r, scene_struct):
    """
    Given the x, y positions, correct based on camera position and get general placement in the scene in terms of
    top, bottom, right, left.
    :param x:
    :param y:
    :param r:
    :param scene_struct:
    :return:
    """
    x_corrected, y_corrected = compute_corrected_x_y(x, y, r, scene_struct)

    if x_corrected > 0:
        x_placement = 'right'
    elif x_corrected < 0:
        x_placement = 'left'
    if y_corrected < 0:
        y_placement = 'top'
    elif y_corrected > 0:
        y_placement = 'bottom'
    return y_placement + ' ' + x_placement

def check_relationship_constraints(x, y, r, scene_struct, cand_obj, cur_objs_attr_dict,
                                   relationship_constraints, cur_class_id):
    """
    This is a monster, beware the beast!!!!!!
    :param x:
    :param y:
    :param r:
    :param scene_struct:
    :param cand_obj:
    :param cur_objs_attr_dict:
    :param relationship_constraints:
    :param cur_class_id:
    :return:
    """
    x_corrected, y_corrected = compute_corrected_x_y(x, y, r, scene_struct)

    # set dummy value
    relationship_constraints_hold = True
    relationship_must_hold = True
    for idx, must_obj in enumerate(relationship_constraints):
        # if the current class id is the same as that of the relationship_constraint list
        # depending on relationship_must_hold we must evaluate differently when a relationship holds
        relationship_must_hold = True if must_obj["class_id"] == cur_class_id else False
        relationship_constraints_hold = relationship_must_hold # this ensures the first if cases to be passed

        # check if candidate obj attributes one with potential relationship constraints
        if compare_objs(cand_obj, must_obj):
            for relationship_key, relationship_list in list(must_obj["relationships"].items()):
                # find a relationship direction with constraints
                if relationship_list:
                    # for each object within this constraint list check if a corresponding object has already been
                    # placed in the scene
                    for constraint_obj in relationship_list:

                        # if a constraint with one object is already broken, but is supposed to hold
                        # or a constraint holds when it should not
                        if not(xnor(relationship_constraints_hold, relationship_must_hold)):
                            break
                        # otherwise check next constraint obj with all objects that have been placed in scene
                        for _, obj in cur_objs_attr_dict.items():
                            # if a constraint with one object is already broken, but is supposed to hold
                            # or a constraint holds when it should not
                            if not(xnor(relationship_constraints_hold, relationship_must_hold)):
                                break

                            # if the cand_obj has relationship constraints and another object in the scene stands in
                            # relationship with cand_obj, check if the relationship holds
                            if compare_objs(obj, constraint_obj):
                                relationship_constraints_hold = relate_objs([x_corrected, y_corrected],
                                                                            obj["corr_position"], relationship_key)

    # if all constraints hold and are supposed to or do not hold and are not supposed to, keep cand_obj x, y positions
    # otherwise resample until these conditions hold
    relationship_conflict = xnor(relationship_constraints_hold, relationship_must_hold)
    return relationship_conflict

# def place_obj(scene_struct, num_objects, args, camera,
#               cand_obj, cur_objs_attr_dict, blender_objects, positions,
#               relationship_constraints, general_position, r):
#     """
#     Place a candidate object, making sure it is far enough from the borders and other objects.
#     :param scene_struct:
#     :param blender_objects:
#     :param positions:
#     :param general_position:
#     :param r:
#     :param args:
#     :return:
#     """
#     # Try to place the object, ensuring that we don't intersect any existing
#     # objects and that we are more than the desired margin away from all existing
#     # objects along all cardinal directions.
#     num_tries = 0
#     while True:
#         # If we try and fail to place an object too many times, then delete all
#         # the objects in the scene and send message to wrapper.
#         num_tries += 1
#         if num_tries > args.max_retries:
#             for obj in blender_objects:
#                 delete_object(obj)
#             raise RetrySceneException()
#             # print("\nRetrying on new image!!\n")
#             # return add_random_objects(scene_struct, num_objects, args, camera)
#
#         # first make sure higher level constraints hold
#         relationship_constraint_hold = False
#         while not relationship_constraint_hold:
#             # first catch general placement constraints
#             if general_position:
#                 x, y = sample_obj_place_with_general_constraint(general_position, r, scene_struct)
#             else:
#                 x, y = sample_obj_place_with_general_constraint(None, r, scene_struct)
#             # next check if position holds for any given relationship constraints
#             relationship_constraint_hold = check_relationship_constraints(x, y, r, scene_struct, cand_obj,
#                                                                           cur_objs_attr_dict, relationship_constraints,
#                                                                           cur_class_id=args.img_class_id)
#
#         print("\nDirection constraints all hold!\n")
#         # Check to make sure the new object is further than min_dist from all
#         # other objects, and further than margin along the four cardinal directions
#         dists_good = True
#         margins_good = True
#         for (xx, yy, rr) in positions:
#             dx, dy = x - xx, y - yy
#             dist = math.sqrt(dx * dx + dy * dy)
#             if dist - r - rr < args.min_dist:
#                 dists_good = False
#                 break
#             for direction_name in ['left', 'right', 'front', 'behind']:
#                 direction_vec = scene_struct['directions'][direction_name]
#                 assert direction_vec[2] == 0
#                 margin = dx * direction_vec[0] + dy * direction_vec[1]
#                 if 0 < margin < args.margin:
#                     print(margin, args.margin, direction_name)
#                     print('BROKEN MARGIN!')
#                     margins_good = False
#                     break
#             if not margins_good:
#                 break
#
#         if dists_good and margins_good:
#             break
#
#     general_position_name = get_general_obj_placement_name(x, y, r, scene_struct)
#     x_corrected, y_corrected = compute_corrected_x_y(x, y, r, scene_struct)
#
#     return x, y, general_position_name, x_corrected, y_corrected

def check_for_classes_with_probabilities(conf_combos_all_classes, gt_combos_all_classes, img_class_id):
    """
    Given a class rule set with several variations with specific probabilities, choose one of these variations based on
    the specified probabilities and update the global rule lists to only contain that variation rule that was chosen.
    :param conf_combos_all_classes:
    :param gt_combos_all_classes:
    :param img_class_id:
    :return:
    """
    # if the class rule list which has variations does not correspond to img_class_id then make the smallest subset
    # variation the standard rule list, otherwise sample according to the probabilities
    if isinstance(conf_combos_all_classes[img_class_id], dict):
        must_attr_combos = conf_combos_all_classes[img_class_id]
        variation_keys = list(must_attr_combos.keys())

        # get the probabilities of every sub rule list
        probabilities = [float(prob_key) for key in must_attr_combos.keys()
                         for prob_key in must_attr_combos[key].keys()]
        assert np.sum(probabilities) == 1.

        # choose one of the rule lists based on the given probabilities
        idx = np.random.choice(np.arange(0, len(must_attr_combos)), p=probabilities)
        chosen_variation_key = variation_keys[idx]

        # get the prob key
        conf_chosen_prob_key = list(conf_combos_all_classes[img_class_id][chosen_variation_key].keys())[0]
        gt_chosen_prob_key = list(gt_combos_all_classes[img_class_id][chosen_variation_key].keys())[0]

        # remove those options that were not chosen
        conf_combos_all_classes[img_class_id] = conf_combos_all_classes[img_class_id][chosen_variation_key][conf_chosen_prob_key]
        gt_combos_all_classes[img_class_id] = gt_combos_all_classes[img_class_id][chosen_variation_key][gt_chosen_prob_key]

    else:
        for class_id, class_set in conf_combos_all_classes.items():
            if isinstance(class_set, dict):
                variations = unrole_variations_to_list(class_set)
                smallest_subset_idx = np.argmin([len(variation) for variation in variations])

                variation_key_shortest_subset = list(class_set.keys())[smallest_subset_idx]

                conf_smallest_subset_prob_key = list(conf_combos_all_classes[class_id][variation_key_shortest_subset].keys())[0]
                gt_smallest_subset_prob_key = list(gt_combos_all_classes[class_id][variation_key_shortest_subset].keys())[0]

                # keep the smallest subset variation and remove the rest
                conf_combos_all_classes[class_id] = conf_combos_all_classes[class_id][variation_key_shortest_subset][
                    conf_smallest_subset_prob_key]
                gt_combos_all_classes[class_id] = gt_combos_all_classes[class_id][variation_key_shortest_subset][
                    gt_smallest_subset_prob_key]

    return conf_combos_all_classes, gt_combos_all_classes

def relate_objs(obj1_coords, obj2_coords, relation):
    """
    Relates obj2 in relation to obj1, e.g. whether obj2 is behind obj1 or whether obj2 is right of obj1.
    :param obj1_coords:
    :param obj2_coords:
    :param relation:
    :return:
    """
    relation_holds = False
    if relation == "behind" and obj1_coords[1] > obj2_coords[1]:
        relation_holds = True
    elif relation == "front" and obj1_coords[1] < obj2_coords[1]:
        relation_holds = True
    elif relation == "right" and obj1_coords[0] < obj2_coords[0]:
        relation_holds = True
    elif relation == "left" and obj1_coords[0] > obj2_coords[0]:
        relation_holds = True
    return relation_holds

def xnor(x, y):
    return not (x or y) or (x and y)